11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/kernel/scsi_debug.c 31da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 41da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 51da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 61da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 71da177e4SLinus Torvalds * anything out of the ordinary is seen. 81da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This version is more generic, simulating a variable number of disk 111da177e4SLinus Torvalds * (or disk like devices) sharing a common amount of RAM 121da177e4SLinus Torvalds * 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * For documentation see http://www.torque.net/sg/sdebug26.html 151da177e4SLinus Torvalds * 161da177e4SLinus Torvalds * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] 171da177e4SLinus Torvalds * dpg: work for devfs large number of disks [20010809] 181da177e4SLinus Torvalds * forked for lk 2.5 series [20011216, 20020101] 191da177e4SLinus Torvalds * use vmalloc() more inquiry+mode_sense [20020302] 201da177e4SLinus Torvalds * add timers for delayed responses [20020721] 211da177e4SLinus Torvalds * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] 221da177e4SLinus Torvalds * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] 231da177e4SLinus Torvalds * dpg: change style of boot options to "scsi_debug.num_tgts=2" and 241da177e4SLinus Torvalds * module options to "modprobe scsi_debug num_tgts=2" [20021221] 251da177e4SLinus Torvalds */ 261da177e4SLinus Torvalds 271da177e4SLinus Torvalds #include <linux/config.h> 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 #ifndef LINUX_VERSION_CODE 521da177e4SLinus Torvalds #include <linux/version.h> 531da177e4SLinus Torvalds #endif 541da177e4SLinus Torvalds 551da177e4SLinus Torvalds #include "scsi_logging.h" 561da177e4SLinus Torvalds #include "scsi_debug.h" 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds #define SCSI_DEBUG_VERSION "1.75" 591da177e4SLinus Torvalds static const char * scsi_debug_version_date = "20050113"; 601da177e4SLinus Torvalds 611da177e4SLinus Torvalds /* Additional Sense Code (ASC) used */ 621da177e4SLinus Torvalds #define NO_ADDED_SENSE 0x0 631da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 641da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 651da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 661da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 671da177e4SLinus Torvalds #define POWERON_RESET 0x29 681da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 691da177e4SLinus Torvalds #define THRESHHOLD_EXCEEDED 0x5d 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 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 901da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 911da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 921da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 931da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 941da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 951da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 961da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 971da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 981da177e4SLinus Torvalds * 991da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1001da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1011da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1021da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1031da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1041da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1051da177e4SLinus Torvalds */ 1061da177e4SLinus Torvalds 1071da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1081da177e4SLinus Torvalds * sector on read commands: */ 1091da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1101da177e4SLinus Torvalds 1111da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1121da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1131da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 1141da177e4SLinus Torvalds 1151da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1161da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1171da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1181da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1191da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 1201da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 1211da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1221da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1231da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1241da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1251da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1281da177e4SLinus Torvalds 1291da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1301da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds static unsigned long sdebug_store_size; /* in bytes */ 1331da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1361da177e4SLinus Torvalds may still need them */ 1371da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 1381da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 1391da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */ 1421da177e4SLinus Torvalds #define POW2_SECT_SIZE 9 1431da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE) 1441da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds struct sdebug_dev_info { 1511da177e4SLinus Torvalds struct list_head dev_list; 1521da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 1531da177e4SLinus Torvalds unsigned int channel; 1541da177e4SLinus Torvalds unsigned int target; 1551da177e4SLinus Torvalds unsigned int lun; 1561da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 1571da177e4SLinus Torvalds char reset; 1581da177e4SLinus Torvalds char used; 1591da177e4SLinus Torvalds }; 1601da177e4SLinus Torvalds 1611da177e4SLinus Torvalds struct sdebug_host_info { 1621da177e4SLinus Torvalds struct list_head host_list; 1631da177e4SLinus Torvalds struct Scsi_Host *shost; 1641da177e4SLinus Torvalds struct device dev; 1651da177e4SLinus Torvalds struct list_head dev_info_list; 1661da177e4SLinus Torvalds }; 1671da177e4SLinus Torvalds 1681da177e4SLinus Torvalds #define to_sdebug_host(d) \ 1691da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 1721da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 1751da177e4SLinus Torvalds 1761da177e4SLinus Torvalds struct sdebug_queued_cmd { 1771da177e4SLinus Torvalds int in_use; 1781da177e4SLinus Torvalds struct timer_list cmnd_timer; 1791da177e4SLinus Torvalds done_funct_t done_funct; 1801da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 1811da177e4SLinus Torvalds int scsi_result; 1821da177e4SLinus Torvalds }; 1831da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds static Scsi_Host_Template sdebug_driver_template = { 1861da177e4SLinus Torvalds .proc_info = scsi_debug_proc_info, 1871da177e4SLinus Torvalds .name = "SCSI DEBUG", 1881da177e4SLinus Torvalds .info = scsi_debug_info, 1891da177e4SLinus Torvalds .slave_alloc = scsi_debug_slave_alloc, 1901da177e4SLinus Torvalds .slave_configure = scsi_debug_slave_configure, 1911da177e4SLinus Torvalds .slave_destroy = scsi_debug_slave_destroy, 1921da177e4SLinus Torvalds .ioctl = scsi_debug_ioctl, 1931da177e4SLinus Torvalds .queuecommand = scsi_debug_queuecommand, 1941da177e4SLinus Torvalds .eh_abort_handler = scsi_debug_abort, 1951da177e4SLinus Torvalds .eh_bus_reset_handler = scsi_debug_bus_reset, 1961da177e4SLinus Torvalds .eh_device_reset_handler = scsi_debug_device_reset, 1971da177e4SLinus Torvalds .eh_host_reset_handler = scsi_debug_host_reset, 1981da177e4SLinus Torvalds .bios_param = scsi_debug_biosparam, 1991da177e4SLinus Torvalds .can_queue = SCSI_DEBUG_CANQUEUE, 2001da177e4SLinus Torvalds .this_id = 7, 2011da177e4SLinus Torvalds .sg_tablesize = 64, 2021da177e4SLinus Torvalds .cmd_per_lun = 3, 2031da177e4SLinus Torvalds .max_sectors = 4096, 2041da177e4SLinus Torvalds .unchecked_isa_dma = 0, 2051da177e4SLinus Torvalds .use_clustering = DISABLE_CLUSTERING, 2061da177e4SLinus Torvalds .module = THIS_MODULE, 2071da177e4SLinus Torvalds }; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds static int num_aborts = 0; 2121da177e4SLinus Torvalds static int num_dev_resets = 0; 2131da177e4SLinus Torvalds static int num_bus_resets = 0; 2141da177e4SLinus Torvalds static int num_host_resets = 0; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2171da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *); 2221da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *); 2231da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2261da177e4SLinus Torvalds .name = sdebug_proc_name, 2271da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2281da177e4SLinus Torvalds .probe = sdebug_driver_probe, 2291da177e4SLinus Torvalds .remove = sdebug_driver_remove, 2301da177e4SLinus Torvalds }; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static const int check_condition_result = 2331da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds /* function declarations */ 2361da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, 2371da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2381da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * SCpnt, 2391da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2401da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * SCpnt, 2411da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2421da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target, 2431da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2441da177e4SLinus Torvalds static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, 2451da177e4SLinus Torvalds int num, struct sdebug_dev_info * devip); 2461da177e4SLinus Torvalds static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, 2471da177e4SLinus Torvalds int num, struct sdebug_dev_info * devip); 2481da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * SCpnt, 2491da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2501da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2511da177e4SLinus Torvalds int arr_len); 2521da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2531da177e4SLinus Torvalds int max_arr_len); 2541da177e4SLinus Torvalds static void timer_intr_handler(unsigned long); 2551da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); 2561da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 2571da177e4SLinus Torvalds int asc, int asq); 2581da177e4SLinus Torvalds static int check_reset(struct scsi_cmnd * SCpnt, 2591da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2601da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 2611da177e4SLinus Torvalds struct sdebug_dev_info * devip, 2621da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff); 2631da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp); 2641da177e4SLinus Torvalds static void __init init_all_queued(void); 2651da177e4SLinus Torvalds static void stop_all_queued(void); 2661da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd); 2671da177e4SLinus Torvalds static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, 2681da177e4SLinus Torvalds const char * dev_id_str, int dev_id_str_len); 2691da177e4SLinus Torvalds static void do_create_driverfs_files(void); 2701da177e4SLinus Torvalds static void do_remove_driverfs_files(void); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds static int sdebug_add_adapter(void); 2731da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 2741da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static struct device pseudo_primary; 2771da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds 2801da177e4SLinus Torvalds static 2811da177e4SLinus Torvalds int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) 2821da177e4SLinus Torvalds { 2831da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 2841da177e4SLinus Torvalds int block, upper_blk, num, k; 2851da177e4SLinus Torvalds int errsts = 0; 2861da177e4SLinus Torvalds int target = SCpnt->device->id; 2871da177e4SLinus Torvalds struct sdebug_dev_info * devip = NULL; 2881da177e4SLinus Torvalds int inj_recovered = 0; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds if (done == NULL) 2911da177e4SLinus Torvalds return 0; /* assume mid level reprocessing command */ 2921da177e4SLinus Torvalds 2931da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 2941da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: cmd "); 2951da177e4SLinus Torvalds for (k = 0, num = SCpnt->cmd_len; k < num; ++k) 2961da177e4SLinus Torvalds printk("%02x ", (int)cmd[k]); 2971da177e4SLinus Torvalds printk("\n"); 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds if(target == sdebug_driver_template.this_id) { 3001da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: initiator's id used as " 3011da177e4SLinus Torvalds "target!\n"); 3021da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3031da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3041da177e4SLinus Torvalds } 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds if (SCpnt->device->lun >= scsi_debug_max_luns) 3071da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3081da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3091da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 3101da177e4SLinus Torvalds if (NULL == devip) 3111da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3121da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds if ((scsi_debug_every_nth != 0) && 3151da177e4SLinus Torvalds (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3161da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 3171da177e4SLinus Torvalds if (scsi_debug_every_nth < -1) 3181da177e4SLinus Torvalds scsi_debug_every_nth = -1; 3191da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3201da177e4SLinus Torvalds return 0; /* ignore command causing timeout */ 3211da177e4SLinus Torvalds else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3221da177e4SLinus Torvalds inj_recovered = 1; /* to reads and writes below */ 3231da177e4SLinus Torvalds } 3241da177e4SLinus Torvalds 3251da177e4SLinus Torvalds switch (*cmd) { 3261da177e4SLinus Torvalds case INQUIRY: /* mandatory, ignore unit attention */ 3271da177e4SLinus Torvalds errsts = resp_inquiry(SCpnt, target, devip); 3281da177e4SLinus Torvalds break; 3291da177e4SLinus Torvalds case REQUEST_SENSE: /* mandatory, ignore unit attention */ 3301da177e4SLinus Torvalds errsts = resp_requests(SCpnt, devip); 3311da177e4SLinus Torvalds break; 3321da177e4SLinus Torvalds case REZERO_UNIT: /* actually this is REWIND for SSC */ 3331da177e4SLinus Torvalds case START_STOP: 3341da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3351da177e4SLinus Torvalds break; 3361da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 3371da177e4SLinus Torvalds if ((errsts = check_reset(SCpnt, devip))) 3381da177e4SLinus Torvalds break; 3391da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3401da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Medium removal %s\n", 3411da177e4SLinus Torvalds cmd[4] ? "inhibited" : "enabled"); 3421da177e4SLinus Torvalds break; 3431da177e4SLinus Torvalds case SEND_DIAGNOSTIC: /* mandatory */ 3441da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3451da177e4SLinus Torvalds break; 3461da177e4SLinus Torvalds case TEST_UNIT_READY: /* mandatory */ 3471da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3481da177e4SLinus Torvalds break; 3491da177e4SLinus Torvalds case RESERVE: 3501da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3511da177e4SLinus Torvalds break; 3521da177e4SLinus Torvalds case RESERVE_10: 3531da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3541da177e4SLinus Torvalds break; 3551da177e4SLinus Torvalds case RELEASE: 3561da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3571da177e4SLinus Torvalds break; 3581da177e4SLinus Torvalds case RELEASE_10: 3591da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 3601da177e4SLinus Torvalds break; 3611da177e4SLinus Torvalds case READ_CAPACITY: 3621da177e4SLinus Torvalds errsts = resp_readcap(SCpnt, devip); 3631da177e4SLinus Torvalds break; 3641da177e4SLinus Torvalds case READ_16: 3651da177e4SLinus Torvalds case READ_12: 3661da177e4SLinus Torvalds case READ_10: 3671da177e4SLinus Torvalds case READ_6: 3681da177e4SLinus Torvalds if ((errsts = check_reset(SCpnt, devip))) 3691da177e4SLinus Torvalds break; 3701da177e4SLinus Torvalds upper_blk = 0; 3711da177e4SLinus Torvalds if ((*cmd) == READ_16) { 3721da177e4SLinus Torvalds upper_blk = cmd[5] + (cmd[4] << 8) + 3731da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 3741da177e4SLinus Torvalds block = cmd[9] + (cmd[8] << 8) + 3751da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 3761da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 3771da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 3781da177e4SLinus Torvalds } else if ((*cmd) == READ_12) { 3791da177e4SLinus Torvalds block = cmd[5] + (cmd[4] << 8) + 3801da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 3811da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 3821da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 3831da177e4SLinus Torvalds } else if ((*cmd) == READ_10) { 3841da177e4SLinus Torvalds block = cmd[5] + (cmd[4] << 8) + 3851da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 3861da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 3871da177e4SLinus Torvalds } else { 3881da177e4SLinus Torvalds block = cmd[3] + (cmd[2] << 8) + 3891da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 3901da177e4SLinus Torvalds num = cmd[4]; 3911da177e4SLinus Torvalds } 3921da177e4SLinus Torvalds errsts = resp_read(SCpnt, upper_blk, block, num, devip); 3931da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 3941da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 3951da177e4SLinus Torvalds THRESHHOLD_EXCEEDED, 0); 3961da177e4SLinus Torvalds errsts = check_condition_result; 3971da177e4SLinus Torvalds } 3981da177e4SLinus Torvalds break; 3991da177e4SLinus Torvalds case REPORT_LUNS: /* mandatory, ignore unit attention */ 4001da177e4SLinus Torvalds errsts = resp_report_luns(SCpnt, devip); 4011da177e4SLinus Torvalds break; 4021da177e4SLinus Torvalds case VERIFY: /* 10 byte SBC-2 command */ 4031da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 4041da177e4SLinus Torvalds break; 4051da177e4SLinus Torvalds case WRITE_16: 4061da177e4SLinus Torvalds case WRITE_12: 4071da177e4SLinus Torvalds case WRITE_10: 4081da177e4SLinus Torvalds case WRITE_6: 4091da177e4SLinus Torvalds if ((errsts = check_reset(SCpnt, devip))) 4101da177e4SLinus Torvalds break; 4111da177e4SLinus Torvalds upper_blk = 0; 4121da177e4SLinus Torvalds if ((*cmd) == WRITE_16) { 4131da177e4SLinus Torvalds upper_blk = cmd[5] + (cmd[4] << 8) + 4141da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4151da177e4SLinus Torvalds block = cmd[9] + (cmd[8] << 8) + 4161da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 4171da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 4181da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 4191da177e4SLinus Torvalds } else if ((*cmd) == WRITE_12) { 4201da177e4SLinus Torvalds block = cmd[5] + (cmd[4] << 8) + 4211da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4221da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 4231da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 4241da177e4SLinus Torvalds } else if ((*cmd) == WRITE_10) { 4251da177e4SLinus Torvalds block = cmd[5] + (cmd[4] << 8) + 4261da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4271da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 4281da177e4SLinus Torvalds } else { 4291da177e4SLinus Torvalds block = cmd[3] + (cmd[2] << 8) + 4301da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 4311da177e4SLinus Torvalds num = cmd[4]; 4321da177e4SLinus Torvalds } 4331da177e4SLinus Torvalds errsts = resp_write(SCpnt, upper_blk, block, num, devip); 4341da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 4351da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 4361da177e4SLinus Torvalds THRESHHOLD_EXCEEDED, 0); 4371da177e4SLinus Torvalds errsts = check_condition_result; 4381da177e4SLinus Torvalds } 4391da177e4SLinus Torvalds break; 4401da177e4SLinus Torvalds case MODE_SENSE: 4411da177e4SLinus Torvalds case MODE_SENSE_10: 4421da177e4SLinus Torvalds errsts = resp_mode_sense(SCpnt, target, devip); 4431da177e4SLinus Torvalds break; 4441da177e4SLinus Torvalds case SYNCHRONIZE_CACHE: 4451da177e4SLinus Torvalds errsts = check_reset(SCpnt, devip); 4461da177e4SLinus Torvalds break; 4471da177e4SLinus Torvalds default: 4481da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4491da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 4501da177e4SLinus Torvalds "supported\n", *cmd); 4511da177e4SLinus Torvalds if ((errsts = check_reset(SCpnt, devip))) 4521da177e4SLinus Torvalds break; /* Unit attention takes precedence */ 4531da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 4541da177e4SLinus Torvalds errsts = check_condition_result; 4551da177e4SLinus Torvalds break; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay); 4581da177e4SLinus Torvalds } 4591da177e4SLinus Torvalds 4601da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 4611da177e4SLinus Torvalds { 4621da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 4631da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 4641da177e4SLinus Torvalds } 4651da177e4SLinus Torvalds return -EINVAL; 4661da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip) 4701da177e4SLinus Torvalds { 4711da177e4SLinus Torvalds if (devip->reset) { 4721da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4731da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 4741da177e4SLinus Torvalds "attention: power on reset\n"); 4751da177e4SLinus Torvalds devip->reset = 0; 4761da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 4771da177e4SLinus Torvalds return check_condition_result; 4781da177e4SLinus Torvalds } 4791da177e4SLinus Torvalds return 0; 4801da177e4SLinus Torvalds } 4811da177e4SLinus Torvalds 4821da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 4831da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 4841da177e4SLinus Torvalds int arr_len) 4851da177e4SLinus Torvalds { 4861da177e4SLinus Torvalds int k, req_len, act_len, len, active; 4871da177e4SLinus Torvalds void * kaddr; 4881da177e4SLinus Torvalds void * kaddr_off; 4891da177e4SLinus Torvalds struct scatterlist * sgpnt; 4901da177e4SLinus Torvalds 4911da177e4SLinus Torvalds if (0 == scp->request_bufflen) 4921da177e4SLinus Torvalds return 0; 4931da177e4SLinus Torvalds if (NULL == scp->request_buffer) 4941da177e4SLinus Torvalds return (DID_ERROR << 16); 4951da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 4961da177e4SLinus Torvalds (scp->sc_data_direction == DMA_FROM_DEVICE))) 4971da177e4SLinus Torvalds return (DID_ERROR << 16); 4981da177e4SLinus Torvalds if (0 == scp->use_sg) { 4991da177e4SLinus Torvalds req_len = scp->request_bufflen; 5001da177e4SLinus Torvalds act_len = (req_len < arr_len) ? req_len : arr_len; 5011da177e4SLinus Torvalds memcpy(scp->request_buffer, arr, act_len); 5021da177e4SLinus Torvalds scp->resid = req_len - act_len; 5031da177e4SLinus Torvalds return 0; 5041da177e4SLinus Torvalds } 5051da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 5061da177e4SLinus Torvalds active = 1; 5071da177e4SLinus Torvalds for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { 5081da177e4SLinus Torvalds if (active) { 5091da177e4SLinus Torvalds kaddr = (unsigned char *) 5101da177e4SLinus Torvalds kmap_atomic(sgpnt->page, KM_USER0); 5111da177e4SLinus Torvalds if (NULL == kaddr) 5121da177e4SLinus Torvalds return (DID_ERROR << 16); 5131da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 5141da177e4SLinus Torvalds len = sgpnt->length; 5151da177e4SLinus Torvalds if ((req_len + len) > arr_len) { 5161da177e4SLinus Torvalds active = 0; 5171da177e4SLinus Torvalds len = arr_len - req_len; 5181da177e4SLinus Torvalds } 5191da177e4SLinus Torvalds memcpy(kaddr_off, arr + req_len, len); 5201da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 5211da177e4SLinus Torvalds act_len += len; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds req_len += sgpnt->length; 5241da177e4SLinus Torvalds } 5251da177e4SLinus Torvalds scp->resid = req_len - act_len; 5261da177e4SLinus Torvalds return 0; 5271da177e4SLinus Torvalds } 5281da177e4SLinus Torvalds 5291da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 5301da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 5311da177e4SLinus Torvalds int max_arr_len) 5321da177e4SLinus Torvalds { 5331da177e4SLinus Torvalds int k, req_len, len, fin; 5341da177e4SLinus Torvalds void * kaddr; 5351da177e4SLinus Torvalds void * kaddr_off; 5361da177e4SLinus Torvalds struct scatterlist * sgpnt; 5371da177e4SLinus Torvalds 5381da177e4SLinus Torvalds if (0 == scp->request_bufflen) 5391da177e4SLinus Torvalds return 0; 5401da177e4SLinus Torvalds if (NULL == scp->request_buffer) 5411da177e4SLinus Torvalds return -1; 5421da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 5431da177e4SLinus Torvalds (scp->sc_data_direction == DMA_TO_DEVICE))) 5441da177e4SLinus Torvalds return -1; 5451da177e4SLinus Torvalds if (0 == scp->use_sg) { 5461da177e4SLinus Torvalds req_len = scp->request_bufflen; 5471da177e4SLinus Torvalds len = (req_len < max_arr_len) ? req_len : max_arr_len; 5481da177e4SLinus Torvalds memcpy(arr, scp->request_buffer, len); 5491da177e4SLinus Torvalds return len; 5501da177e4SLinus Torvalds } 5511da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 5521da177e4SLinus Torvalds for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { 5531da177e4SLinus Torvalds kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); 5541da177e4SLinus Torvalds if (NULL == kaddr) 5551da177e4SLinus Torvalds return -1; 5561da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 5571da177e4SLinus Torvalds len = sgpnt->length; 5581da177e4SLinus Torvalds if ((req_len + len) > max_arr_len) { 5591da177e4SLinus Torvalds len = max_arr_len - req_len; 5601da177e4SLinus Torvalds fin = 1; 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds memcpy(arr + req_len, kaddr_off, len); 5631da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 5641da177e4SLinus Torvalds if (fin) 5651da177e4SLinus Torvalds return req_len + len; 5661da177e4SLinus Torvalds req_len += sgpnt->length; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds return req_len; 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 5731da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 5741da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds static int inquiry_evpd_83(unsigned char * arr, int dev_id_num, 5771da177e4SLinus Torvalds const char * dev_id_str, int dev_id_str_len) 5781da177e4SLinus Torvalds { 5791da177e4SLinus Torvalds int num; 5801da177e4SLinus Torvalds 5811da177e4SLinus Torvalds /* Two identification descriptors: */ 5821da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 5831da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 5841da177e4SLinus Torvalds arr[1] = 0x1; 5851da177e4SLinus Torvalds arr[2] = 0x0; 5861da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 5871da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 5881da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 5891da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 5901da177e4SLinus Torvalds arr[3] = num; 5911da177e4SLinus Torvalds num += 4; 5921da177e4SLinus Torvalds /* NAA IEEE registered identifier (faked) */ 5931da177e4SLinus Torvalds arr[num] = 0x1; /* binary */ 5941da177e4SLinus Torvalds arr[num + 1] = 0x3; 5951da177e4SLinus Torvalds arr[num + 2] = 0x0; 5961da177e4SLinus Torvalds arr[num + 3] = 0x8; 5971da177e4SLinus Torvalds arr[num + 4] = 0x51; /* ieee company id=0x123456 (faked) */ 5981da177e4SLinus Torvalds arr[num + 5] = 0x23; 5991da177e4SLinus Torvalds arr[num + 6] = 0x45; 6001da177e4SLinus Torvalds arr[num + 7] = 0x60; 6011da177e4SLinus Torvalds arr[num + 8] = (dev_id_num >> 24); 6021da177e4SLinus Torvalds arr[num + 9] = (dev_id_num >> 16) & 0xff; 6031da177e4SLinus Torvalds arr[num + 10] = (dev_id_num >> 8) & 0xff; 6041da177e4SLinus Torvalds arr[num + 11] = dev_id_num & 0xff; 6051da177e4SLinus Torvalds return num + 12; 6061da177e4SLinus Torvalds } 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 6101da177e4SLinus Torvalds #define SDEBUG_MAX_INQ_ARR_SZ 128 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 6131da177e4SLinus Torvalds struct sdebug_dev_info * devip) 6141da177e4SLinus Torvalds { 6151da177e4SLinus Torvalds unsigned char pq_pdt; 6161da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ]; 6171da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 6181da177e4SLinus Torvalds int alloc_len; 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 6211da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ); 6221da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 6231da177e4SLinus Torvalds arr[0] = pq_pdt; 6241da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 6251da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 6261da177e4SLinus Torvalds 0); 6271da177e4SLinus Torvalds return check_condition_result; 6281da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 6291da177e4SLinus Torvalds int dev_id_num, len; 6301da177e4SLinus Torvalds char dev_id_str[6]; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 6331da177e4SLinus Torvalds (devip->target * 1000) + devip->lun; 6341da177e4SLinus Torvalds len = scnprintf(dev_id_str, 6, "%d", dev_id_num); 6351da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 6361da177e4SLinus Torvalds arr[3] = 3; 6371da177e4SLinus Torvalds arr[4] = 0x0; /* this page */ 6381da177e4SLinus Torvalds arr[5] = 0x80; /* unit serial number */ 6391da177e4SLinus Torvalds arr[6] = 0x83; /* device identification */ 6401da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 6411da177e4SLinus Torvalds arr[1] = 0x80; 6421da177e4SLinus Torvalds arr[3] = len; 6431da177e4SLinus Torvalds memcpy(&arr[4], dev_id_str, len); 6441da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 6451da177e4SLinus Torvalds arr[1] = 0x83; 6461da177e4SLinus Torvalds arr[3] = inquiry_evpd_83(&arr[4], dev_id_num, 6471da177e4SLinus Torvalds dev_id_str, len); 6481da177e4SLinus Torvalds } else { 6491da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 6501da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 6511da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 6521da177e4SLinus Torvalds return check_condition_result; 6531da177e4SLinus Torvalds } 6541da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 6551da177e4SLinus Torvalds min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ)); 6561da177e4SLinus Torvalds } 6571da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 6581da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 6591da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 6601da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 6611da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 6621da177e4SLinus Torvalds arr[6] = 0x1; /* claim: ADDR16 */ 6631da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 6641da177e4SLinus Torvalds arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */ 6651da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 6661da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 6671da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 6681da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 6691da177e4SLinus Torvalds arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */ 6701da177e4SLinus Torvalds arr[60] = 0x3; arr[61] = 0x0; /* SPC-3 */ 6711da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 6721da177e4SLinus Torvalds arr[62] = 0x1; arr[63] = 0x80; /* SBC */ 6731da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 6741da177e4SLinus Torvalds arr[62] = 0x2; arr[63] = 0x00; /* SSC */ 6751da177e4SLinus Torvalds } 6761da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 6771da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 6781da177e4SLinus Torvalds } 6791da177e4SLinus Torvalds 6801da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 6811da177e4SLinus Torvalds struct sdebug_dev_info * devip) 6821da177e4SLinus Torvalds { 6831da177e4SLinus Torvalds unsigned char * sbuff; 6841da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 6851da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 6861da177e4SLinus Torvalds int len = 18; 6871da177e4SLinus Torvalds 6881da177e4SLinus Torvalds memset(arr, 0, SDEBUG_SENSE_LEN); 6891da177e4SLinus Torvalds if (devip->reset == 1) 6901da177e4SLinus Torvalds mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); 6911da177e4SLinus Torvalds sbuff = devip->sense_buff; 6921da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 6931da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 6941da177e4SLinus Torvalds arr[0] = 0x72; 6951da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 6961da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 6971da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 6981da177e4SLinus Torvalds len = 8; 6991da177e4SLinus Torvalds } else 7001da177e4SLinus Torvalds memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 7011da177e4SLinus Torvalds mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0); 7021da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 7031da177e4SLinus Torvalds } 7041da177e4SLinus Torvalds 7051da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 7061da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 7071da177e4SLinus Torvalds struct sdebug_dev_info * devip) 7081da177e4SLinus Torvalds { 7091da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 7101da177e4SLinus Torvalds unsigned long capac; 7111da177e4SLinus Torvalds int errsts; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds if ((errsts = check_reset(scp, devip))) 7141da177e4SLinus Torvalds return errsts; 7151da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 7161da177e4SLinus Torvalds capac = (unsigned long)sdebug_capacity - 1; 7171da177e4SLinus Torvalds arr[0] = (capac >> 24); 7181da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 7191da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 7201da177e4SLinus Torvalds arr[3] = capac & 0xff; 7211da177e4SLinus Torvalds arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 7221da177e4SLinus Torvalds arr[7] = SECT_SIZE_PER(target) & 0xff; 7231da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 7291da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 7301da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 7311da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 7321da177e4SLinus Torvalds 7331da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 7341da177e4SLinus Torvalds if (1 == pcontrol) 7351da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 7361da177e4SLinus Torvalds return sizeof(err_recov_pg); 7371da177e4SLinus Torvalds } 7381da177e4SLinus Torvalds 7391da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 7401da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 7411da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 7421da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 7451da177e4SLinus Torvalds if (1 == pcontrol) 7461da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 7471da177e4SLinus Torvalds return sizeof(disconnect_pg); 7481da177e4SLinus Torvalds } 7491da177e4SLinus Torvalds 7501da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 7511da177e4SLinus Torvalds { /* Format device page for mode_sense */ 7521da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 7531da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 7541da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 7571da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 7581da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 7591da177e4SLinus Torvalds p[12] = (SECT_SIZE >> 8) & 0xff; 7601da177e4SLinus Torvalds p[13] = SECT_SIZE & 0xff; 7611da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 7621da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 7631da177e4SLinus Torvalds if (1 == pcontrol) 7641da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 7651da177e4SLinus Torvalds return sizeof(format_pg); 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 7691da177e4SLinus Torvalds { /* Caching page for mode_sense */ 7701da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 7711da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 7721da177e4SLinus Torvalds 7731da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 7741da177e4SLinus Torvalds if (1 == pcontrol) 7751da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 7761da177e4SLinus Torvalds return sizeof(caching_pg); 7771da177e4SLinus Torvalds } 7781da177e4SLinus Torvalds 7791da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 7801da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 7811da177e4SLinus Torvalds unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 7821da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 7831da177e4SLinus Torvalds 7841da177e4SLinus Torvalds if (scsi_debug_dsense) 7851da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 7861da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 7871da177e4SLinus Torvalds if (1 == pcontrol) 7881da177e4SLinus Torvalds memset(p + 2, 0, sizeof(ctrl_m_pg) - 2); 7891da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 7901da177e4SLinus Torvalds } 7911da177e4SLinus Torvalds 7921da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 7931da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 7941da177e4SLinus Torvalds unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 7951da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 7961da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 7971da177e4SLinus Torvalds if (1 == pcontrol) 7981da177e4SLinus Torvalds memset(p + 2, 0, sizeof(iec_m_pg) - 2); 7991da177e4SLinus Torvalds return sizeof(iec_m_pg); 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds 8021da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 8031da177e4SLinus Torvalds 8041da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 8051da177e4SLinus Torvalds struct sdebug_dev_info * devip) 8061da177e4SLinus Torvalds { 8071da177e4SLinus Torvalds unsigned char dbd; 8081da177e4SLinus Torvalds int pcontrol, pcode, subpcode; 8091da177e4SLinus Torvalds unsigned char dev_spec; 8101da177e4SLinus Torvalds int alloc_len, msense_6, offset, len, errsts; 8111da177e4SLinus Torvalds unsigned char * ap; 8121da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 8131da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds if ((errsts = check_reset(scp, devip))) 8161da177e4SLinus Torvalds return errsts; 8171da177e4SLinus Torvalds dbd = cmd[1] & 0x8; 8181da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 8191da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 8201da177e4SLinus Torvalds subpcode = cmd[3]; 8211da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 8221da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 8231da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 8241da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 8251da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 8261da177e4SLinus Torvalds 0); 8271da177e4SLinus Torvalds return check_condition_result; 8281da177e4SLinus Torvalds } 8291da177e4SLinus Torvalds dev_spec = DEV_READONLY(target) ? 0x80 : 0x0; 8301da177e4SLinus Torvalds if (msense_6) { 8311da177e4SLinus Torvalds arr[2] = dev_spec; 8321da177e4SLinus Torvalds offset = 4; 8331da177e4SLinus Torvalds } else { 8341da177e4SLinus Torvalds arr[3] = dev_spec; 8351da177e4SLinus Torvalds offset = 8; 8361da177e4SLinus Torvalds } 8371da177e4SLinus Torvalds ap = arr + offset; 8381da177e4SLinus Torvalds 8391da177e4SLinus Torvalds if (0 != subpcode) { /* TODO: Control Extension page */ 8401da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 8411da177e4SLinus Torvalds 0); 8421da177e4SLinus Torvalds return check_condition_result; 8431da177e4SLinus Torvalds } 8441da177e4SLinus Torvalds switch (pcode) { 8451da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 8461da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 8471da177e4SLinus Torvalds offset += len; 8481da177e4SLinus Torvalds break; 8491da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 8501da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 8511da177e4SLinus Torvalds offset += len; 8521da177e4SLinus Torvalds break; 8531da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 8541da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 8551da177e4SLinus Torvalds offset += len; 8561da177e4SLinus Torvalds break; 8571da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 8581da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 8591da177e4SLinus Torvalds offset += len; 8601da177e4SLinus Torvalds break; 8611da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 8621da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 8631da177e4SLinus Torvalds offset += len; 8641da177e4SLinus Torvalds break; 8651da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 8661da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 8671da177e4SLinus Torvalds offset += len; 8681da177e4SLinus Torvalds break; 8691da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 8701da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 8711da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 8721da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 8731da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 8741da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 8751da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 8761da177e4SLinus Torvalds offset += len; 8771da177e4SLinus Torvalds break; 8781da177e4SLinus Torvalds default: 8791da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 8801da177e4SLinus Torvalds 0); 8811da177e4SLinus Torvalds return check_condition_result; 8821da177e4SLinus Torvalds } 8831da177e4SLinus Torvalds if (msense_6) 8841da177e4SLinus Torvalds arr[0] = offset - 1; 8851da177e4SLinus Torvalds else { 8861da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 8871da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 8881da177e4SLinus Torvalds } 8891da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 8901da177e4SLinus Torvalds } 8911da177e4SLinus Torvalds 8921da177e4SLinus Torvalds static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block, 8931da177e4SLinus Torvalds int num, struct sdebug_dev_info * devip) 8941da177e4SLinus Torvalds { 8951da177e4SLinus Torvalds unsigned long iflags; 8961da177e4SLinus Torvalds int ret; 8971da177e4SLinus Torvalds 8981da177e4SLinus Torvalds if (upper_blk || (block + num > sdebug_capacity)) { 8991da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 9001da177e4SLinus Torvalds 0); 9011da177e4SLinus Torvalds return check_condition_result; 9021da177e4SLinus Torvalds } 9031da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 9041da177e4SLinus Torvalds (block <= OPT_MEDIUM_ERR_ADDR) && 9051da177e4SLinus Torvalds ((block + num) > OPT_MEDIUM_ERR_ADDR)) { 9061da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 9071da177e4SLinus Torvalds 0); 9081da177e4SLinus Torvalds /* claim unrecoverable read error */ 9091da177e4SLinus Torvalds return check_condition_result; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 9121da177e4SLinus Torvalds ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), 9131da177e4SLinus Torvalds num * SECT_SIZE); 9141da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 9151da177e4SLinus Torvalds return ret; 9161da177e4SLinus Torvalds } 9171da177e4SLinus Torvalds 9181da177e4SLinus Torvalds static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block, 9191da177e4SLinus Torvalds int num, struct sdebug_dev_info * devip) 9201da177e4SLinus Torvalds { 9211da177e4SLinus Torvalds unsigned long iflags; 9221da177e4SLinus Torvalds int res; 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds if (upper_blk || (block + num > sdebug_capacity)) { 9251da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 9261da177e4SLinus Torvalds 0); 9271da177e4SLinus Torvalds return check_condition_result; 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds 9301da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 9311da177e4SLinus Torvalds res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE), 9321da177e4SLinus Torvalds num * SECT_SIZE); 9331da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 9341da177e4SLinus Torvalds if (-1 == res) 9351da177e4SLinus Torvalds return (DID_ERROR << 16); 9361da177e4SLinus Torvalds else if ((res < (num * SECT_SIZE)) && 9371da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 9381da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, " 9391da177e4SLinus Torvalds " IO sent=%d bytes\n", num * SECT_SIZE, res); 9401da177e4SLinus Torvalds return 0; 9411da177e4SLinus Torvalds } 9421da177e4SLinus Torvalds 9431da177e4SLinus Torvalds #define SDEBUG_RLUN_ARR_SZ 128 9441da177e4SLinus Torvalds 9451da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 9461da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9471da177e4SLinus Torvalds { 9481da177e4SLinus Torvalds unsigned int alloc_len; 9491da177e4SLinus Torvalds int lun_cnt, i, upper; 9501da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 9511da177e4SLinus Torvalds int select_report = (int)cmd[2]; 9521da177e4SLinus Torvalds struct scsi_lun *one_lun; 9531da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 9561da177e4SLinus Torvalds if ((alloc_len < 16) || (select_report > 2)) { 9571da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 9581da177e4SLinus Torvalds 0); 9591da177e4SLinus Torvalds return check_condition_result; 9601da177e4SLinus Torvalds } 9611da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 9621da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 9631da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 9641da177e4SLinus Torvalds arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff; 9651da177e4SLinus Torvalds arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff; 9661da177e4SLinus Torvalds lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 9671da177e4SLinus Torvalds sizeof(struct scsi_lun)), lun_cnt); 9681da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 9691da177e4SLinus Torvalds for (i = 0; i < lun_cnt; i++) { 9701da177e4SLinus Torvalds upper = (i >> 8) & 0x3f; 9711da177e4SLinus Torvalds if (upper) 9721da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 9731da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 9741da177e4SLinus Torvalds one_lun[i].scsi_lun[1] = i & 0xff; 9751da177e4SLinus Torvalds } 9761da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 9771da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds /* When timer goes off this function is called. */ 9811da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 9821da177e4SLinus Torvalds { 9831da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 9841da177e4SLinus Torvalds unsigned long iflags; 9851da177e4SLinus Torvalds 9861da177e4SLinus Torvalds if (indx >= SCSI_DEBUG_CANQUEUE) { 9871da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 9881da177e4SLinus Torvalds "large\n"); 9891da177e4SLinus Torvalds return; 9901da177e4SLinus Torvalds } 9911da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 9921da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 9931da177e4SLinus Torvalds if (! sqcp->in_use) { 9941da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 9951da177e4SLinus Torvalds "interrupt\n"); 9961da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 9971da177e4SLinus Torvalds return; 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds sqcp->in_use = 0; 10001da177e4SLinus Torvalds if (sqcp->done_funct) { 10011da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 10021da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds sqcp->done_funct = NULL; 10051da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 10061da177e4SLinus Torvalds } 10071da177e4SLinus Torvalds 10081da177e4SLinus Torvalds static int scsi_debug_slave_alloc(struct scsi_device * sdp) 10091da177e4SLinus Torvalds { 10101da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 10111da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 10121da177e4SLinus Torvalds sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 10131da177e4SLinus Torvalds return 0; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds static int scsi_debug_slave_configure(struct scsi_device * sdp) 10171da177e4SLinus Torvalds { 10181da177e4SLinus Torvalds struct sdebug_dev_info * devip; 10191da177e4SLinus Torvalds 10201da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 10211da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 10221da177e4SLinus Torvalds sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 10231da177e4SLinus Torvalds if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 10241da177e4SLinus Torvalds sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 10251da177e4SLinus Torvalds devip = devInfoReg(sdp); 10261da177e4SLinus Torvalds sdp->hostdata = devip; 10271da177e4SLinus Torvalds if (sdp->host->cmd_per_lun) 10281da177e4SLinus Torvalds scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 10291da177e4SLinus Torvalds sdp->host->cmd_per_lun); 10301da177e4SLinus Torvalds return 0; 10311da177e4SLinus Torvalds } 10321da177e4SLinus Torvalds 10331da177e4SLinus Torvalds static void scsi_debug_slave_destroy(struct scsi_device * sdp) 10341da177e4SLinus Torvalds { 10351da177e4SLinus Torvalds struct sdebug_dev_info * devip = 10361da177e4SLinus Torvalds (struct sdebug_dev_info *)sdp->hostdata; 10371da177e4SLinus Torvalds 10381da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 10391da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 10401da177e4SLinus Torvalds sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 10411da177e4SLinus Torvalds if (devip) { 10421da177e4SLinus Torvalds /* make this slot avaliable for re-use */ 10431da177e4SLinus Torvalds devip->used = 0; 10441da177e4SLinus Torvalds sdp->hostdata = NULL; 10451da177e4SLinus Torvalds } 10461da177e4SLinus Torvalds } 10471da177e4SLinus Torvalds 10481da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 10491da177e4SLinus Torvalds { 10501da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 10511da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 10521da177e4SLinus Torvalds struct sdebug_dev_info * devip = 10531da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 10541da177e4SLinus Torvalds 10551da177e4SLinus Torvalds if (devip) 10561da177e4SLinus Torvalds return devip; 10571da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; 10581da177e4SLinus Torvalds if(! sdbg_host) { 10591da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 10601da177e4SLinus Torvalds return NULL; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 10631da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 10641da177e4SLinus Torvalds (devip->target == sdev->id) && 10651da177e4SLinus Torvalds (devip->lun == sdev->lun)) 10661da177e4SLinus Torvalds return devip; 10671da177e4SLinus Torvalds else { 10681da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 10691da177e4SLinus Torvalds open_devip = devip; 10701da177e4SLinus Torvalds } 10711da177e4SLinus Torvalds } 10721da177e4SLinus Torvalds if (NULL == open_devip) { /* try and make a new one */ 10731da177e4SLinus Torvalds open_devip = kmalloc(sizeof(*open_devip),GFP_KERNEL); 10741da177e4SLinus Torvalds if (NULL == open_devip) { 10751da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 10761da177e4SLinus Torvalds __FUNCTION__, __LINE__); 10771da177e4SLinus Torvalds return NULL; 10781da177e4SLinus Torvalds } 10791da177e4SLinus Torvalds memset(open_devip, 0, sizeof(*open_devip)); 10801da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 10811da177e4SLinus Torvalds list_add_tail(&open_devip->dev_list, 10821da177e4SLinus Torvalds &sdbg_host->dev_info_list); 10831da177e4SLinus Torvalds } 10841da177e4SLinus Torvalds if (open_devip) { 10851da177e4SLinus Torvalds open_devip->channel = sdev->channel; 10861da177e4SLinus Torvalds open_devip->target = sdev->id; 10871da177e4SLinus Torvalds open_devip->lun = sdev->lun; 10881da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 10891da177e4SLinus Torvalds open_devip->reset = 1; 10901da177e4SLinus Torvalds open_devip->used = 1; 10911da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 10921da177e4SLinus Torvalds if (scsi_debug_dsense) 10931da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 10941da177e4SLinus Torvalds else { 10951da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 10961da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 10971da177e4SLinus Torvalds } 10981da177e4SLinus Torvalds return open_devip; 10991da177e4SLinus Torvalds } 11001da177e4SLinus Torvalds return NULL; 11011da177e4SLinus Torvalds } 11021da177e4SLinus Torvalds 11031da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 11041da177e4SLinus Torvalds int asc, int asq) 11051da177e4SLinus Torvalds { 11061da177e4SLinus Torvalds unsigned char * sbuff; 11071da177e4SLinus Torvalds 11081da177e4SLinus Torvalds sbuff = devip->sense_buff; 11091da177e4SLinus Torvalds memset(sbuff, 0, SDEBUG_SENSE_LEN); 11101da177e4SLinus Torvalds if (scsi_debug_dsense) { 11111da177e4SLinus Torvalds sbuff[0] = 0x72; /* descriptor, current */ 11121da177e4SLinus Torvalds sbuff[1] = key; 11131da177e4SLinus Torvalds sbuff[2] = asc; 11141da177e4SLinus Torvalds sbuff[3] = asq; 11151da177e4SLinus Torvalds } else { 11161da177e4SLinus Torvalds sbuff[0] = 0x70; /* fixed, current */ 11171da177e4SLinus Torvalds sbuff[2] = key; 11181da177e4SLinus Torvalds sbuff[7] = 0xa; /* implies 18 byte sense buffer */ 11191da177e4SLinus Torvalds sbuff[12] = asc; 11201da177e4SLinus Torvalds sbuff[13] = asq; 11211da177e4SLinus Torvalds } 11221da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 11231da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 11241da177e4SLinus Torvalds "[0x%x,0x%x,0x%x]\n", key, asc, asq); 11251da177e4SLinus Torvalds } 11261da177e4SLinus Torvalds 11271da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 11281da177e4SLinus Torvalds { 11291da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 11301da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 11311da177e4SLinus Torvalds ++num_aborts; 11321da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 11331da177e4SLinus Torvalds return SUCCESS; 11341da177e4SLinus Torvalds } 11351da177e4SLinus Torvalds 11361da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 11371da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 11381da177e4SLinus Torvalds { 11391da177e4SLinus Torvalds int res; 11401da177e4SLinus Torvalds unsigned char *buf; 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 11431da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 11441da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 11451da177e4SLinus Torvalds if (buf) { 11461da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 11471da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 11481da177e4SLinus Torvalds kfree(buf); 11491da177e4SLinus Torvalds if (! res) 11501da177e4SLinus Torvalds return res; 11511da177e4SLinus Torvalds } 11521da177e4SLinus Torvalds info[0] = sdebug_heads; 11531da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 11541da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 11551da177e4SLinus Torvalds return 0; 11561da177e4SLinus Torvalds } 11571da177e4SLinus Torvalds 11581da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 11591da177e4SLinus Torvalds { 11601da177e4SLinus Torvalds struct sdebug_dev_info * devip; 11611da177e4SLinus Torvalds 11621da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 11631da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 11641da177e4SLinus Torvalds ++num_dev_resets; 11651da177e4SLinus Torvalds if (SCpnt) { 11661da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 11671da177e4SLinus Torvalds if (devip) 11681da177e4SLinus Torvalds devip->reset = 1; 11691da177e4SLinus Torvalds } 11701da177e4SLinus Torvalds return SUCCESS; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 11731da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 11741da177e4SLinus Torvalds { 11751da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 11761da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 11771da177e4SLinus Torvalds struct scsi_device * sdp; 11781da177e4SLinus Torvalds struct Scsi_Host * hp; 11791da177e4SLinus Torvalds 11801da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 11811da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 11821da177e4SLinus Torvalds ++num_bus_resets; 11831da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 11841da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) hp->hostdata; 11851da177e4SLinus Torvalds if (sdbg_host) { 11861da177e4SLinus Torvalds list_for_each_entry(dev_info, 11871da177e4SLinus Torvalds &sdbg_host->dev_info_list, 11881da177e4SLinus Torvalds dev_list) 11891da177e4SLinus Torvalds dev_info->reset = 1; 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds return SUCCESS; 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 11961da177e4SLinus Torvalds { 11971da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 11981da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 12011da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 12021da177e4SLinus Torvalds ++num_host_resets; 12031da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 12041da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 12051da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 12061da177e4SLinus Torvalds dev_list) 12071da177e4SLinus Torvalds dev_info->reset = 1; 12081da177e4SLinus Torvalds } 12091da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 12101da177e4SLinus Torvalds stop_all_queued(); 12111da177e4SLinus Torvalds return SUCCESS; 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 12151da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd) 12161da177e4SLinus Torvalds { 12171da177e4SLinus Torvalds unsigned long iflags; 12181da177e4SLinus Torvalds int k; 12191da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 12221da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 12231da177e4SLinus Torvalds sqcp = &queued_arr[k]; 12241da177e4SLinus Torvalds if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 12251da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 12261da177e4SLinus Torvalds sqcp->in_use = 0; 12271da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 12281da177e4SLinus Torvalds break; 12291da177e4SLinus Torvalds } 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 12321da177e4SLinus Torvalds return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; 12331da177e4SLinus Torvalds } 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds /* Deletes (stops) timers of all queued commands */ 12361da177e4SLinus Torvalds static void stop_all_queued(void) 12371da177e4SLinus Torvalds { 12381da177e4SLinus Torvalds unsigned long iflags; 12391da177e4SLinus Torvalds int k; 12401da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 12411da177e4SLinus Torvalds 12421da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 12431da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 12441da177e4SLinus Torvalds sqcp = &queued_arr[k]; 12451da177e4SLinus Torvalds if (sqcp->in_use && sqcp->a_cmnd) { 12461da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 12471da177e4SLinus Torvalds sqcp->in_use = 0; 12481da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 12491da177e4SLinus Torvalds } 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 12521da177e4SLinus Torvalds } 12531da177e4SLinus Torvalds 12541da177e4SLinus Torvalds /* Initializes timers in queued array */ 12551da177e4SLinus Torvalds static void __init init_all_queued(void) 12561da177e4SLinus Torvalds { 12571da177e4SLinus Torvalds unsigned long iflags; 12581da177e4SLinus Torvalds int k; 12591da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 12601da177e4SLinus Torvalds 12611da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 12621da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 12631da177e4SLinus Torvalds sqcp = &queued_arr[k]; 12641da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 12651da177e4SLinus Torvalds sqcp->in_use = 0; 12661da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 12671da177e4SLinus Torvalds } 12681da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 12691da177e4SLinus Torvalds } 12701da177e4SLinus Torvalds 12711da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp) 12721da177e4SLinus Torvalds { 12731da177e4SLinus Torvalds struct partition * pp; 12741da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 12751da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 12761da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 12771da177e4SLinus Torvalds 12781da177e4SLinus Torvalds /* assume partition table already zeroed */ 12791da177e4SLinus Torvalds if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) 12801da177e4SLinus Torvalds return; 12811da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 12821da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 12831da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 12841da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 12851da177e4SLinus Torvalds } 12861da177e4SLinus Torvalds num_sectors = (int)(sdebug_store_size / SECT_SIZE); 12871da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 12881da177e4SLinus Torvalds / scsi_debug_num_parts; 12891da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 12901da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 12911da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 12921da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 12931da177e4SLinus Torvalds * heads_by_sects; 12941da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 12951da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 12961da177e4SLinus Torvalds 12971da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 12981da177e4SLinus Torvalds ramp[511] = 0xAA; 12991da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 13001da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 13011da177e4SLinus Torvalds start_sec = starts[k]; 13021da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 13031da177e4SLinus Torvalds pp->boot_ind = 0; 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 13061da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 13071da177e4SLinus Torvalds / sdebug_sectors_per; 13081da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 13111da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 13121da177e4SLinus Torvalds / sdebug_sectors_per; 13131da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds pp->start_sect = start_sec; 13161da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 13171da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 13181da177e4SLinus Torvalds } 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 13221da177e4SLinus Torvalds struct sdebug_dev_info * devip, 13231da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 13241da177e4SLinus Torvalds { 13251da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 13261da177e4SLinus Torvalds if (scsi_result) { 13271da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 13301da177e4SLinus Torvalds "non-zero result=0x%x\n", sdp->host->host_no, 13311da177e4SLinus Torvalds sdp->channel, sdp->id, sdp->lun, scsi_result); 13321da177e4SLinus Torvalds } 13331da177e4SLinus Torvalds } 13341da177e4SLinus Torvalds if (cmnd && devip) { 13351da177e4SLinus Torvalds /* simulate autosense by this driver */ 13361da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 13371da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 13381da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 13391da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 13401da177e4SLinus Torvalds } 13411da177e4SLinus Torvalds if (delta_jiff <= 0) { 13421da177e4SLinus Torvalds if (cmnd) 13431da177e4SLinus Torvalds cmnd->result = scsi_result; 13441da177e4SLinus Torvalds if (done) 13451da177e4SLinus Torvalds done(cmnd); 13461da177e4SLinus Torvalds return 0; 13471da177e4SLinus Torvalds } else { 13481da177e4SLinus Torvalds unsigned long iflags; 13491da177e4SLinus Torvalds int k; 13501da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 13511da177e4SLinus Torvalds 13521da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 13531da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 13541da177e4SLinus Torvalds sqcp = &queued_arr[k]; 13551da177e4SLinus Torvalds if (! sqcp->in_use) 13561da177e4SLinus Torvalds break; 13571da177e4SLinus Torvalds } 13581da177e4SLinus Torvalds if (k >= SCSI_DEBUG_CANQUEUE) { 13591da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 13601da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 13611da177e4SLinus Torvalds return 1; /* report busy to mid level */ 13621da177e4SLinus Torvalds } 13631da177e4SLinus Torvalds sqcp->in_use = 1; 13641da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 13651da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 13661da177e4SLinus Torvalds sqcp->done_funct = done; 13671da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 13681da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 13691da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 13701da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 13711da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 13721da177e4SLinus Torvalds if (cmnd) 13731da177e4SLinus Torvalds cmnd->result = 0; 13741da177e4SLinus Torvalds return 0; 13751da177e4SLinus Torvalds } 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds 13781da177e4SLinus Torvalds /* Set 'perm' (4th argument) to 0 to disable module_param's definition 13791da177e4SLinus Torvalds * of sysfs parameters (which module_param doesn't yet support). 13801da177e4SLinus Torvalds * Sysfs parameters defined explicitly below. 13811da177e4SLinus Torvalds */ 13821da177e4SLinus Torvalds module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */ 13831da177e4SLinus Torvalds module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */ 13841da177e4SLinus Torvalds module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0); 13851da177e4SLinus Torvalds module_param_named(dsense, scsi_debug_dsense, int, 0); 13861da177e4SLinus Torvalds module_param_named(every_nth, scsi_debug_every_nth, int, 0); 13871da177e4SLinus Torvalds module_param_named(max_luns, scsi_debug_max_luns, int, 0); 13881da177e4SLinus Torvalds module_param_named(num_parts, scsi_debug_num_parts, int, 0); 13891da177e4SLinus Torvalds module_param_named(num_tgts, scsi_debug_num_tgts, int, 0); 13901da177e4SLinus Torvalds module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */ 13911da177e4SLinus Torvalds module_param_named(ptype, scsi_debug_ptype, int, 0); 13921da177e4SLinus Torvalds module_param_named(scsi_level, scsi_debug_scsi_level, int, 0); 13931da177e4SLinus Torvalds 13941da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 13951da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 13961da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 13971da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 13981da177e4SLinus Torvalds 13991da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 14001da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 14011da177e4SLinus Torvalds MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs"); 14021da177e4SLinus Torvalds MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)"); 14031da177e4SLinus Torvalds MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)"); 14041da177e4SLinus Torvalds MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate"); 14051da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 14061da177e4SLinus Torvalds MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate"); 14071da177e4SLinus Torvalds MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->..."); 14081da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 14091da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 14101da177e4SLinus Torvalds 14111da177e4SLinus Torvalds 14121da177e4SLinus Torvalds static char sdebug_info[256]; 14131da177e4SLinus Torvalds 14141da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 14151da177e4SLinus Torvalds { 14161da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 14171da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 14181da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 14191da177e4SLinus Torvalds scsi_debug_opts); 14201da177e4SLinus Torvalds return sdebug_info; 14211da177e4SLinus Torvalds } 14221da177e4SLinus Torvalds 14231da177e4SLinus Torvalds /* scsi_debug_proc_info 14241da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 14251da177e4SLinus Torvalds */ 14261da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 14271da177e4SLinus Torvalds int length, int inout) 14281da177e4SLinus Torvalds { 14291da177e4SLinus Torvalds int len, pos, begin; 14301da177e4SLinus Torvalds int orig_length; 14311da177e4SLinus Torvalds 14321da177e4SLinus Torvalds orig_length = length; 14331da177e4SLinus Torvalds 14341da177e4SLinus Torvalds if (inout == 1) { 14351da177e4SLinus Torvalds char arr[16]; 14361da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 14371da177e4SLinus Torvalds 14381da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 14391da177e4SLinus Torvalds return -EACCES; 14401da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 14411da177e4SLinus Torvalds arr[minLen] = '\0'; 14421da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 14431da177e4SLinus Torvalds return -EINVAL; 14441da177e4SLinus Torvalds scsi_debug_opts = pos; 14451da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 14461da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 14471da177e4SLinus Torvalds return length; 14481da177e4SLinus Torvalds } 14491da177e4SLinus Torvalds begin = 0; 14501da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 14511da177e4SLinus Torvalds "%s [%s]\n" 14521da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 14531da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 14541da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 14551da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 14561da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 14571da177e4SLinus Torvalds "host_resets=%d\n", 14581da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 14591da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 14601da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 14611da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 14621da177e4SLinus Torvalds SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 14631da177e4SLinus Torvalds num_aborts, num_dev_resets, num_bus_resets, num_host_resets); 14641da177e4SLinus Torvalds if (pos < offset) { 14651da177e4SLinus Torvalds len = 0; 14661da177e4SLinus Torvalds begin = pos; 14671da177e4SLinus Torvalds } 14681da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 14691da177e4SLinus Torvalds len -= (offset - begin); 14701da177e4SLinus Torvalds if (len > length) 14711da177e4SLinus Torvalds len = length; 14721da177e4SLinus Torvalds return len; 14731da177e4SLinus Torvalds } 14741da177e4SLinus Torvalds 14751da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 14761da177e4SLinus Torvalds { 14771da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 14781da177e4SLinus Torvalds } 14791da177e4SLinus Torvalds 14801da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 14811da177e4SLinus Torvalds const char * buf, size_t count) 14821da177e4SLinus Torvalds { 14831da177e4SLinus Torvalds int delay; 14841da177e4SLinus Torvalds char work[20]; 14851da177e4SLinus Torvalds 14861da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 14871da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 14881da177e4SLinus Torvalds scsi_debug_delay = delay; 14891da177e4SLinus Torvalds return count; 14901da177e4SLinus Torvalds } 14911da177e4SLinus Torvalds } 14921da177e4SLinus Torvalds return -EINVAL; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 14951da177e4SLinus Torvalds sdebug_delay_store); 14961da177e4SLinus Torvalds 14971da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 14981da177e4SLinus Torvalds { 14991da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 15001da177e4SLinus Torvalds } 15011da177e4SLinus Torvalds 15021da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 15031da177e4SLinus Torvalds const char * buf, size_t count) 15041da177e4SLinus Torvalds { 15051da177e4SLinus Torvalds int opts; 15061da177e4SLinus Torvalds char work[20]; 15071da177e4SLinus Torvalds 15081da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 15091da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 15101da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 15111da177e4SLinus Torvalds goto opts_done; 15121da177e4SLinus Torvalds } else { 15131da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 15141da177e4SLinus Torvalds goto opts_done; 15151da177e4SLinus Torvalds } 15161da177e4SLinus Torvalds } 15171da177e4SLinus Torvalds return -EINVAL; 15181da177e4SLinus Torvalds opts_done: 15191da177e4SLinus Torvalds scsi_debug_opts = opts; 15201da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 15211da177e4SLinus Torvalds return count; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 15241da177e4SLinus Torvalds sdebug_opts_store); 15251da177e4SLinus Torvalds 15261da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 15271da177e4SLinus Torvalds { 15281da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 15291da177e4SLinus Torvalds } 15301da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 15311da177e4SLinus Torvalds const char * buf, size_t count) 15321da177e4SLinus Torvalds { 15331da177e4SLinus Torvalds int n; 15341da177e4SLinus Torvalds 15351da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 15361da177e4SLinus Torvalds scsi_debug_ptype = n; 15371da177e4SLinus Torvalds return count; 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds return -EINVAL; 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 15421da177e4SLinus Torvalds 15431da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 15441da177e4SLinus Torvalds { 15451da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 15461da177e4SLinus Torvalds } 15471da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 15481da177e4SLinus Torvalds const char * buf, size_t count) 15491da177e4SLinus Torvalds { 15501da177e4SLinus Torvalds int n; 15511da177e4SLinus Torvalds 15521da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 15531da177e4SLinus Torvalds scsi_debug_dsense = n; 15541da177e4SLinus Torvalds return count; 15551da177e4SLinus Torvalds } 15561da177e4SLinus Torvalds return -EINVAL; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 15591da177e4SLinus Torvalds sdebug_dsense_store); 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 15621da177e4SLinus Torvalds { 15631da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 15641da177e4SLinus Torvalds } 15651da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 15661da177e4SLinus Torvalds const char * buf, size_t count) 15671da177e4SLinus Torvalds { 15681da177e4SLinus Torvalds int n; 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 15711da177e4SLinus Torvalds scsi_debug_num_tgts = n; 15721da177e4SLinus Torvalds sdebug_max_tgts_luns(); 15731da177e4SLinus Torvalds return count; 15741da177e4SLinus Torvalds } 15751da177e4SLinus Torvalds return -EINVAL; 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 15781da177e4SLinus Torvalds sdebug_num_tgts_store); 15791da177e4SLinus Torvalds 15801da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 15811da177e4SLinus Torvalds { 15821da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 15831da177e4SLinus Torvalds } 15841da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 15851da177e4SLinus Torvalds 15861da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 15871da177e4SLinus Torvalds { 15881da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 15891da177e4SLinus Torvalds } 15901da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 15911da177e4SLinus Torvalds 15921da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 15931da177e4SLinus Torvalds { 15941da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 15951da177e4SLinus Torvalds } 15961da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 15971da177e4SLinus Torvalds const char * buf, size_t count) 15981da177e4SLinus Torvalds { 15991da177e4SLinus Torvalds int nth; 16001da177e4SLinus Torvalds 16011da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 16021da177e4SLinus Torvalds scsi_debug_every_nth = nth; 16031da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 16041da177e4SLinus Torvalds return count; 16051da177e4SLinus Torvalds } 16061da177e4SLinus Torvalds return -EINVAL; 16071da177e4SLinus Torvalds } 16081da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 16091da177e4SLinus Torvalds sdebug_every_nth_store); 16101da177e4SLinus Torvalds 16111da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 16121da177e4SLinus Torvalds { 16131da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 16141da177e4SLinus Torvalds } 16151da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 16161da177e4SLinus Torvalds const char * buf, size_t count) 16171da177e4SLinus Torvalds { 16181da177e4SLinus Torvalds int n; 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 16211da177e4SLinus Torvalds scsi_debug_max_luns = n; 16221da177e4SLinus Torvalds sdebug_max_tgts_luns(); 16231da177e4SLinus Torvalds return count; 16241da177e4SLinus Torvalds } 16251da177e4SLinus Torvalds return -EINVAL; 16261da177e4SLinus Torvalds } 16271da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 16281da177e4SLinus Torvalds sdebug_max_luns_store); 16291da177e4SLinus Torvalds 16301da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 16311da177e4SLinus Torvalds { 16321da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 16331da177e4SLinus Torvalds } 16341da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 16351da177e4SLinus Torvalds 16361da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 16371da177e4SLinus Torvalds { 16381da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 16391da177e4SLinus Torvalds } 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 16421da177e4SLinus Torvalds const char * buf, size_t count) 16431da177e4SLinus Torvalds { 16441da177e4SLinus Torvalds int delta_hosts; 16451da177e4SLinus Torvalds char work[20]; 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds if (1 != sscanf(buf, "%10s", work)) 16481da177e4SLinus Torvalds return -EINVAL; 16491da177e4SLinus Torvalds { /* temporary hack around sscanf() problem with -ve nums */ 16501da177e4SLinus Torvalds int neg = 0; 16511da177e4SLinus Torvalds 16521da177e4SLinus Torvalds if ('-' == *work) 16531da177e4SLinus Torvalds neg = 1; 16541da177e4SLinus Torvalds if (1 != sscanf(work + neg, "%d", &delta_hosts)) 16551da177e4SLinus Torvalds return -EINVAL; 16561da177e4SLinus Torvalds if (neg) 16571da177e4SLinus Torvalds delta_hosts = -delta_hosts; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds if (delta_hosts > 0) { 16601da177e4SLinus Torvalds do { 16611da177e4SLinus Torvalds sdebug_add_adapter(); 16621da177e4SLinus Torvalds } while (--delta_hosts); 16631da177e4SLinus Torvalds } else if (delta_hosts < 0) { 16641da177e4SLinus Torvalds do { 16651da177e4SLinus Torvalds sdebug_remove_adapter(); 16661da177e4SLinus Torvalds } while (++delta_hosts); 16671da177e4SLinus Torvalds } 16681da177e4SLinus Torvalds return count; 16691da177e4SLinus Torvalds } 16701da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 16711da177e4SLinus Torvalds sdebug_add_host_store); 16721da177e4SLinus Torvalds 16731da177e4SLinus Torvalds static void do_create_driverfs_files(void) 16741da177e4SLinus Torvalds { 16751da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 16761da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 16771da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 16781da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 16791da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 16801da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 16811da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 16821da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 16831da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 16841da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 16851da177e4SLinus Torvalds driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 16861da177e4SLinus Torvalds } 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 16891da177e4SLinus Torvalds { 16901da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 16911da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 16921da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 16931da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 16941da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 16951da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 16961da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 16971da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 16981da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 16991da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 17001da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 17011da177e4SLinus Torvalds } 17021da177e4SLinus Torvalds 17031da177e4SLinus Torvalds static int __init scsi_debug_init(void) 17041da177e4SLinus Torvalds { 17051da177e4SLinus Torvalds unsigned long sz; 17061da177e4SLinus Torvalds int host_to_add; 17071da177e4SLinus Torvalds int k; 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 17101da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 17111da177e4SLinus Torvalds sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576; 17121da177e4SLinus Torvalds sdebug_capacity = sdebug_store_size / SECT_SIZE; 17131da177e4SLinus Torvalds 17141da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 17151da177e4SLinus Torvalds sdebug_heads = 8; 17161da177e4SLinus Torvalds sdebug_sectors_per = 32; 17171da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 17181da177e4SLinus Torvalds sdebug_heads = 32; 17191da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 17201da177e4SLinus Torvalds sdebug_heads = 64; 17211da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 17221da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 17231da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 17241da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 17251da177e4SLinus Torvalds sdebug_heads = 255; 17261da177e4SLinus Torvalds sdebug_sectors_per = 63; 17271da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 17281da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 17291da177e4SLinus Torvalds } 17301da177e4SLinus Torvalds 17311da177e4SLinus Torvalds sz = sdebug_store_size; 17321da177e4SLinus Torvalds fake_storep = vmalloc(sz); 17331da177e4SLinus Torvalds if (NULL == fake_storep) { 17341da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 17351da177e4SLinus Torvalds return -ENOMEM; 17361da177e4SLinus Torvalds } 17371da177e4SLinus Torvalds memset(fake_storep, 0, sz); 17381da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 17391da177e4SLinus Torvalds sdebug_build_parts(fake_storep); 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds init_all_queued(); 17421da177e4SLinus Torvalds 17431da177e4SLinus Torvalds device_register(&pseudo_primary); 17441da177e4SLinus Torvalds bus_register(&pseudo_lld_bus); 17451da177e4SLinus Torvalds driver_register(&sdebug_driverfs_driver); 17461da177e4SLinus Torvalds do_create_driverfs_files(); 17471da177e4SLinus Torvalds 17481da177e4SLinus Torvalds sdebug_driver_template.proc_name = (char *)sdebug_proc_name; 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 17511da177e4SLinus Torvalds scsi_debug_add_host = 0; 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 17541da177e4SLinus Torvalds if (sdebug_add_adapter()) { 17551da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 17561da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 17571da177e4SLinus Torvalds break; 17581da177e4SLinus Torvalds } 17591da177e4SLinus Torvalds } 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 17621da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 17631da177e4SLinus Torvalds scsi_debug_add_host); 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds return 0; 17661da177e4SLinus Torvalds } 17671da177e4SLinus Torvalds 17681da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 17691da177e4SLinus Torvalds { 17701da177e4SLinus Torvalds int k = scsi_debug_add_host; 17711da177e4SLinus Torvalds 17721da177e4SLinus Torvalds stop_all_queued(); 17731da177e4SLinus Torvalds for (; k; k--) 17741da177e4SLinus Torvalds sdebug_remove_adapter(); 17751da177e4SLinus Torvalds do_remove_driverfs_files(); 17761da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 17771da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 17781da177e4SLinus Torvalds device_unregister(&pseudo_primary); 17791da177e4SLinus Torvalds 17801da177e4SLinus Torvalds vfree(fake_storep); 17811da177e4SLinus Torvalds } 17821da177e4SLinus Torvalds 17831da177e4SLinus Torvalds device_initcall(scsi_debug_init); 17841da177e4SLinus Torvalds module_exit(scsi_debug_exit); 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds void pseudo_0_release(struct device * dev) 17871da177e4SLinus Torvalds { 17881da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 17891da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); 17901da177e4SLinus Torvalds } 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds static struct device pseudo_primary = { 17931da177e4SLinus Torvalds .bus_id = "pseudo_0", 17941da177e4SLinus Torvalds .release = pseudo_0_release, 17951da177e4SLinus Torvalds }; 17961da177e4SLinus Torvalds 17971da177e4SLinus Torvalds static int pseudo_lld_bus_match(struct device *dev, 17981da177e4SLinus Torvalds struct device_driver *dev_driver) 17991da177e4SLinus Torvalds { 18001da177e4SLinus Torvalds return 1; 18011da177e4SLinus Torvalds } 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus = { 18041da177e4SLinus Torvalds .name = "pseudo", 18051da177e4SLinus Torvalds .match = pseudo_lld_bus_match, 18061da177e4SLinus Torvalds }; 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 18091da177e4SLinus Torvalds { 18101da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 18111da177e4SLinus Torvalds 18121da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 18131da177e4SLinus Torvalds kfree(sdbg_host); 18141da177e4SLinus Torvalds } 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds static int sdebug_add_adapter(void) 18171da177e4SLinus Torvalds { 18181da177e4SLinus Torvalds int k, devs_per_host; 18191da177e4SLinus Torvalds int error = 0; 18201da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 18211da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 18221da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL); 18251da177e4SLinus Torvalds 18261da177e4SLinus Torvalds if (NULL == sdbg_host) { 18271da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 18281da177e4SLinus Torvalds __FUNCTION__, __LINE__); 18291da177e4SLinus Torvalds return -ENOMEM; 18301da177e4SLinus Torvalds } 18311da177e4SLinus Torvalds 18321da177e4SLinus Torvalds memset(sdbg_host, 0, sizeof(*sdbg_host)); 18331da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 18361da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 18371da177e4SLinus Torvalds sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); 18381da177e4SLinus Torvalds if (NULL == sdbg_devinfo) { 18391da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 18401da177e4SLinus Torvalds __FUNCTION__, __LINE__); 18411da177e4SLinus Torvalds error = -ENOMEM; 18421da177e4SLinus Torvalds goto clean; 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo)); 18451da177e4SLinus Torvalds sdbg_devinfo->sdbg_host = sdbg_host; 18461da177e4SLinus Torvalds list_add_tail(&sdbg_devinfo->dev_list, 18471da177e4SLinus Torvalds &sdbg_host->dev_info_list); 18481da177e4SLinus Torvalds } 18491da177e4SLinus Torvalds 18501da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 18511da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 18521da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 18551da177e4SLinus Torvalds sdbg_host->dev.parent = &pseudo_primary; 18561da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 18571da177e4SLinus Torvalds sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); 18581da177e4SLinus Torvalds 18591da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 18601da177e4SLinus Torvalds 18611da177e4SLinus Torvalds if (error) 18621da177e4SLinus Torvalds goto clean; 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds ++scsi_debug_add_host; 18651da177e4SLinus Torvalds return error; 18661da177e4SLinus Torvalds 18671da177e4SLinus Torvalds clean: 18681da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 18691da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 18701da177e4SLinus Torvalds dev_list); 18711da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 18721da177e4SLinus Torvalds kfree(sdbg_devinfo); 18731da177e4SLinus Torvalds } 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds kfree(sdbg_host); 18761da177e4SLinus Torvalds return error; 18771da177e4SLinus Torvalds } 18781da177e4SLinus Torvalds 18791da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 18801da177e4SLinus Torvalds { 18811da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 18841da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 18851da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 18861da177e4SLinus Torvalds struct sdebug_host_info, host_list); 18871da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 18901da177e4SLinus Torvalds 18911da177e4SLinus Torvalds if (!sdbg_host) 18921da177e4SLinus Torvalds return; 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 18951da177e4SLinus Torvalds --scsi_debug_add_host; 18961da177e4SLinus Torvalds } 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 18991da177e4SLinus Torvalds { 19001da177e4SLinus Torvalds int error = 0; 19011da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 19021da177e4SLinus Torvalds struct Scsi_Host *hpnt; 19031da177e4SLinus Torvalds 19041da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 19071da177e4SLinus Torvalds if (NULL == hpnt) { 19081da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); 19091da177e4SLinus Torvalds error = -ENODEV; 19101da177e4SLinus Torvalds return error; 19111da177e4SLinus Torvalds } 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds sdbg_host->shost = hpnt; 19141da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 19151da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 19161da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 19171da177e4SLinus Torvalds else 19181da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 19191da177e4SLinus Torvalds hpnt->max_lun = scsi_debug_max_luns; 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 19221da177e4SLinus Torvalds if (error) { 19231da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); 19241da177e4SLinus Torvalds error = -ENODEV; 19251da177e4SLinus Torvalds scsi_host_put(hpnt); 19261da177e4SLinus Torvalds } else 19271da177e4SLinus Torvalds scsi_scan_host(hpnt); 19281da177e4SLinus Torvalds 19291da177e4SLinus Torvalds 19301da177e4SLinus Torvalds return error; 19311da177e4SLinus Torvalds } 19321da177e4SLinus Torvalds 19331da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 19341da177e4SLinus Torvalds { 19351da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 19361da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 19371da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds if (!sdbg_host) { 19421da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 19431da177e4SLinus Torvalds __FUNCTION__); 19441da177e4SLinus Torvalds return -ENODEV; 19451da177e4SLinus Torvalds } 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 19501da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 19511da177e4SLinus Torvalds dev_list); 19521da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 19531da177e4SLinus Torvalds kfree(sdbg_devinfo); 19541da177e4SLinus Torvalds } 19551da177e4SLinus Torvalds 19561da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 19571da177e4SLinus Torvalds return 0; 19581da177e4SLinus Torvalds } 19591da177e4SLinus Torvalds 19601da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void) 19611da177e4SLinus Torvalds { 19621da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 19631da177e4SLinus Torvalds struct Scsi_Host *hpnt; 19641da177e4SLinus Torvalds 19651da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 19661da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 19671da177e4SLinus Torvalds hpnt = sdbg_host->shost; 19681da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && 19691da177e4SLinus Torvalds (scsi_debug_num_tgts > hpnt->this_id)) 19701da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 19711da177e4SLinus Torvalds else 19721da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 19731da177e4SLinus Torvalds hpnt->max_lun = scsi_debug_max_luns; 19741da177e4SLinus Torvalds } 19751da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 19761da177e4SLinus Torvalds } 1977