11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This version is more generic, simulating a variable number of disk 1023183910SDouglas Gilbert * (or disk like devices) sharing a common amount of RAM. To be more 1123183910SDouglas Gilbert * realistic, the simulated devices have the transport attributes of 1223183910SDouglas Gilbert * SAS disks. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * For documentation see http://www.torque.net/sg/sdebug26.html 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] 181da177e4SLinus Torvalds * dpg: work for devfs large number of disks [20010809] 191da177e4SLinus Torvalds * forked for lk 2.5 series [20011216, 20020101] 201da177e4SLinus Torvalds * use vmalloc() more inquiry+mode_sense [20020302] 211da177e4SLinus Torvalds * add timers for delayed responses [20020721] 221da177e4SLinus Torvalds * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] 231da177e4SLinus Torvalds * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] 241da177e4SLinus Torvalds * dpg: change style of boot options to "scsi_debug.num_tgts=2" and 251da177e4SLinus Torvalds * module options to "modprobe scsi_debug num_tgts=2" [20021221] 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #include <linux/kernel.h> 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/timer.h> 331da177e4SLinus Torvalds #include <linux/types.h> 341da177e4SLinus Torvalds #include <linux/string.h> 351da177e4SLinus Torvalds #include <linux/genhd.h> 361da177e4SLinus Torvalds #include <linux/fs.h> 371da177e4SLinus Torvalds #include <linux/init.h> 381da177e4SLinus Torvalds #include <linux/proc_fs.h> 391da177e4SLinus Torvalds #include <linux/vmalloc.h> 401da177e4SLinus Torvalds #include <linux/moduleparam.h> 411da177e4SLinus Torvalds 421da177e4SLinus Torvalds #include <linux/blkdev.h> 431da177e4SLinus Torvalds #include "scsi.h" 441da177e4SLinus Torvalds #include <scsi/scsi_host.h> 451da177e4SLinus Torvalds #include <scsi/scsicam.h> 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds #include <linux/stat.h> 481da177e4SLinus Torvalds 491da177e4SLinus Torvalds #include "scsi_logging.h" 501da177e4SLinus Torvalds #include "scsi_debug.h" 511da177e4SLinus Torvalds 526f3cbf55SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.81" 536f3cbf55SDouglas Gilbert static const char * scsi_debug_version_date = "20070104"; 541da177e4SLinus Torvalds 556f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 56c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 57c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 581da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 59c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 601da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 611da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 621da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 63c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 641da177e4SLinus Torvalds #define POWERON_RESET 0x29 651da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 666f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 67c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 68c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 691da177e4SLinus Torvalds 706f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 716f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 726f3cbf55SDouglas Gilbert 731da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 741da177e4SLinus Torvalds 751da177e4SLinus Torvalds /* Default values for driver parameters */ 761da177e4SLinus Torvalds #define DEF_NUM_HOST 1 771da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 781da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 791da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 801da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 811da177e4SLinus Torvalds */ 821da177e4SLinus Torvalds #define DEF_DELAY 1 831da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 841da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 851da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 861da177e4SLinus Torvalds #define DEF_OPTS 0 871da177e4SLinus Torvalds #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 881da177e4SLinus Torvalds #define DEF_PTYPE 0 891da177e4SLinus Torvalds #define DEF_D_SENSE 0 90c65b1445SDouglas Gilbert #define DEF_NO_LUN_0 0 91c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB 0 9223183910SDouglas Gilbert #define DEF_FAKE_RW 0 9323183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 961da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 971da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 981da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 991da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1006f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 1011da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1021da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1031da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1041da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1056f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1066f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1071da177e4SLinus Torvalds * 1081da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1091da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1101da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1111da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1126f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1136f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1141da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1151da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1161da177e4SLinus Torvalds */ 1171da177e4SLinus Torvalds 1181da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1191da177e4SLinus Torvalds * sector on read commands: */ 1201da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1231da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1241da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 125c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1281da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1291da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1301da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1311da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 1321da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 1331da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1341da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1351da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1361da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1371da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 138c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 139c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 14023183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW; 14123183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 1421da177e4SLinus Torvalds 1431da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1461da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1471da177e4SLinus Torvalds 148c65b1445SDouglas Gilbert static unsigned int sdebug_store_size; /* in bytes */ 149c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 1501da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1511da177e4SLinus Torvalds 1521da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1531da177e4SLinus Torvalds may still need them */ 1541da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 1551da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 1561da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 1571da177e4SLinus Torvalds 1581da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */ 1591da177e4SLinus Torvalds #define POW2_SECT_SIZE 9 1601da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE) 1611da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE 1621da177e4SLinus Torvalds 1631da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds struct sdebug_dev_info { 1681da177e4SLinus Torvalds struct list_head dev_list; 1691da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 1701da177e4SLinus Torvalds unsigned int channel; 1711da177e4SLinus Torvalds unsigned int target; 1721da177e4SLinus Torvalds unsigned int lun; 1731da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 174c65b1445SDouglas Gilbert unsigned int wlun; 1751da177e4SLinus Torvalds char reset; 176c65b1445SDouglas Gilbert char stopped; 1771da177e4SLinus Torvalds char used; 1781da177e4SLinus Torvalds }; 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds struct sdebug_host_info { 1811da177e4SLinus Torvalds struct list_head host_list; 1821da177e4SLinus Torvalds struct Scsi_Host *shost; 1831da177e4SLinus Torvalds struct device dev; 1841da177e4SLinus Torvalds struct list_head dev_info_list; 1851da177e4SLinus Torvalds }; 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds #define to_sdebug_host(d) \ 1881da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 1911da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds struct sdebug_queued_cmd { 1961da177e4SLinus Torvalds int in_use; 1971da177e4SLinus Torvalds struct timer_list cmnd_timer; 1981da177e4SLinus Torvalds done_funct_t done_funct; 1991da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2001da177e4SLinus Torvalds int scsi_result; 2011da177e4SLinus Torvalds }; 2021da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2031da177e4SLinus Torvalds 204d0be4a7dSChristoph Hellwig static struct scsi_host_template sdebug_driver_template = { 2051da177e4SLinus Torvalds .proc_info = scsi_debug_proc_info, 2061da177e4SLinus Torvalds .name = "SCSI DEBUG", 2071da177e4SLinus Torvalds .info = scsi_debug_info, 2081da177e4SLinus Torvalds .slave_alloc = scsi_debug_slave_alloc, 2091da177e4SLinus Torvalds .slave_configure = scsi_debug_slave_configure, 2101da177e4SLinus Torvalds .slave_destroy = scsi_debug_slave_destroy, 2111da177e4SLinus Torvalds .ioctl = scsi_debug_ioctl, 2121da177e4SLinus Torvalds .queuecommand = scsi_debug_queuecommand, 2131da177e4SLinus Torvalds .eh_abort_handler = scsi_debug_abort, 2141da177e4SLinus Torvalds .eh_bus_reset_handler = scsi_debug_bus_reset, 2151da177e4SLinus Torvalds .eh_device_reset_handler = scsi_debug_device_reset, 2161da177e4SLinus Torvalds .eh_host_reset_handler = scsi_debug_host_reset, 2171da177e4SLinus Torvalds .bios_param = scsi_debug_biosparam, 2181da177e4SLinus Torvalds .can_queue = SCSI_DEBUG_CANQUEUE, 2191da177e4SLinus Torvalds .this_id = 7, 220c65b1445SDouglas Gilbert .sg_tablesize = 256, 221c65b1445SDouglas Gilbert .cmd_per_lun = 16, 222c65b1445SDouglas Gilbert .max_sectors = 0xffff, 2231da177e4SLinus Torvalds .unchecked_isa_dma = 0, 224c65b1445SDouglas Gilbert .use_clustering = ENABLE_CLUSTERING, 2251da177e4SLinus Torvalds .module = THIS_MODULE, 2261da177e4SLinus Torvalds }; 2271da177e4SLinus Torvalds 2281da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static int num_aborts = 0; 2311da177e4SLinus Torvalds static int num_dev_resets = 0; 2321da177e4SLinus Torvalds static int num_bus_resets = 0; 2331da177e4SLinus Torvalds static int num_host_resets = 0; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2361da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *); 2411da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *); 2421da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2451da177e4SLinus Torvalds .name = sdebug_proc_name, 2461da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2471da177e4SLinus Torvalds }; 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds static const int check_condition_result = 2501da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2511da177e4SLinus Torvalds 252c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 253c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 254c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 255c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 256c65b1445SDouglas Gilbert 2571da177e4SLinus Torvalds /* function declarations */ 2581da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * SCpnt, int target, 2591da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2601da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * SCpnt, 2611da177e4SLinus Torvalds struct sdebug_dev_info * devip); 262c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 263c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 2645a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 2655a09e398SHannes Reinecke struct sdebug_dev_info * devip); 2661da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * SCpnt, 2671da177e4SLinus Torvalds struct sdebug_dev_info * devip); 268c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * SCpnt, 2691da177e4SLinus Torvalds struct sdebug_dev_info * devip); 270c65b1445SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd * scp, int target, 271c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 272c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 273c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 274c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 275c65b1445SDouglas Gilbert struct sdebug_dev_info * devip); 276c65b1445SDouglas Gilbert static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, 277c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip); 278c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, 279c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip); 2801da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * SCpnt, 2811da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2821da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2831da177e4SLinus Torvalds int arr_len); 2841da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 2851da177e4SLinus Torvalds int max_arr_len); 2861da177e4SLinus Torvalds static void timer_intr_handler(unsigned long); 2871da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); 2881da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 2891da177e4SLinus Torvalds int asc, int asq); 290c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 2911da177e4SLinus Torvalds struct sdebug_dev_info * devip); 2921da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 2931da177e4SLinus Torvalds struct sdebug_dev_info * devip, 2941da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff); 2951da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp); 2961da177e4SLinus Torvalds static void __init init_all_queued(void); 2971da177e4SLinus Torvalds static void stop_all_queued(void); 2981da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd); 2995a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 3005a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 3015a09e398SHannes Reinecke const char * dev_id_str, int dev_id_str_len); 302c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id); 3036ecaff7fSRandy Dunlap static int do_create_driverfs_files(void); 3041da177e4SLinus Torvalds static void do_remove_driverfs_files(void); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds static int sdebug_add_adapter(void); 3071da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 3081da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void); 3091da177e4SLinus Torvalds 3101da177e4SLinus Torvalds static struct device pseudo_primary; 3111da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 3121da177e4SLinus Torvalds 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds static 3151da177e4SLinus Torvalds int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done) 3161da177e4SLinus Torvalds { 3171da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 318c65b1445SDouglas Gilbert int len, k, j; 319c65b1445SDouglas Gilbert unsigned int num; 320c65b1445SDouglas Gilbert unsigned long long lba; 3211da177e4SLinus Torvalds int errsts = 0; 322c65b1445SDouglas Gilbert int target = SCpnt->device->id; 3231da177e4SLinus Torvalds struct sdebug_dev_info * devip = NULL; 3241da177e4SLinus Torvalds int inj_recovered = 0; 3256f3cbf55SDouglas Gilbert int inj_transport = 0; 326c65b1445SDouglas Gilbert int delay_override = 0; 3271da177e4SLinus Torvalds 3281da177e4SLinus Torvalds if (done == NULL) 3291da177e4SLinus Torvalds return 0; /* assume mid level reprocessing command */ 3301da177e4SLinus Torvalds 331c65b1445SDouglas Gilbert SCpnt->resid = 0; 3321da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 3331da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: cmd "); 334c65b1445SDouglas Gilbert for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 3351da177e4SLinus Torvalds printk("%02x ", (int)cmd[k]); 3361da177e4SLinus Torvalds printk("\n"); 3371da177e4SLinus Torvalds } 3381da177e4SLinus Torvalds if(target == sdebug_driver_template.this_id) { 3391da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: initiator's id used as " 3401da177e4SLinus Torvalds "target!\n"); 3411da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3421da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 345c65b1445SDouglas Gilbert if ((SCpnt->device->lun >= scsi_debug_max_luns) && 346c65b1445SDouglas Gilbert (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 3471da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3481da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3491da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 3501da177e4SLinus Torvalds if (NULL == devip) 3511da177e4SLinus Torvalds return schedule_resp(SCpnt, NULL, done, 3521da177e4SLinus Torvalds DID_NO_CONNECT << 16, 0); 3531da177e4SLinus Torvalds 3541da177e4SLinus Torvalds if ((scsi_debug_every_nth != 0) && 3551da177e4SLinus Torvalds (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3561da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 3571da177e4SLinus Torvalds if (scsi_debug_every_nth < -1) 3581da177e4SLinus Torvalds scsi_debug_every_nth = -1; 3591da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3601da177e4SLinus Torvalds return 0; /* ignore command causing timeout */ 3611da177e4SLinus Torvalds else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3621da177e4SLinus Torvalds inj_recovered = 1; /* to reads and writes below */ 3636f3cbf55SDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 3646f3cbf55SDouglas Gilbert inj_transport = 1; /* to reads and writes below */ 3651da177e4SLinus Torvalds } 3661da177e4SLinus Torvalds 367c65b1445SDouglas Gilbert if (devip->wlun) { 368c65b1445SDouglas Gilbert switch (*cmd) { 369c65b1445SDouglas Gilbert case INQUIRY: 370c65b1445SDouglas Gilbert case REQUEST_SENSE: 371c65b1445SDouglas Gilbert case TEST_UNIT_READY: 372c65b1445SDouglas Gilbert case REPORT_LUNS: 373c65b1445SDouglas Gilbert break; /* only allowable wlun commands */ 374c65b1445SDouglas Gilbert default: 375c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 376c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 377c65b1445SDouglas Gilbert "not supported for wlun\n", *cmd); 378c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 379c65b1445SDouglas Gilbert INVALID_OPCODE, 0); 380c65b1445SDouglas Gilbert errsts = check_condition_result; 381c65b1445SDouglas Gilbert return schedule_resp(SCpnt, devip, done, errsts, 382c65b1445SDouglas Gilbert 0); 383c65b1445SDouglas Gilbert } 384c65b1445SDouglas Gilbert } 385c65b1445SDouglas Gilbert 3861da177e4SLinus Torvalds switch (*cmd) { 3871da177e4SLinus Torvalds case INQUIRY: /* mandatory, ignore unit attention */ 388c65b1445SDouglas Gilbert delay_override = 1; 3891da177e4SLinus Torvalds errsts = resp_inquiry(SCpnt, target, devip); 3901da177e4SLinus Torvalds break; 3911da177e4SLinus Torvalds case REQUEST_SENSE: /* mandatory, ignore unit attention */ 392c65b1445SDouglas Gilbert delay_override = 1; 3931da177e4SLinus Torvalds errsts = resp_requests(SCpnt, devip); 3941da177e4SLinus Torvalds break; 3951da177e4SLinus Torvalds case REZERO_UNIT: /* actually this is REWIND for SSC */ 3961da177e4SLinus Torvalds case START_STOP: 397c65b1445SDouglas Gilbert errsts = resp_start_stop(SCpnt, devip); 3981da177e4SLinus Torvalds break; 3991da177e4SLinus Torvalds case ALLOW_MEDIUM_REMOVAL: 400c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 1, devip))) 4011da177e4SLinus Torvalds break; 4021da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4031da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Medium removal %s\n", 4041da177e4SLinus Torvalds cmd[4] ? "inhibited" : "enabled"); 4051da177e4SLinus Torvalds break; 4061da177e4SLinus Torvalds case SEND_DIAGNOSTIC: /* mandatory */ 407c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4081da177e4SLinus Torvalds break; 4091da177e4SLinus Torvalds case TEST_UNIT_READY: /* mandatory */ 410c65b1445SDouglas Gilbert delay_override = 1; 411c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 4121da177e4SLinus Torvalds break; 4131da177e4SLinus Torvalds case RESERVE: 414c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4151da177e4SLinus Torvalds break; 4161da177e4SLinus Torvalds case RESERVE_10: 417c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4181da177e4SLinus Torvalds break; 4191da177e4SLinus Torvalds case RELEASE: 420c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4211da177e4SLinus Torvalds break; 4221da177e4SLinus Torvalds case RELEASE_10: 423c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 4241da177e4SLinus Torvalds break; 4251da177e4SLinus Torvalds case READ_CAPACITY: 4261da177e4SLinus Torvalds errsts = resp_readcap(SCpnt, devip); 4271da177e4SLinus Torvalds break; 428c65b1445SDouglas Gilbert case SERVICE_ACTION_IN: 429c65b1445SDouglas Gilbert if (SAI_READ_CAPACITY_16 != cmd[1]) { 430c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 431c65b1445SDouglas Gilbert INVALID_OPCODE, 0); 432c65b1445SDouglas Gilbert errsts = check_condition_result; 433c65b1445SDouglas Gilbert break; 434c65b1445SDouglas Gilbert } 435c65b1445SDouglas Gilbert errsts = resp_readcap16(SCpnt, devip); 436c65b1445SDouglas Gilbert break; 4375a09e398SHannes Reinecke case MAINTENANCE_IN: 4385a09e398SHannes Reinecke if (MI_REPORT_TARGET_PGS != cmd[1]) { 4395a09e398SHannes Reinecke mk_sense_buffer(devip, ILLEGAL_REQUEST, 4405a09e398SHannes Reinecke INVALID_OPCODE, 0); 4415a09e398SHannes Reinecke errsts = check_condition_result; 4425a09e398SHannes Reinecke break; 4435a09e398SHannes Reinecke } 4445a09e398SHannes Reinecke errsts = resp_report_tgtpgs(SCpnt, devip); 4455a09e398SHannes Reinecke break; 4461da177e4SLinus Torvalds case READ_16: 4471da177e4SLinus Torvalds case READ_12: 4481da177e4SLinus Torvalds case READ_10: 4491da177e4SLinus Torvalds case READ_6: 450c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 0, devip))) 4511da177e4SLinus Torvalds break; 45223183910SDouglas Gilbert if (scsi_debug_fake_rw) 45323183910SDouglas Gilbert break; 4541da177e4SLinus Torvalds if ((*cmd) == READ_16) { 455c65b1445SDouglas Gilbert for (lba = 0, j = 0; j < 8; ++j) { 456c65b1445SDouglas Gilbert if (j > 0) 457c65b1445SDouglas Gilbert lba <<= 8; 458c65b1445SDouglas Gilbert lba += cmd[2 + j]; 459c65b1445SDouglas Gilbert } 4601da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 4611da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 4621da177e4SLinus Torvalds } else if ((*cmd) == READ_12) { 463c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4641da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4651da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 4661da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 4671da177e4SLinus Torvalds } else if ((*cmd) == READ_10) { 468c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 4691da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 4701da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 471c65b1445SDouglas Gilbert } else { /* READ (6) */ 472c65b1445SDouglas Gilbert lba = cmd[3] + (cmd[2] << 8) + 4731da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 474c65b1445SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 4751da177e4SLinus Torvalds } 476c65b1445SDouglas Gilbert errsts = resp_read(SCpnt, lba, num, devip); 4771da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 4781da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 479c65b1445SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 4801da177e4SLinus Torvalds errsts = check_condition_result; 4816f3cbf55SDouglas Gilbert } else if (inj_transport && (0 == errsts)) { 4826f3cbf55SDouglas Gilbert mk_sense_buffer(devip, ABORTED_COMMAND, 4836f3cbf55SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 4846f3cbf55SDouglas Gilbert errsts = check_condition_result; 4851da177e4SLinus Torvalds } 4861da177e4SLinus Torvalds break; 4871da177e4SLinus Torvalds case REPORT_LUNS: /* mandatory, ignore unit attention */ 488c65b1445SDouglas Gilbert delay_override = 1; 4891da177e4SLinus Torvalds errsts = resp_report_luns(SCpnt, devip); 4901da177e4SLinus Torvalds break; 4911da177e4SLinus Torvalds case VERIFY: /* 10 byte SBC-2 command */ 492c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 4931da177e4SLinus Torvalds break; 4941da177e4SLinus Torvalds case WRITE_16: 4951da177e4SLinus Torvalds case WRITE_12: 4961da177e4SLinus Torvalds case WRITE_10: 4971da177e4SLinus Torvalds case WRITE_6: 498c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 0, devip))) 4991da177e4SLinus Torvalds break; 50023183910SDouglas Gilbert if (scsi_debug_fake_rw) 50123183910SDouglas Gilbert break; 5021da177e4SLinus Torvalds if ((*cmd) == WRITE_16) { 503c65b1445SDouglas Gilbert for (lba = 0, j = 0; j < 8; ++j) { 504c65b1445SDouglas Gilbert if (j > 0) 505c65b1445SDouglas Gilbert lba <<= 8; 506c65b1445SDouglas Gilbert lba += cmd[2 + j]; 507c65b1445SDouglas Gilbert } 5081da177e4SLinus Torvalds num = cmd[13] + (cmd[12] << 8) + 5091da177e4SLinus Torvalds (cmd[11] << 16) + (cmd[10] << 24); 5101da177e4SLinus Torvalds } else if ((*cmd) == WRITE_12) { 511c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 5121da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 5131da177e4SLinus Torvalds num = cmd[9] + (cmd[8] << 8) + 5141da177e4SLinus Torvalds (cmd[7] << 16) + (cmd[6] << 24); 5151da177e4SLinus Torvalds } else if ((*cmd) == WRITE_10) { 516c65b1445SDouglas Gilbert lba = cmd[5] + (cmd[4] << 8) + 5171da177e4SLinus Torvalds (cmd[3] << 16) + (cmd[2] << 24); 5181da177e4SLinus Torvalds num = cmd[8] + (cmd[7] << 8); 519c65b1445SDouglas Gilbert } else { /* WRITE (6) */ 520c65b1445SDouglas Gilbert lba = cmd[3] + (cmd[2] << 8) + 5211da177e4SLinus Torvalds ((cmd[1] & 0x1f) << 16); 522c65b1445SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 5231da177e4SLinus Torvalds } 524c65b1445SDouglas Gilbert errsts = resp_write(SCpnt, lba, num, devip); 5251da177e4SLinus Torvalds if (inj_recovered && (0 == errsts)) { 5261da177e4SLinus Torvalds mk_sense_buffer(devip, RECOVERED_ERROR, 527c65b1445SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 5281da177e4SLinus Torvalds errsts = check_condition_result; 5291da177e4SLinus Torvalds } 5301da177e4SLinus Torvalds break; 5311da177e4SLinus Torvalds case MODE_SENSE: 5321da177e4SLinus Torvalds case MODE_SENSE_10: 5331da177e4SLinus Torvalds errsts = resp_mode_sense(SCpnt, target, devip); 5341da177e4SLinus Torvalds break; 535c65b1445SDouglas Gilbert case MODE_SELECT: 536c65b1445SDouglas Gilbert errsts = resp_mode_select(SCpnt, 1, devip); 537c65b1445SDouglas Gilbert break; 538c65b1445SDouglas Gilbert case MODE_SELECT_10: 539c65b1445SDouglas Gilbert errsts = resp_mode_select(SCpnt, 0, devip); 540c65b1445SDouglas Gilbert break; 541c65b1445SDouglas Gilbert case LOG_SENSE: 542c65b1445SDouglas Gilbert errsts = resp_log_sense(SCpnt, devip); 543c65b1445SDouglas Gilbert break; 5441da177e4SLinus Torvalds case SYNCHRONIZE_CACHE: 545c65b1445SDouglas Gilbert delay_override = 1; 546c65b1445SDouglas Gilbert errsts = check_readiness(SCpnt, 0, devip); 5471da177e4SLinus Torvalds break; 5486f3cbf55SDouglas Gilbert case WRITE_BUFFER: 5496f3cbf55SDouglas Gilbert errsts = check_readiness(SCpnt, 1, devip); 5506f3cbf55SDouglas Gilbert break; 5511da177e4SLinus Torvalds default: 5521da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 5531da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 5541da177e4SLinus Torvalds "supported\n", *cmd); 555c65b1445SDouglas Gilbert if ((errsts = check_readiness(SCpnt, 1, devip))) 5561da177e4SLinus Torvalds break; /* Unit attention takes precedence */ 5571da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 5581da177e4SLinus Torvalds errsts = check_condition_result; 5591da177e4SLinus Torvalds break; 5601da177e4SLinus Torvalds } 561c65b1445SDouglas Gilbert return schedule_resp(SCpnt, devip, done, errsts, 562c65b1445SDouglas Gilbert (delay_override ? 0 : scsi_debug_delay)); 5631da177e4SLinus Torvalds } 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 5661da177e4SLinus Torvalds { 5671da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 5681da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds return -EINVAL; 5711da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 5721da177e4SLinus Torvalds } 5731da177e4SLinus Torvalds 574c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 575c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 5761da177e4SLinus Torvalds { 5771da177e4SLinus Torvalds if (devip->reset) { 5781da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 5791da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 5801da177e4SLinus Torvalds "attention: power on reset\n"); 5811da177e4SLinus Torvalds devip->reset = 0; 5821da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 5831da177e4SLinus Torvalds return check_condition_result; 5841da177e4SLinus Torvalds } 585c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 586c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 587c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 588c65b1445SDouglas Gilbert "ready: initializing command required\n"); 589c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 590c65b1445SDouglas Gilbert 0x2); 591c65b1445SDouglas Gilbert return check_condition_result; 592c65b1445SDouglas Gilbert } 5931da177e4SLinus Torvalds return 0; 5941da177e4SLinus Torvalds } 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 5971da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 5981da177e4SLinus Torvalds int arr_len) 5991da177e4SLinus Torvalds { 6001da177e4SLinus Torvalds int k, req_len, act_len, len, active; 6011da177e4SLinus Torvalds void * kaddr; 6021da177e4SLinus Torvalds void * kaddr_off; 6031da177e4SLinus Torvalds struct scatterlist * sgpnt; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds if (0 == scp->request_bufflen) 6061da177e4SLinus Torvalds return 0; 6071da177e4SLinus Torvalds if (NULL == scp->request_buffer) 6081da177e4SLinus Torvalds return (DID_ERROR << 16); 6091da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 6101da177e4SLinus Torvalds (scp->sc_data_direction == DMA_FROM_DEVICE))) 6111da177e4SLinus Torvalds return (DID_ERROR << 16); 6121da177e4SLinus Torvalds if (0 == scp->use_sg) { 6131da177e4SLinus Torvalds req_len = scp->request_bufflen; 6141da177e4SLinus Torvalds act_len = (req_len < arr_len) ? req_len : arr_len; 6151da177e4SLinus Torvalds memcpy(scp->request_buffer, arr, act_len); 616c65b1445SDouglas Gilbert if (scp->resid) 617c65b1445SDouglas Gilbert scp->resid -= act_len; 618c65b1445SDouglas Gilbert else 6191da177e4SLinus Torvalds scp->resid = req_len - act_len; 6201da177e4SLinus Torvalds return 0; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 6231da177e4SLinus Torvalds active = 1; 6241da177e4SLinus Torvalds for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) { 6251da177e4SLinus Torvalds if (active) { 6261da177e4SLinus Torvalds kaddr = (unsigned char *) 6271da177e4SLinus Torvalds kmap_atomic(sgpnt->page, KM_USER0); 6281da177e4SLinus Torvalds if (NULL == kaddr) 6291da177e4SLinus Torvalds return (DID_ERROR << 16); 6301da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 6311da177e4SLinus Torvalds len = sgpnt->length; 6321da177e4SLinus Torvalds if ((req_len + len) > arr_len) { 6331da177e4SLinus Torvalds active = 0; 6341da177e4SLinus Torvalds len = arr_len - req_len; 6351da177e4SLinus Torvalds } 6361da177e4SLinus Torvalds memcpy(kaddr_off, arr + req_len, len); 6371da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 6381da177e4SLinus Torvalds act_len += len; 6391da177e4SLinus Torvalds } 6401da177e4SLinus Torvalds req_len += sgpnt->length; 6411da177e4SLinus Torvalds } 642c65b1445SDouglas Gilbert if (scp->resid) 643c65b1445SDouglas Gilbert scp->resid -= act_len; 644c65b1445SDouglas Gilbert else 6451da177e4SLinus Torvalds scp->resid = req_len - act_len; 6461da177e4SLinus Torvalds return 0; 6471da177e4SLinus Torvalds } 6481da177e4SLinus Torvalds 6491da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 6501da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr, 6511da177e4SLinus Torvalds int max_arr_len) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds int k, req_len, len, fin; 6541da177e4SLinus Torvalds void * kaddr; 6551da177e4SLinus Torvalds void * kaddr_off; 6561da177e4SLinus Torvalds struct scatterlist * sgpnt; 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds if (0 == scp->request_bufflen) 6591da177e4SLinus Torvalds return 0; 6601da177e4SLinus Torvalds if (NULL == scp->request_buffer) 6611da177e4SLinus Torvalds return -1; 6621da177e4SLinus Torvalds if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) || 6631da177e4SLinus Torvalds (scp->sc_data_direction == DMA_TO_DEVICE))) 6641da177e4SLinus Torvalds return -1; 6651da177e4SLinus Torvalds if (0 == scp->use_sg) { 6661da177e4SLinus Torvalds req_len = scp->request_bufflen; 6671da177e4SLinus Torvalds len = (req_len < max_arr_len) ? req_len : max_arr_len; 6681da177e4SLinus Torvalds memcpy(arr, scp->request_buffer, len); 6691da177e4SLinus Torvalds return len; 6701da177e4SLinus Torvalds } 6711da177e4SLinus Torvalds sgpnt = (struct scatterlist *)scp->request_buffer; 6721da177e4SLinus Torvalds for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) { 6731da177e4SLinus Torvalds kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0); 6741da177e4SLinus Torvalds if (NULL == kaddr) 6751da177e4SLinus Torvalds return -1; 6761da177e4SLinus Torvalds kaddr_off = (unsigned char *)kaddr + sgpnt->offset; 6771da177e4SLinus Torvalds len = sgpnt->length; 6781da177e4SLinus Torvalds if ((req_len + len) > max_arr_len) { 6791da177e4SLinus Torvalds len = max_arr_len - req_len; 6801da177e4SLinus Torvalds fin = 1; 6811da177e4SLinus Torvalds } 6821da177e4SLinus Torvalds memcpy(arr + req_len, kaddr_off, len); 6831da177e4SLinus Torvalds kunmap_atomic(kaddr, KM_USER0); 6841da177e4SLinus Torvalds if (fin) 6851da177e4SLinus Torvalds return req_len + len; 6861da177e4SLinus Torvalds req_len += sgpnt->length; 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds return req_len; 6891da177e4SLinus Torvalds } 6901da177e4SLinus Torvalds 6911da177e4SLinus Torvalds 6921da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 6931da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 6941da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 6951da177e4SLinus Torvalds 6965a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 6975a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 6985a09e398SHannes Reinecke const char * dev_id_str, 699c65b1445SDouglas Gilbert int dev_id_str_len) 7001da177e4SLinus Torvalds { 701c65b1445SDouglas Gilbert int num, port_a; 702c65b1445SDouglas Gilbert char b[32]; 7031da177e4SLinus Torvalds 704c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 7051da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 7061da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 7071da177e4SLinus Torvalds arr[1] = 0x1; 7081da177e4SLinus Torvalds arr[2] = 0x0; 7091da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 7101da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 7111da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 7121da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 7131da177e4SLinus Torvalds arr[3] = num; 7141da177e4SLinus Torvalds num += 4; 715c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 716c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 717c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 718c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 719c65b1445SDouglas Gilbert arr[num++] = 0x0; 720c65b1445SDouglas Gilbert arr[num++] = 0x8; 721c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 722c65b1445SDouglas Gilbert arr[num++] = 0x33; 723c65b1445SDouglas Gilbert arr[num++] = 0x33; 724c65b1445SDouglas Gilbert arr[num++] = 0x30; 725c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 726c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 727c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 728c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 729c65b1445SDouglas Gilbert /* Target relative port number */ 730c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 731c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 732c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 733c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 734c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 735c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 736c65b1445SDouglas Gilbert arr[num++] = 0x0; 737c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 738c65b1445SDouglas Gilbert } 739c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 740c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 741c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 742c65b1445SDouglas Gilbert arr[num++] = 0x0; 743c65b1445SDouglas Gilbert arr[num++] = 0x8; 744c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 745c65b1445SDouglas Gilbert arr[num++] = 0x22; 746c65b1445SDouglas Gilbert arr[num++] = 0x22; 747c65b1445SDouglas Gilbert arr[num++] = 0x20; 748c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 749c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 750c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 751c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 7525a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 7535a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 7545a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 7555a09e398SHannes Reinecke arr[num++] = 0x0; 7565a09e398SHannes Reinecke arr[num++] = 0x4; 7575a09e398SHannes Reinecke arr[num++] = 0; 7585a09e398SHannes Reinecke arr[num++] = 0; 7595a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 7605a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 761c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 762c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 763c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 764c65b1445SDouglas Gilbert arr[num++] = 0x0; 765c65b1445SDouglas Gilbert arr[num++] = 0x8; 766c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 767c65b1445SDouglas Gilbert arr[num++] = 0x22; 768c65b1445SDouglas Gilbert arr[num++] = 0x22; 769c65b1445SDouglas Gilbert arr[num++] = 0x20; 770c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 771c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 772c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 773c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 774c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 775c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 776c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 777c65b1445SDouglas Gilbert arr[num++] = 0x0; 778c65b1445SDouglas Gilbert arr[num++] = 24; 779c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 780c65b1445SDouglas Gilbert num += 12; 781c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 782c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 783c65b1445SDouglas Gilbert num += 8; 784c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 785c65b1445SDouglas Gilbert num += 4; 786c65b1445SDouglas Gilbert return num; 787c65b1445SDouglas Gilbert } 788c65b1445SDouglas Gilbert 789c65b1445SDouglas Gilbert 790c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 791c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 792c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 793c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 794c65b1445SDouglas Gilbert }; 795c65b1445SDouglas Gilbert 796c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 797c65b1445SDouglas Gilbert { 798c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 799c65b1445SDouglas Gilbert return sizeof(vpd84_data); 800c65b1445SDouglas Gilbert } 801c65b1445SDouglas Gilbert 802c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 803c65b1445SDouglas Gilbert { 804c65b1445SDouglas Gilbert int num = 0; 805c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 806c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 807c65b1445SDouglas Gilbert int plen, olen; 808c65b1445SDouglas Gilbert 809c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 810c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 811c65b1445SDouglas Gilbert arr[num++] = 0x0; 812c65b1445SDouglas Gilbert olen = strlen(na1); 813c65b1445SDouglas Gilbert plen = olen + 1; 814c65b1445SDouglas Gilbert if (plen % 4) 815c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 816c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 817c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 818c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 819c65b1445SDouglas Gilbert num += plen; 820c65b1445SDouglas Gilbert 821c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 822c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 823c65b1445SDouglas Gilbert arr[num++] = 0x0; 824c65b1445SDouglas Gilbert olen = strlen(na2); 825c65b1445SDouglas Gilbert plen = olen + 1; 826c65b1445SDouglas Gilbert if (plen % 4) 827c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 828c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 829c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 830c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 831c65b1445SDouglas Gilbert num += plen; 832c65b1445SDouglas Gilbert 833c65b1445SDouglas Gilbert return num; 834c65b1445SDouglas Gilbert } 835c65b1445SDouglas Gilbert 836c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 837c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 838c65b1445SDouglas Gilbert { 839c65b1445SDouglas Gilbert int num = 0; 840c65b1445SDouglas Gilbert int port_a, port_b; 841c65b1445SDouglas Gilbert 842c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 843c65b1445SDouglas Gilbert port_b = port_a + 1; 844c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 845c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 846c65b1445SDouglas Gilbert arr[num++] = 0x0; 847c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 848c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 849c65b1445SDouglas Gilbert num += 6; 850c65b1445SDouglas Gilbert arr[num++] = 0x0; 851c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 852c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 853c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 854c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 855c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 856c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 857c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 858c65b1445SDouglas Gilbert arr[num++] = 0x22; 859c65b1445SDouglas Gilbert arr[num++] = 0x22; 860c65b1445SDouglas Gilbert arr[num++] = 0x20; 861c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 862c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 863c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 864c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 865c65b1445SDouglas Gilbert 866c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 867c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 868c65b1445SDouglas Gilbert arr[num++] = 0x0; 869c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 870c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 871c65b1445SDouglas Gilbert num += 6; 872c65b1445SDouglas Gilbert arr[num++] = 0x0; 873c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 874c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 875c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 876c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 877c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 878c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 879c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 880c65b1445SDouglas Gilbert arr[num++] = 0x22; 881c65b1445SDouglas Gilbert arr[num++] = 0x22; 882c65b1445SDouglas Gilbert arr[num++] = 0x20; 883c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 884c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 885c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 886c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 887c65b1445SDouglas Gilbert 888c65b1445SDouglas Gilbert return num; 889c65b1445SDouglas Gilbert } 890c65b1445SDouglas Gilbert 891c65b1445SDouglas Gilbert 892c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 893c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 894c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 895c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 896c65b1445SDouglas Gilbert '1','2','3','4', 897c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 898c65b1445SDouglas Gilbert 0xec,0,0,0, 899c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 900c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 901c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 902c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 903c65b1445SDouglas Gilbert 0x53,0x41, 904c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 905c65b1445SDouglas Gilbert 0x20,0x20, 906c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 907c65b1445SDouglas Gilbert 0x10,0x80, 908c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 909c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 910c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 911c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 912c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 913c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 914c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 915c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 916c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 917c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 918c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 919c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 920c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 921c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 922c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 923c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 924c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 925c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 926c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 927c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 928c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 929c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 930c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 931c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 932c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 933c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 934c65b1445SDouglas Gilbert }; 935c65b1445SDouglas Gilbert 936c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 937c65b1445SDouglas Gilbert { 938c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 939c65b1445SDouglas Gilbert return sizeof(vpd89_data); 940c65b1445SDouglas Gilbert } 941c65b1445SDouglas Gilbert 942c65b1445SDouglas Gilbert 943c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 944c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 945c65b1445SDouglas Gilbert 0,0,0x4,0, 946c65b1445SDouglas Gilbert 0,0,0,64, 947c65b1445SDouglas Gilbert }; 948c65b1445SDouglas Gilbert 949c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 950c65b1445SDouglas Gilbert { 951c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 952c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 953c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 954c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 955c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 956c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 957c65b1445SDouglas Gilbert } 958c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 9591da177e4SLinus Torvalds } 9601da177e4SLinus Torvalds 9611da177e4SLinus Torvalds 9621da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 963c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 9641da177e4SLinus Torvalds 9651da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 9661da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9671da177e4SLinus Torvalds { 9681da177e4SLinus Torvalds unsigned char pq_pdt; 9695a09e398SHannes Reinecke unsigned char * arr; 9701da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 9715a09e398SHannes Reinecke int alloc_len, n, ret; 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 9746f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 9756f3cbf55SDouglas Gilbert if (! arr) 9766f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 977c65b1445SDouglas Gilbert if (devip->wlun) 978c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 979c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 980c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 981c65b1445SDouglas Gilbert else 9821da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 9831da177e4SLinus Torvalds arr[0] = pq_pdt; 9841da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 9851da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 9861da177e4SLinus Torvalds 0); 9875a09e398SHannes Reinecke kfree(arr); 9881da177e4SLinus Torvalds return check_condition_result; 9891da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 9905a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 991c65b1445SDouglas Gilbert char lu_id_str[6]; 992c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 9931da177e4SLinus Torvalds 9945a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 9955a09e398SHannes Reinecke (devip->channel & 0x7f); 99623183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 99723183910SDouglas Gilbert host_no = 0; 998c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 999c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1000c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1001c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1002c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 10031da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1004c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1005c65b1445SDouglas Gilbert n = 4; 1006c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1007c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1008c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1009c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1010c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1011c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1012c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1013c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1014c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1015c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 1016c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 10171da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1018c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 10191da177e4SLinus Torvalds arr[3] = len; 1020c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 10211da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1022c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 10235a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 10245a09e398SHannes Reinecke target_dev_id, lu_id_num, 10255a09e398SHannes Reinecke lu_id_str, len); 1026c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1027c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1028c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 1029c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1030c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1031c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 1032c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1033c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1034c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1035c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1036c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1037c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1038c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1039c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1040c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1041c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1042c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1043c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1044c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1045c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1046c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 1047c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 1048c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1049c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 1050c65b1445SDouglas Gilbert arr[2] = (n >> 8); 1051c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 1052c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 1053c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1054c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 10551da177e4SLinus Torvalds } else { 10561da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 10571da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 10581da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 10595a09e398SHannes Reinecke kfree(arr); 10601da177e4SLinus Torvalds return check_condition_result; 10611da177e4SLinus Torvalds } 1062c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 10635a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1064c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 10655a09e398SHannes Reinecke kfree(arr); 10665a09e398SHannes Reinecke return ret; 10671da177e4SLinus Torvalds } 10681da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 10691da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 10701da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 10711da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 10721da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 10735a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 10745a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1075c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 10761da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1077c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 10781da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 10791da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 10801da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 10811da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1082c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 1083c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 1084c65b1445SDouglas Gilbert n = 62; 10851da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 1086c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 10871da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 1088c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 10891da177e4SLinus Torvalds } 1090c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 10915a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 10921da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 10935a09e398SHannes Reinecke kfree(arr); 10945a09e398SHannes Reinecke return ret; 10951da177e4SLinus Torvalds } 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 10981da177e4SLinus Torvalds struct sdebug_dev_info * devip) 10991da177e4SLinus Torvalds { 11001da177e4SLinus Torvalds unsigned char * sbuff; 11011da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 11021da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 1103c65b1445SDouglas Gilbert int want_dsense; 11041da177e4SLinus Torvalds int len = 18; 11051da177e4SLinus Torvalds 1106c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 11071da177e4SLinus Torvalds if (devip->reset == 1) 1108c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 1109c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 11101da177e4SLinus Torvalds sbuff = devip->sense_buff; 1111c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1112c65b1445SDouglas Gilbert if (want_dsense) { 1113c65b1445SDouglas Gilbert arr[0] = 0x72; 1114c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1115c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1116c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1117c65b1445SDouglas Gilbert } else { 1118c65b1445SDouglas Gilbert arr[0] = 0x70; 1119c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1120c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1121c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1122c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1123c65b1445SDouglas Gilbert } 1124c65b1445SDouglas Gilbert } else { 1125c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 11261da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 11271da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 1128c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 11291da177e4SLinus Torvalds arr[0] = 0x72; 11301da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 11311da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 11321da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 11331da177e4SLinus Torvalds len = 8; 1134c65b1445SDouglas Gilbert } 1135c65b1445SDouglas Gilbert } 1136c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 11371da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 11381da177e4SLinus Torvalds } 11391da177e4SLinus Torvalds 1140c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1141c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1142c65b1445SDouglas Gilbert { 1143c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1144c65b1445SDouglas Gilbert int power_cond, errsts, start; 1145c65b1445SDouglas Gilbert 1146c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1147c65b1445SDouglas Gilbert return errsts; 1148c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1149c65b1445SDouglas Gilbert if (power_cond) { 1150c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1151c65b1445SDouglas Gilbert 0); 1152c65b1445SDouglas Gilbert return check_condition_result; 1153c65b1445SDouglas Gilbert } 1154c65b1445SDouglas Gilbert start = cmd[4] & 1; 1155c65b1445SDouglas Gilbert if (start == devip->stopped) 1156c65b1445SDouglas Gilbert devip->stopped = !start; 1157c65b1445SDouglas Gilbert return 0; 1158c65b1445SDouglas Gilbert } 1159c65b1445SDouglas Gilbert 11601da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 11611da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 11621da177e4SLinus Torvalds struct sdebug_dev_info * devip) 11631da177e4SLinus Torvalds { 11641da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1165c65b1445SDouglas Gilbert unsigned int capac; 11661da177e4SLinus Torvalds int errsts; 11671da177e4SLinus Torvalds 1168c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 11691da177e4SLinus Torvalds return errsts; 1170c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 1171c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 1172c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 1173c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 1174c65b1445SDouglas Gilbert } else 1175c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 11761da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1177c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1178c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 11791da177e4SLinus Torvalds arr[0] = (capac >> 24); 11801da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 11811da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 11821da177e4SLinus Torvalds arr[3] = capac & 0xff; 1183c65b1445SDouglas Gilbert } else { 1184c65b1445SDouglas Gilbert arr[0] = 0xff; 1185c65b1445SDouglas Gilbert arr[1] = 0xff; 1186c65b1445SDouglas Gilbert arr[2] = 0xff; 1187c65b1445SDouglas Gilbert arr[3] = 0xff; 1188c65b1445SDouglas Gilbert } 11891da177e4SLinus Torvalds arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 11901da177e4SLinus Torvalds arr[7] = SECT_SIZE_PER(target) & 0xff; 11911da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds 1194c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1195c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1196c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1197c65b1445SDouglas Gilbert { 1198c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1199c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1200c65b1445SDouglas Gilbert unsigned long long capac; 1201c65b1445SDouglas Gilbert int errsts, k, alloc_len; 1202c65b1445SDouglas Gilbert 1203c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1204c65b1445SDouglas Gilbert return errsts; 1205c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1206c65b1445SDouglas Gilbert + cmd[13]); 1207c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 1208c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 1209c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 1210c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 1211c65b1445SDouglas Gilbert } else 1212c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 1213c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1214c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1215c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1216c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1217c65b1445SDouglas Gilbert arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; 1218c65b1445SDouglas Gilbert arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; 1219c65b1445SDouglas Gilbert arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; 1220c65b1445SDouglas Gilbert arr[11] = SECT_SIZE_PER(target) & 0xff; 1221c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1222c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1223c65b1445SDouglas Gilbert } 1224c65b1445SDouglas Gilbert 12255a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 12265a09e398SHannes Reinecke 12275a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 12285a09e398SHannes Reinecke struct sdebug_dev_info * devip) 12295a09e398SHannes Reinecke { 12305a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 12315a09e398SHannes Reinecke unsigned char * arr; 12325a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 12335a09e398SHannes Reinecke int n, ret, alen, rlen; 12345a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 12355a09e398SHannes Reinecke 12365a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 12375a09e398SHannes Reinecke + cmd[9]); 12385a09e398SHannes Reinecke 12396f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 12406f3cbf55SDouglas Gilbert if (! arr) 12416f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 12425a09e398SHannes Reinecke /* 12435a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 12445a09e398SHannes Reinecke * real and a fake port with no device connected. 12455a09e398SHannes Reinecke * So we create two port groups with one port each 12465a09e398SHannes Reinecke * and set the group with port B to unavailable. 12475a09e398SHannes Reinecke */ 12485a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 12495a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 12505a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 12515a09e398SHannes Reinecke (devip->channel & 0x7f); 12525a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 12535a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 12545a09e398SHannes Reinecke 12555a09e398SHannes Reinecke /* 12565a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 12575a09e398SHannes Reinecke */ 12585a09e398SHannes Reinecke n = 4; 12595a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 12605a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 12615a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 12625a09e398SHannes Reinecke } else { 12635a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 12645a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 12655a09e398SHannes Reinecke } 12665a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 12675a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 12685a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12695a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 12705a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 12715a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 12725a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12735a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12745a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 12755a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 12765a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 12775a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 12785a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 12795a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 12805a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12815a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 12825a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 12835a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 12845a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12855a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 12865a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 12875a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 12885a09e398SHannes Reinecke 12895a09e398SHannes Reinecke rlen = n - 4; 12905a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 12915a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 12925a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 12935a09e398SHannes Reinecke arr[3] = rlen & 0xff; 12945a09e398SHannes Reinecke 12955a09e398SHannes Reinecke /* 12965a09e398SHannes Reinecke * Return the smallest value of either 12975a09e398SHannes Reinecke * - The allocated length 12985a09e398SHannes Reinecke * - The constructed command length 12995a09e398SHannes Reinecke * - The maximum array size 13005a09e398SHannes Reinecke */ 13015a09e398SHannes Reinecke rlen = min(alen,n); 13025a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 13035a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 13045a09e398SHannes Reinecke kfree(arr); 13055a09e398SHannes Reinecke return ret; 13065a09e398SHannes Reinecke } 13075a09e398SHannes Reinecke 13081da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 13111da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 13121da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 13131da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 13161da177e4SLinus Torvalds if (1 == pcontrol) 13171da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 13181da177e4SLinus Torvalds return sizeof(err_recov_pg); 13191da177e4SLinus Torvalds } 13201da177e4SLinus Torvalds 13211da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 13221da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 13231da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 13241da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 13251da177e4SLinus Torvalds 13261da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 13271da177e4SLinus Torvalds if (1 == pcontrol) 13281da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 13291da177e4SLinus Torvalds return sizeof(disconnect_pg); 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 13331da177e4SLinus Torvalds { /* Format device page for mode_sense */ 13341da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 13351da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 13361da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 13391da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 13401da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 13411da177e4SLinus Torvalds p[12] = (SECT_SIZE >> 8) & 0xff; 13421da177e4SLinus Torvalds p[13] = SECT_SIZE & 0xff; 13431da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 13441da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 13451da177e4SLinus Torvalds if (1 == pcontrol) 13461da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 13471da177e4SLinus Torvalds return sizeof(format_pg); 13481da177e4SLinus Torvalds } 13491da177e4SLinus Torvalds 13501da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 13511da177e4SLinus Torvalds { /* Caching page for mode_sense */ 13521da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 13531da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 13541da177e4SLinus Torvalds 13551da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 13561da177e4SLinus Torvalds if (1 == pcontrol) 13571da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 13581da177e4SLinus Torvalds return sizeof(caching_pg); 13591da177e4SLinus Torvalds } 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 13621da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1363c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1364c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1365c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 13661da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds if (scsi_debug_dsense) 13691da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1370c65b1445SDouglas Gilbert else 1371c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 13721da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 13731da177e4SLinus Torvalds if (1 == pcontrol) 1374c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1375c65b1445SDouglas Gilbert else if (2 == pcontrol) 1376c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 13771da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 13781da177e4SLinus Torvalds } 13791da177e4SLinus Torvalds 1380c65b1445SDouglas Gilbert 13811da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 13821da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1383c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 13841da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1385c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1386c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1387c65b1445SDouglas Gilbert 13881da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 13891da177e4SLinus Torvalds if (1 == pcontrol) 1390c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1391c65b1445SDouglas Gilbert else if (2 == pcontrol) 1392c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 13931da177e4SLinus Torvalds return sizeof(iec_m_pg); 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 1396c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1397c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1398c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1399c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1400c65b1445SDouglas Gilbert 1401c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1402c65b1445SDouglas Gilbert if (1 == pcontrol) 1403c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1404c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1405c65b1445SDouglas Gilbert } 1406c65b1445SDouglas Gilbert 1407c65b1445SDouglas Gilbert 1408c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1409c65b1445SDouglas Gilbert int target_dev_id) 1410c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1411c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1412c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1413c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1414c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1415c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1416c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1417c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1418c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1419c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1420c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1421c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1422c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1423c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1424c65b1445SDouglas Gilbert }; 1425c65b1445SDouglas Gilbert int port_a, port_b; 1426c65b1445SDouglas Gilbert 1427c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1428c65b1445SDouglas Gilbert port_b = port_a + 1; 1429c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1430c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1431c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1432c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1433c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1434c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1435c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1436c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1437c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1438c65b1445SDouglas Gilbert if (1 == pcontrol) 1439c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1440c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1441c65b1445SDouglas Gilbert } 1442c65b1445SDouglas Gilbert 1443c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1444c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1445c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1446c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1447c65b1445SDouglas Gilbert }; 1448c65b1445SDouglas Gilbert 1449c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1450c65b1445SDouglas Gilbert if (1 == pcontrol) 1451c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1452c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1453c65b1445SDouglas Gilbert } 1454c65b1445SDouglas Gilbert 14551da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 14561da177e4SLinus Torvalds 14571da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 14581da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14591da177e4SLinus Torvalds { 146023183910SDouglas Gilbert unsigned char dbd, llbaa; 146123183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 14621da177e4SLinus Torvalds unsigned char dev_spec; 146323183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 14641da177e4SLinus Torvalds unsigned char * ap; 14651da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 14661da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 14671da177e4SLinus Torvalds 1468c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 14691da177e4SLinus Torvalds return errsts; 147023183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 14711da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 14721da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 14731da177e4SLinus Torvalds subpcode = cmd[3]; 14741da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 147523183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 147623183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 147723183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 147823183910SDouglas Gilbert else 147923183910SDouglas Gilbert bd_len = 0; 14801da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 14811da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 14821da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 14831da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 14841da177e4SLinus Torvalds 0); 14851da177e4SLinus Torvalds return check_condition_result; 14861da177e4SLinus Torvalds } 1487c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1488c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 148923183910SDouglas Gilbert /* set DPOFUA bit for disks */ 149023183910SDouglas Gilbert if (0 == scsi_debug_ptype) 149123183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 149223183910SDouglas Gilbert else 149323183910SDouglas Gilbert dev_spec = 0x0; 14941da177e4SLinus Torvalds if (msense_6) { 14951da177e4SLinus Torvalds arr[2] = dev_spec; 149623183910SDouglas Gilbert arr[3] = bd_len; 14971da177e4SLinus Torvalds offset = 4; 14981da177e4SLinus Torvalds } else { 14991da177e4SLinus Torvalds arr[3] = dev_spec; 150023183910SDouglas Gilbert if (16 == bd_len) 150123183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 150223183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 15031da177e4SLinus Torvalds offset = 8; 15041da177e4SLinus Torvalds } 15051da177e4SLinus Torvalds ap = arr + offset; 150623183910SDouglas Gilbert if ((bd_len > 0) && (0 == sdebug_capacity)) { 150723183910SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 150823183910SDouglas Gilbert sdebug_capacity = 2048 * 1024; 150923183910SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 151023183910SDouglas Gilbert } else 151123183910SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 151223183910SDouglas Gilbert } 151323183910SDouglas Gilbert if (8 == bd_len) { 151423183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 151523183910SDouglas Gilbert ap[0] = 0xff; 151623183910SDouglas Gilbert ap[1] = 0xff; 151723183910SDouglas Gilbert ap[2] = 0xff; 151823183910SDouglas Gilbert ap[3] = 0xff; 151923183910SDouglas Gilbert } else { 152023183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 152123183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 152223183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 152323183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 152423183910SDouglas Gilbert } 152523183910SDouglas Gilbert ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 152623183910SDouglas Gilbert ap[7] = SECT_SIZE_PER(target) & 0xff; 152723183910SDouglas Gilbert offset += bd_len; 152823183910SDouglas Gilbert ap = arr + offset; 152923183910SDouglas Gilbert } else if (16 == bd_len) { 153023183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 153123183910SDouglas Gilbert 153223183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 153323183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 153423183910SDouglas Gilbert ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; 153523183910SDouglas Gilbert ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; 153623183910SDouglas Gilbert ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; 153723183910SDouglas Gilbert ap[15] = SECT_SIZE_PER(target) & 0xff; 153823183910SDouglas Gilbert offset += bd_len; 153923183910SDouglas Gilbert ap = arr + offset; 154023183910SDouglas Gilbert } 15411da177e4SLinus Torvalds 1542c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1543c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 15441da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 15451da177e4SLinus Torvalds 0); 15461da177e4SLinus Torvalds return check_condition_result; 15471da177e4SLinus Torvalds } 15481da177e4SLinus Torvalds switch (pcode) { 15491da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 15501da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 15511da177e4SLinus Torvalds offset += len; 15521da177e4SLinus Torvalds break; 15531da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 15541da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 15551da177e4SLinus Torvalds offset += len; 15561da177e4SLinus Torvalds break; 15571da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 15581da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 15591da177e4SLinus Torvalds offset += len; 15601da177e4SLinus Torvalds break; 15611da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 15621da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 15631da177e4SLinus Torvalds offset += len; 15641da177e4SLinus Torvalds break; 15651da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 15661da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 15671da177e4SLinus Torvalds offset += len; 15681da177e4SLinus Torvalds break; 1569c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1570c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1571c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1572c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1573c65b1445SDouglas Gilbert return check_condition_result; 1574c65b1445SDouglas Gilbert } 1575c65b1445SDouglas Gilbert len = 0; 1576c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1577c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1578c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1579c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1580c65b1445SDouglas Gilbert target_dev_id); 1581c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1582c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1583c65b1445SDouglas Gilbert offset += len; 1584c65b1445SDouglas Gilbert break; 15851da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 15861da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 15871da177e4SLinus Torvalds offset += len; 15881da177e4SLinus Torvalds break; 15891da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1590c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 15911da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 15921da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 15931da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 15941da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 15951da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1596c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1597c65b1445SDouglas Gilbert if (0xff == subpcode) { 1598c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1599c65b1445SDouglas Gilbert target, target_dev_id); 1600c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1601c65b1445SDouglas Gilbert } 16021da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1603c65b1445SDouglas Gilbert } else { 1604c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1605c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1606c65b1445SDouglas Gilbert return check_condition_result; 1607c65b1445SDouglas Gilbert } 16081da177e4SLinus Torvalds offset += len; 16091da177e4SLinus Torvalds break; 16101da177e4SLinus Torvalds default: 16111da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 16121da177e4SLinus Torvalds 0); 16131da177e4SLinus Torvalds return check_condition_result; 16141da177e4SLinus Torvalds } 16151da177e4SLinus Torvalds if (msense_6) 16161da177e4SLinus Torvalds arr[0] = offset - 1; 16171da177e4SLinus Torvalds else { 16181da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 16191da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 16201da177e4SLinus Torvalds } 16211da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 16221da177e4SLinus Torvalds } 16231da177e4SLinus Torvalds 1624c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1625c65b1445SDouglas Gilbert 1626c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1627c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1628c65b1445SDouglas Gilbert { 1629c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1630c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1631c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1632c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1633c65b1445SDouglas Gilbert 1634c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1635c65b1445SDouglas Gilbert return errsts; 1636c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1637c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1638c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1639c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1640c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1641c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1642c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1643c65b1445SDouglas Gilbert return check_condition_result; 1644c65b1445SDouglas Gilbert } 1645c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1646c65b1445SDouglas Gilbert if (-1 == res) 1647c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1648c65b1445SDouglas Gilbert else if ((res < param_len) && 1649c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1650c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1651c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1652c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1653c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 165423183910SDouglas Gilbert if (md_len > 2) { 1655c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1656c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1657c65b1445SDouglas Gilbert return check_condition_result; 1658c65b1445SDouglas Gilbert } 1659c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1660c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1661c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1662c65b1445SDouglas Gilbert if (ps) { 1663c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1664c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1665c65b1445SDouglas Gilbert return check_condition_result; 1666c65b1445SDouglas Gilbert } 1667c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1668c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1669c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1670c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1671c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1672c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1673c65b1445SDouglas Gilbert return check_condition_result; 1674c65b1445SDouglas Gilbert } 1675c65b1445SDouglas Gilbert switch (mpage) { 1676c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1677c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1678c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1679c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1680c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1681c65b1445SDouglas Gilbert return 0; 1682c65b1445SDouglas Gilbert } 1683c65b1445SDouglas Gilbert break; 1684c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1685c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1686c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1687c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1688c65b1445SDouglas Gilbert return 0; 1689c65b1445SDouglas Gilbert } 1690c65b1445SDouglas Gilbert break; 1691c65b1445SDouglas Gilbert default: 1692c65b1445SDouglas Gilbert break; 1693c65b1445SDouglas Gilbert } 1694c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1695c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1696c65b1445SDouglas Gilbert return check_condition_result; 1697c65b1445SDouglas Gilbert } 1698c65b1445SDouglas Gilbert 1699c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1700c65b1445SDouglas Gilbert { 1701c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1702c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1703c65b1445SDouglas Gilbert }; 1704c65b1445SDouglas Gilbert 1705c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1706c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1707c65b1445SDouglas Gilbert } 1708c65b1445SDouglas Gilbert 1709c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1710c65b1445SDouglas Gilbert { 1711c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1712c65b1445SDouglas Gilbert }; 1713c65b1445SDouglas Gilbert 1714c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1715c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1716c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1717c65b1445SDouglas Gilbert arr[5] = 0xff; 1718c65b1445SDouglas Gilbert } 1719c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1720c65b1445SDouglas Gilbert } 1721c65b1445SDouglas Gilbert 1722c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1723c65b1445SDouglas Gilbert 1724c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1725c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1726c65b1445SDouglas Gilbert { 172723183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1728c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1729c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1730c65b1445SDouglas Gilbert 1731c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1732c65b1445SDouglas Gilbert return errsts; 1733c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1734c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1735c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1736c65b1445SDouglas Gilbert if (ppc || sp) { 1737c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1738c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1739c65b1445SDouglas Gilbert return check_condition_result; 1740c65b1445SDouglas Gilbert } 1741c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1742c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 174323183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1744c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1745c65b1445SDouglas Gilbert arr[0] = pcode; 174623183910SDouglas Gilbert if (0 == subpcode) { 1747c65b1445SDouglas Gilbert switch (pcode) { 1748c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1749c65b1445SDouglas Gilbert n = 4; 1750c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1751c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1752c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1753c65b1445SDouglas Gilbert arr[3] = n - 4; 1754c65b1445SDouglas Gilbert break; 1755c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1756c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1757c65b1445SDouglas Gilbert break; 1758c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1759c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1760c65b1445SDouglas Gilbert break; 1761c65b1445SDouglas Gilbert default: 1762c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1763c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1764c65b1445SDouglas Gilbert return check_condition_result; 1765c65b1445SDouglas Gilbert } 176623183910SDouglas Gilbert } else if (0xff == subpcode) { 176723183910SDouglas Gilbert arr[0] |= 0x40; 176823183910SDouglas Gilbert arr[1] = subpcode; 176923183910SDouglas Gilbert switch (pcode) { 177023183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 177123183910SDouglas Gilbert n = 4; 177223183910SDouglas Gilbert arr[n++] = 0x0; 177323183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 177423183910SDouglas Gilbert arr[n++] = 0x0; 177523183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 177623183910SDouglas Gilbert arr[n++] = 0xd; 177723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 177823183910SDouglas Gilbert arr[n++] = 0x2f; 177923183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 178023183910SDouglas Gilbert arr[3] = n - 4; 178123183910SDouglas Gilbert break; 178223183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 178323183910SDouglas Gilbert n = 4; 178423183910SDouglas Gilbert arr[n++] = 0xd; 178523183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 178623183910SDouglas Gilbert arr[3] = n - 4; 178723183910SDouglas Gilbert break; 178823183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 178923183910SDouglas Gilbert n = 4; 179023183910SDouglas Gilbert arr[n++] = 0x2f; 179123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 179223183910SDouglas Gilbert arr[3] = n - 4; 179323183910SDouglas Gilbert break; 179423183910SDouglas Gilbert default: 179523183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 179623183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 179723183910SDouglas Gilbert return check_condition_result; 179823183910SDouglas Gilbert } 179923183910SDouglas Gilbert } else { 180023183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 180123183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 180223183910SDouglas Gilbert return check_condition_result; 180323183910SDouglas Gilbert } 1804c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1805c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1806c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1807c65b1445SDouglas Gilbert } 1808c65b1445SDouglas Gilbert 1809c65b1445SDouglas Gilbert static int resp_read(struct scsi_cmnd * SCpnt, unsigned long long lba, 1810c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip) 18111da177e4SLinus Torvalds { 18121da177e4SLinus Torvalds unsigned long iflags; 1813c65b1445SDouglas Gilbert unsigned int block, from_bottom; 1814c65b1445SDouglas Gilbert unsigned long long u; 18151da177e4SLinus Torvalds int ret; 18161da177e4SLinus Torvalds 1817c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 18181da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 18191da177e4SLinus Torvalds 0); 18201da177e4SLinus Torvalds return check_condition_result; 18211da177e4SLinus Torvalds } 1822c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1823c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 1824c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1825c65b1445SDouglas Gilbert 0); 1826c65b1445SDouglas Gilbert return check_condition_result; 1827c65b1445SDouglas Gilbert } 18281da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 1829c65b1445SDouglas Gilbert (lba <= OPT_MEDIUM_ERR_ADDR) && 1830c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1831c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 18321da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 18331da177e4SLinus Torvalds 0); 1834c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1835c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1836c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 1837c65b1445SDouglas Gilbert ret = OPT_MEDIUM_ERR_ADDR; 1838c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1839c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1840c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1841c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1842c65b1445SDouglas Gilbert } 18431da177e4SLinus Torvalds return check_condition_result; 18441da177e4SLinus Torvalds } 18451da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 1846c65b1445SDouglas Gilbert if ((lba + num) <= sdebug_store_sectors) 1847c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, 1848c65b1445SDouglas Gilbert fake_storep + (lba * SECT_SIZE), 18491da177e4SLinus Torvalds num * SECT_SIZE); 1850c65b1445SDouglas Gilbert else { 1851c65b1445SDouglas Gilbert /* modulo when one arg is 64 bits needs do_div() */ 1852c65b1445SDouglas Gilbert u = lba; 1853c65b1445SDouglas Gilbert block = do_div(u, sdebug_store_sectors); 1854c65b1445SDouglas Gilbert from_bottom = 0; 1855c65b1445SDouglas Gilbert if ((block + num) > sdebug_store_sectors) 1856c65b1445SDouglas Gilbert from_bottom = (block + num) - sdebug_store_sectors; 1857c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, 1858c65b1445SDouglas Gilbert fake_storep + (block * SECT_SIZE), 1859c65b1445SDouglas Gilbert (num - from_bottom) * SECT_SIZE); 1860c65b1445SDouglas Gilbert if ((0 == ret) && (from_bottom > 0)) 1861c65b1445SDouglas Gilbert ret = fill_from_dev_buffer(SCpnt, fake_storep, 1862c65b1445SDouglas Gilbert from_bottom * SECT_SIZE); 1863c65b1445SDouglas Gilbert } 18641da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 18651da177e4SLinus Torvalds return ret; 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 1868c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd * SCpnt, unsigned long long lba, 1869c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info * devip) 18701da177e4SLinus Torvalds { 18711da177e4SLinus Torvalds unsigned long iflags; 1872c65b1445SDouglas Gilbert unsigned int block, to_bottom; 1873c65b1445SDouglas Gilbert unsigned long long u; 18741da177e4SLinus Torvalds int res; 18751da177e4SLinus Torvalds 1876c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 18771da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 18781da177e4SLinus Torvalds 0); 18791da177e4SLinus Torvalds return check_condition_result; 18801da177e4SLinus Torvalds } 1881c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1882c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 1883c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1884c65b1445SDouglas Gilbert 0); 1885c65b1445SDouglas Gilbert return check_condition_result; 1886c65b1445SDouglas Gilbert } 18871da177e4SLinus Torvalds 18881da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 1889c65b1445SDouglas Gilbert if ((lba + num) <= sdebug_store_sectors) 1890c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, 1891c65b1445SDouglas Gilbert fake_storep + (lba * SECT_SIZE), 18921da177e4SLinus Torvalds num * SECT_SIZE); 1893c65b1445SDouglas Gilbert else { 1894c65b1445SDouglas Gilbert /* modulo when one arg is 64 bits needs do_div() */ 1895c65b1445SDouglas Gilbert u = lba; 1896c65b1445SDouglas Gilbert block = do_div(u, sdebug_store_sectors); 1897c65b1445SDouglas Gilbert to_bottom = 0; 1898c65b1445SDouglas Gilbert if ((block + num) > sdebug_store_sectors) 1899c65b1445SDouglas Gilbert to_bottom = (block + num) - sdebug_store_sectors; 1900c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, 1901c65b1445SDouglas Gilbert fake_storep + (block * SECT_SIZE), 1902c65b1445SDouglas Gilbert (num - to_bottom) * SECT_SIZE); 1903c65b1445SDouglas Gilbert if ((0 == res) && (to_bottom > 0)) 1904c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(SCpnt, fake_storep, 1905c65b1445SDouglas Gilbert to_bottom * SECT_SIZE); 1906c65b1445SDouglas Gilbert } 19071da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 19081da177e4SLinus Torvalds if (-1 == res) 19091da177e4SLinus Torvalds return (DID_ERROR << 16); 19101da177e4SLinus Torvalds else if ((res < (num * SECT_SIZE)) && 19111da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1912c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 19131da177e4SLinus Torvalds " IO sent=%d bytes\n", num * SECT_SIZE, res); 19141da177e4SLinus Torvalds return 0; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds 1917c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 19201da177e4SLinus Torvalds struct sdebug_dev_info * devip) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds unsigned int alloc_len; 1923c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 19241da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 19251da177e4SLinus Torvalds int select_report = (int)cmd[2]; 19261da177e4SLinus Torvalds struct scsi_lun *one_lun; 19271da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 1928c65b1445SDouglas Gilbert unsigned char * max_addr; 19291da177e4SLinus Torvalds 19301da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 1931c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 19321da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 19331da177e4SLinus Torvalds 0); 19341da177e4SLinus Torvalds return check_condition_result; 19351da177e4SLinus Torvalds } 19361da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 19371da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 19381da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 1939c65b1445SDouglas Gilbert if (1 == select_report) 1940c65b1445SDouglas Gilbert lun_cnt = 0; 1941c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 1942c65b1445SDouglas Gilbert --lun_cnt; 1943c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 1944c65b1445SDouglas Gilbert num = lun_cnt + wlun; 1945c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 1946c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 1947c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 1948c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 1949c65b1445SDouglas Gilbert if (n < num) { 1950c65b1445SDouglas Gilbert wlun = 0; 1951c65b1445SDouglas Gilbert lun_cnt = n; 1952c65b1445SDouglas Gilbert } 19531da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 1954c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 1955c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 1956c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 1957c65b1445SDouglas Gilbert i++, lun++) { 1958c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 19591da177e4SLinus Torvalds if (upper) 19601da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 19611da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 1962c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 19631da177e4SLinus Torvalds } 1964c65b1445SDouglas Gilbert if (wlun) { 1965c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 1966c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 1967c65b1445SDouglas Gilbert i++; 1968c65b1445SDouglas Gilbert } 1969c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 19701da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 19711da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds /* When timer goes off this function is called. */ 19751da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 19761da177e4SLinus Torvalds { 19771da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 19781da177e4SLinus Torvalds unsigned long iflags; 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds if (indx >= SCSI_DEBUG_CANQUEUE) { 19811da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 19821da177e4SLinus Torvalds "large\n"); 19831da177e4SLinus Torvalds return; 19841da177e4SLinus Torvalds } 19851da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 19861da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 19871da177e4SLinus Torvalds if (! sqcp->in_use) { 19881da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 19891da177e4SLinus Torvalds "interrupt\n"); 19901da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 19911da177e4SLinus Torvalds return; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds sqcp->in_use = 0; 19941da177e4SLinus Torvalds if (sqcp->done_funct) { 19951da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 19961da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 19971da177e4SLinus Torvalds } 19981da177e4SLinus Torvalds sqcp->done_funct = NULL; 19991da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20001da177e4SLinus Torvalds } 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds static int scsi_debug_slave_alloc(struct scsi_device * sdp) 20031da177e4SLinus Torvalds { 20041da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2005c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 2006c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 20071da177e4SLinus Torvalds return 0; 20081da177e4SLinus Torvalds } 20091da177e4SLinus Torvalds 20101da177e4SLinus Torvalds static int scsi_debug_slave_configure(struct scsi_device * sdp) 20111da177e4SLinus Torvalds { 20121da177e4SLinus Torvalds struct sdebug_dev_info * devip; 20131da177e4SLinus Torvalds 20141da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2015c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 2016c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 20171da177e4SLinus Torvalds if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 20181da177e4SLinus Torvalds sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 20191da177e4SLinus Torvalds devip = devInfoReg(sdp); 20206f3cbf55SDouglas Gilbert if (NULL == devip) 20216f3cbf55SDouglas Gilbert return 1; /* no resources, will be marked offline */ 20221da177e4SLinus Torvalds sdp->hostdata = devip; 20231da177e4SLinus Torvalds if (sdp->host->cmd_per_lun) 20241da177e4SLinus Torvalds scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 20251da177e4SLinus Torvalds sdp->host->cmd_per_lun); 2026c65b1445SDouglas Gilbert blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 20271da177e4SLinus Torvalds return 0; 20281da177e4SLinus Torvalds } 20291da177e4SLinus Torvalds 20301da177e4SLinus Torvalds static void scsi_debug_slave_destroy(struct scsi_device * sdp) 20311da177e4SLinus Torvalds { 20321da177e4SLinus Torvalds struct sdebug_dev_info * devip = 20331da177e4SLinus Torvalds (struct sdebug_dev_info *)sdp->hostdata; 20341da177e4SLinus Torvalds 20351da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2036c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 2037c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 20381da177e4SLinus Torvalds if (devip) { 20391da177e4SLinus Torvalds /* make this slot avaliable for re-use */ 20401da177e4SLinus Torvalds devip->used = 0; 20411da177e4SLinus Torvalds sdp->hostdata = NULL; 20421da177e4SLinus Torvalds } 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds 20451da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 20461da177e4SLinus Torvalds { 20471da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 20481da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 20491da177e4SLinus Torvalds struct sdebug_dev_info * devip = 20501da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 20511da177e4SLinus Torvalds 20521da177e4SLinus Torvalds if (devip) 20531da177e4SLinus Torvalds return devip; 20541da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata; 20551da177e4SLinus Torvalds if(! sdbg_host) { 20561da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 20571da177e4SLinus Torvalds return NULL; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 20601da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 20611da177e4SLinus Torvalds (devip->target == sdev->id) && 20621da177e4SLinus Torvalds (devip->lun == sdev->lun)) 20631da177e4SLinus Torvalds return devip; 20641da177e4SLinus Torvalds else { 20651da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 20661da177e4SLinus Torvalds open_devip = devip; 20671da177e4SLinus Torvalds } 20681da177e4SLinus Torvalds } 20691da177e4SLinus Torvalds if (NULL == open_devip) { /* try and make a new one */ 20706f3cbf55SDouglas Gilbert open_devip = kzalloc(sizeof(*open_devip),GFP_ATOMIC); 20711da177e4SLinus Torvalds if (NULL == open_devip) { 20721da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 20731da177e4SLinus Torvalds __FUNCTION__, __LINE__); 20741da177e4SLinus Torvalds return NULL; 20751da177e4SLinus Torvalds } 20761da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 20771da177e4SLinus Torvalds list_add_tail(&open_devip->dev_list, 20781da177e4SLinus Torvalds &sdbg_host->dev_info_list); 20791da177e4SLinus Torvalds } 20801da177e4SLinus Torvalds if (open_devip) { 20811da177e4SLinus Torvalds open_devip->channel = sdev->channel; 20821da177e4SLinus Torvalds open_devip->target = sdev->id; 20831da177e4SLinus Torvalds open_devip->lun = sdev->lun; 20841da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 20851da177e4SLinus Torvalds open_devip->reset = 1; 20861da177e4SLinus Torvalds open_devip->used = 1; 20871da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 20881da177e4SLinus Torvalds if (scsi_debug_dsense) 20891da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 20901da177e4SLinus Torvalds else { 20911da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 20921da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 20931da177e4SLinus Torvalds } 2094c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 2095c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 20961da177e4SLinus Torvalds return open_devip; 20971da177e4SLinus Torvalds } 20981da177e4SLinus Torvalds return NULL; 20991da177e4SLinus Torvalds } 21001da177e4SLinus Torvalds 21011da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 21021da177e4SLinus Torvalds int asc, int asq) 21031da177e4SLinus Torvalds { 21041da177e4SLinus Torvalds unsigned char * sbuff; 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds sbuff = devip->sense_buff; 21071da177e4SLinus Torvalds memset(sbuff, 0, SDEBUG_SENSE_LEN); 21081da177e4SLinus Torvalds if (scsi_debug_dsense) { 21091da177e4SLinus Torvalds sbuff[0] = 0x72; /* descriptor, current */ 21101da177e4SLinus Torvalds sbuff[1] = key; 21111da177e4SLinus Torvalds sbuff[2] = asc; 21121da177e4SLinus Torvalds sbuff[3] = asq; 21131da177e4SLinus Torvalds } else { 21141da177e4SLinus Torvalds sbuff[0] = 0x70; /* fixed, current */ 21151da177e4SLinus Torvalds sbuff[2] = key; 21161da177e4SLinus Torvalds sbuff[7] = 0xa; /* implies 18 byte sense buffer */ 21171da177e4SLinus Torvalds sbuff[12] = asc; 21181da177e4SLinus Torvalds sbuff[13] = asq; 21191da177e4SLinus Torvalds } 21201da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21211da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 21221da177e4SLinus Torvalds "[0x%x,0x%x,0x%x]\n", key, asc, asq); 21231da177e4SLinus Torvalds } 21241da177e4SLinus Torvalds 21251da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 21261da177e4SLinus Torvalds { 21271da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21281da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 21291da177e4SLinus Torvalds ++num_aborts; 21301da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 21311da177e4SLinus Torvalds return SUCCESS; 21321da177e4SLinus Torvalds } 21331da177e4SLinus Torvalds 21341da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 21351da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 21361da177e4SLinus Torvalds { 21371da177e4SLinus Torvalds int res; 21381da177e4SLinus Torvalds unsigned char *buf; 21391da177e4SLinus Torvalds 21401da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21411da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 21421da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 21431da177e4SLinus Torvalds if (buf) { 21441da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 21451da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 21461da177e4SLinus Torvalds kfree(buf); 21471da177e4SLinus Torvalds if (! res) 21481da177e4SLinus Torvalds return res; 21491da177e4SLinus Torvalds } 21501da177e4SLinus Torvalds info[0] = sdebug_heads; 21511da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 21521da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 21531da177e4SLinus Torvalds return 0; 21541da177e4SLinus Torvalds } 21551da177e4SLinus Torvalds 21561da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 21571da177e4SLinus Torvalds { 21581da177e4SLinus Torvalds struct sdebug_dev_info * devip; 21591da177e4SLinus Torvalds 21601da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21611da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 21621da177e4SLinus Torvalds ++num_dev_resets; 21631da177e4SLinus Torvalds if (SCpnt) { 21641da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 21651da177e4SLinus Torvalds if (devip) 21661da177e4SLinus Torvalds devip->reset = 1; 21671da177e4SLinus Torvalds } 21681da177e4SLinus Torvalds return SUCCESS; 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 21721da177e4SLinus Torvalds { 21731da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 21741da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 21751da177e4SLinus Torvalds struct scsi_device * sdp; 21761da177e4SLinus Torvalds struct Scsi_Host * hp; 21771da177e4SLinus Torvalds 21781da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21791da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 21801da177e4SLinus Torvalds ++num_bus_resets; 21811da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 21821da177e4SLinus Torvalds sdbg_host = *(struct sdebug_host_info **) hp->hostdata; 21831da177e4SLinus Torvalds if (sdbg_host) { 21841da177e4SLinus Torvalds list_for_each_entry(dev_info, 21851da177e4SLinus Torvalds &sdbg_host->dev_info_list, 21861da177e4SLinus Torvalds dev_list) 21871da177e4SLinus Torvalds dev_info->reset = 1; 21881da177e4SLinus Torvalds } 21891da177e4SLinus Torvalds } 21901da177e4SLinus Torvalds return SUCCESS; 21911da177e4SLinus Torvalds } 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 21941da177e4SLinus Torvalds { 21951da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 21961da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 21971da177e4SLinus Torvalds 21981da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 21991da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 22001da177e4SLinus Torvalds ++num_host_resets; 22011da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 22021da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 22031da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 22041da177e4SLinus Torvalds dev_list) 22051da177e4SLinus Torvalds dev_info->reset = 1; 22061da177e4SLinus Torvalds } 22071da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 22081da177e4SLinus Torvalds stop_all_queued(); 22091da177e4SLinus Torvalds return SUCCESS; 22101da177e4SLinus Torvalds } 22111da177e4SLinus Torvalds 22121da177e4SLinus Torvalds /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 22131da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd) 22141da177e4SLinus Torvalds { 22151da177e4SLinus Torvalds unsigned long iflags; 22161da177e4SLinus Torvalds int k; 22171da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 22181da177e4SLinus Torvalds 22191da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 22201da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 22211da177e4SLinus Torvalds sqcp = &queued_arr[k]; 22221da177e4SLinus Torvalds if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 22231da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 22241da177e4SLinus Torvalds sqcp->in_use = 0; 22251da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 22261da177e4SLinus Torvalds break; 22271da177e4SLinus Torvalds } 22281da177e4SLinus Torvalds } 22291da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 22301da177e4SLinus Torvalds return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; 22311da177e4SLinus Torvalds } 22321da177e4SLinus Torvalds 22331da177e4SLinus Torvalds /* Deletes (stops) timers of all queued commands */ 22341da177e4SLinus Torvalds static void stop_all_queued(void) 22351da177e4SLinus Torvalds { 22361da177e4SLinus Torvalds unsigned long iflags; 22371da177e4SLinus Torvalds int k; 22381da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 22391da177e4SLinus Torvalds 22401da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 22411da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 22421da177e4SLinus Torvalds sqcp = &queued_arr[k]; 22431da177e4SLinus Torvalds if (sqcp->in_use && sqcp->a_cmnd) { 22441da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 22451da177e4SLinus Torvalds sqcp->in_use = 0; 22461da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds } 22491da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 22501da177e4SLinus Torvalds } 22511da177e4SLinus Torvalds 22521da177e4SLinus Torvalds /* Initializes timers in queued array */ 22531da177e4SLinus Torvalds static void __init init_all_queued(void) 22541da177e4SLinus Torvalds { 22551da177e4SLinus Torvalds unsigned long iflags; 22561da177e4SLinus Torvalds int k; 22571da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 22581da177e4SLinus Torvalds 22591da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 22601da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 22611da177e4SLinus Torvalds sqcp = &queued_arr[k]; 22621da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 22631da177e4SLinus Torvalds sqcp->in_use = 0; 22641da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 22651da177e4SLinus Torvalds } 22661da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 22671da177e4SLinus Torvalds } 22681da177e4SLinus Torvalds 22691da177e4SLinus Torvalds static void __init sdebug_build_parts(unsigned char * ramp) 22701da177e4SLinus Torvalds { 22711da177e4SLinus Torvalds struct partition * pp; 22721da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 22731da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 22741da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 22751da177e4SLinus Torvalds 22761da177e4SLinus Torvalds /* assume partition table already zeroed */ 22771da177e4SLinus Torvalds if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576)) 22781da177e4SLinus Torvalds return; 22791da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 22801da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 22811da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 22821da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 22831da177e4SLinus Torvalds } 2284c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 22851da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 22861da177e4SLinus Torvalds / scsi_debug_num_parts; 22871da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 22881da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 22891da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 22901da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 22911da177e4SLinus Torvalds * heads_by_sects; 22921da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 22931da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 22941da177e4SLinus Torvalds 22951da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 22961da177e4SLinus Torvalds ramp[511] = 0xAA; 22971da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 22981da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 22991da177e4SLinus Torvalds start_sec = starts[k]; 23001da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 23011da177e4SLinus Torvalds pp->boot_ind = 0; 23021da177e4SLinus Torvalds 23031da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 23041da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 23051da177e4SLinus Torvalds / sdebug_sectors_per; 23061da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 23091da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 23101da177e4SLinus Torvalds / sdebug_sectors_per; 23111da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 23121da177e4SLinus Torvalds 23131da177e4SLinus Torvalds pp->start_sect = start_sec; 23141da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 23151da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 23161da177e4SLinus Torvalds } 23171da177e4SLinus Torvalds } 23181da177e4SLinus Torvalds 23191da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 23201da177e4SLinus Torvalds struct sdebug_dev_info * devip, 23211da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 23221da177e4SLinus Torvalds { 23231da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 23241da177e4SLinus Torvalds if (scsi_result) { 23251da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 23261da177e4SLinus Torvalds 2327c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2328c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2329c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 23301da177e4SLinus Torvalds } 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds if (cmnd && devip) { 23331da177e4SLinus Torvalds /* simulate autosense by this driver */ 23341da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 23351da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 23361da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 23371da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 23381da177e4SLinus Torvalds } 23391da177e4SLinus Torvalds if (delta_jiff <= 0) { 23401da177e4SLinus Torvalds if (cmnd) 23411da177e4SLinus Torvalds cmnd->result = scsi_result; 23421da177e4SLinus Torvalds if (done) 23431da177e4SLinus Torvalds done(cmnd); 23441da177e4SLinus Torvalds return 0; 23451da177e4SLinus Torvalds } else { 23461da177e4SLinus Torvalds unsigned long iflags; 23471da177e4SLinus Torvalds int k; 23481da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 23491da177e4SLinus Torvalds 23501da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 23511da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 23521da177e4SLinus Torvalds sqcp = &queued_arr[k]; 23531da177e4SLinus Torvalds if (! sqcp->in_use) 23541da177e4SLinus Torvalds break; 23551da177e4SLinus Torvalds } 23561da177e4SLinus Torvalds if (k >= SCSI_DEBUG_CANQUEUE) { 23571da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23581da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 23591da177e4SLinus Torvalds return 1; /* report busy to mid level */ 23601da177e4SLinus Torvalds } 23611da177e4SLinus Torvalds sqcp->in_use = 1; 23621da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 23631da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 23641da177e4SLinus Torvalds sqcp->done_funct = done; 23651da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 23661da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 23671da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 23681da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 23691da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23701da177e4SLinus Torvalds if (cmnd) 23711da177e4SLinus Torvalds cmnd->result = 0; 23721da177e4SLinus Torvalds return 0; 23731da177e4SLinus Torvalds } 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds 237623183910SDouglas Gilbert /* Note: The following macros create attribute files in the 237723183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 237823183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 237923183910SDouglas Gilbert as it can when the corresponding attribute in the 238023183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 238123183910SDouglas Gilbert */ 2382c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 2383c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2384c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 2385c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2386c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 238723183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 2388c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 2389c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 2390c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2391c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 2392c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 2393c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2394c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 2395c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 239623183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 239723183910SDouglas Gilbert S_IRUGO | S_IWUSR); 23981da177e4SLinus Torvalds 23991da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 24001da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 24011da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 24021da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 24031da177e4SLinus Torvalds 24041da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 24051da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2406c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 2407c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2408beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 240923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 2410c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 2411c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 24121da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2413c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 24146f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 24151da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 24161da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2417c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 241823183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 24191da177e4SLinus Torvalds 24201da177e4SLinus Torvalds 24211da177e4SLinus Torvalds static char sdebug_info[256]; 24221da177e4SLinus Torvalds 24231da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 24241da177e4SLinus Torvalds { 24251da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 24261da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 24271da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 24281da177e4SLinus Torvalds scsi_debug_opts); 24291da177e4SLinus Torvalds return sdebug_info; 24301da177e4SLinus Torvalds } 24311da177e4SLinus Torvalds 24321da177e4SLinus Torvalds /* scsi_debug_proc_info 24331da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 24341da177e4SLinus Torvalds */ 24351da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 24361da177e4SLinus Torvalds int length, int inout) 24371da177e4SLinus Torvalds { 24381da177e4SLinus Torvalds int len, pos, begin; 24391da177e4SLinus Torvalds int orig_length; 24401da177e4SLinus Torvalds 24411da177e4SLinus Torvalds orig_length = length; 24421da177e4SLinus Torvalds 24431da177e4SLinus Torvalds if (inout == 1) { 24441da177e4SLinus Torvalds char arr[16]; 24451da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 24461da177e4SLinus Torvalds 24471da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 24481da177e4SLinus Torvalds return -EACCES; 24491da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 24501da177e4SLinus Torvalds arr[minLen] = '\0'; 24511da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 24521da177e4SLinus Torvalds return -EINVAL; 24531da177e4SLinus Torvalds scsi_debug_opts = pos; 24541da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 24551da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 24561da177e4SLinus Torvalds return length; 24571da177e4SLinus Torvalds } 24581da177e4SLinus Torvalds begin = 0; 24591da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 24601da177e4SLinus Torvalds "%s [%s]\n" 24611da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 24621da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 24631da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 24641da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 24651da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 24661da177e4SLinus Torvalds "host_resets=%d\n", 24671da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 24681da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 24691da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 24701da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 24711da177e4SLinus Torvalds SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 24721da177e4SLinus Torvalds num_aborts, num_dev_resets, num_bus_resets, num_host_resets); 24731da177e4SLinus Torvalds if (pos < offset) { 24741da177e4SLinus Torvalds len = 0; 24751da177e4SLinus Torvalds begin = pos; 24761da177e4SLinus Torvalds } 24771da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 24781da177e4SLinus Torvalds len -= (offset - begin); 24791da177e4SLinus Torvalds if (len > length) 24801da177e4SLinus Torvalds len = length; 24811da177e4SLinus Torvalds return len; 24821da177e4SLinus Torvalds } 24831da177e4SLinus Torvalds 24841da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 24851da177e4SLinus Torvalds { 24861da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 24901da177e4SLinus Torvalds const char * buf, size_t count) 24911da177e4SLinus Torvalds { 24921da177e4SLinus Torvalds int delay; 24931da177e4SLinus Torvalds char work[20]; 24941da177e4SLinus Torvalds 24951da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 24961da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 24971da177e4SLinus Torvalds scsi_debug_delay = delay; 24981da177e4SLinus Torvalds return count; 24991da177e4SLinus Torvalds } 25001da177e4SLinus Torvalds } 25011da177e4SLinus Torvalds return -EINVAL; 25021da177e4SLinus Torvalds } 25031da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 25041da177e4SLinus Torvalds sdebug_delay_store); 25051da177e4SLinus Torvalds 25061da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 25071da177e4SLinus Torvalds { 25081da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 25091da177e4SLinus Torvalds } 25101da177e4SLinus Torvalds 25111da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 25121da177e4SLinus Torvalds const char * buf, size_t count) 25131da177e4SLinus Torvalds { 25141da177e4SLinus Torvalds int opts; 25151da177e4SLinus Torvalds char work[20]; 25161da177e4SLinus Torvalds 25171da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 25181da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 25191da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 25201da177e4SLinus Torvalds goto opts_done; 25211da177e4SLinus Torvalds } else { 25221da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 25231da177e4SLinus Torvalds goto opts_done; 25241da177e4SLinus Torvalds } 25251da177e4SLinus Torvalds } 25261da177e4SLinus Torvalds return -EINVAL; 25271da177e4SLinus Torvalds opts_done: 25281da177e4SLinus Torvalds scsi_debug_opts = opts; 25291da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 25301da177e4SLinus Torvalds return count; 25311da177e4SLinus Torvalds } 25321da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 25331da177e4SLinus Torvalds sdebug_opts_store); 25341da177e4SLinus Torvalds 25351da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 25361da177e4SLinus Torvalds { 25371da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 25381da177e4SLinus Torvalds } 25391da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 25401da177e4SLinus Torvalds const char * buf, size_t count) 25411da177e4SLinus Torvalds { 25421da177e4SLinus Torvalds int n; 25431da177e4SLinus Torvalds 25441da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 25451da177e4SLinus Torvalds scsi_debug_ptype = n; 25461da177e4SLinus Torvalds return count; 25471da177e4SLinus Torvalds } 25481da177e4SLinus Torvalds return -EINVAL; 25491da177e4SLinus Torvalds } 25501da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 25511da177e4SLinus Torvalds 25521da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 25531da177e4SLinus Torvalds { 25541da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 25551da177e4SLinus Torvalds } 25561da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 25571da177e4SLinus Torvalds const char * buf, size_t count) 25581da177e4SLinus Torvalds { 25591da177e4SLinus Torvalds int n; 25601da177e4SLinus Torvalds 25611da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 25621da177e4SLinus Torvalds scsi_debug_dsense = n; 25631da177e4SLinus Torvalds return count; 25641da177e4SLinus Torvalds } 25651da177e4SLinus Torvalds return -EINVAL; 25661da177e4SLinus Torvalds } 25671da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 25681da177e4SLinus Torvalds sdebug_dsense_store); 25691da177e4SLinus Torvalds 257023183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 257123183910SDouglas Gilbert { 257223183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 257323183910SDouglas Gilbert } 257423183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 257523183910SDouglas Gilbert const char * buf, size_t count) 257623183910SDouglas Gilbert { 257723183910SDouglas Gilbert int n; 257823183910SDouglas Gilbert 257923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 258023183910SDouglas Gilbert scsi_debug_fake_rw = n; 258123183910SDouglas Gilbert return count; 258223183910SDouglas Gilbert } 258323183910SDouglas Gilbert return -EINVAL; 258423183910SDouglas Gilbert } 258523183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 258623183910SDouglas Gilbert sdebug_fake_rw_store); 258723183910SDouglas Gilbert 2588c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2589c65b1445SDouglas Gilbert { 2590c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2591c65b1445SDouglas Gilbert } 2592c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2593c65b1445SDouglas Gilbert const char * buf, size_t count) 2594c65b1445SDouglas Gilbert { 2595c65b1445SDouglas Gilbert int n; 2596c65b1445SDouglas Gilbert 2597c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2598c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2599c65b1445SDouglas Gilbert return count; 2600c65b1445SDouglas Gilbert } 2601c65b1445SDouglas Gilbert return -EINVAL; 2602c65b1445SDouglas Gilbert } 2603c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 2604c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 2605c65b1445SDouglas Gilbert 26061da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 26071da177e4SLinus Torvalds { 26081da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 26091da177e4SLinus Torvalds } 26101da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 26111da177e4SLinus Torvalds const char * buf, size_t count) 26121da177e4SLinus Torvalds { 26131da177e4SLinus Torvalds int n; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 26161da177e4SLinus Torvalds scsi_debug_num_tgts = n; 26171da177e4SLinus Torvalds sdebug_max_tgts_luns(); 26181da177e4SLinus Torvalds return count; 26191da177e4SLinus Torvalds } 26201da177e4SLinus Torvalds return -EINVAL; 26211da177e4SLinus Torvalds } 26221da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 26231da177e4SLinus Torvalds sdebug_num_tgts_store); 26241da177e4SLinus Torvalds 26251da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 26261da177e4SLinus Torvalds { 26271da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 26281da177e4SLinus Torvalds } 26291da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 26321da177e4SLinus Torvalds { 26331da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 26341da177e4SLinus Torvalds } 26351da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 26381da177e4SLinus Torvalds { 26391da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 26401da177e4SLinus Torvalds } 26411da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 26421da177e4SLinus Torvalds const char * buf, size_t count) 26431da177e4SLinus Torvalds { 26441da177e4SLinus Torvalds int nth; 26451da177e4SLinus Torvalds 26461da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 26471da177e4SLinus Torvalds scsi_debug_every_nth = nth; 26481da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 26491da177e4SLinus Torvalds return count; 26501da177e4SLinus Torvalds } 26511da177e4SLinus Torvalds return -EINVAL; 26521da177e4SLinus Torvalds } 26531da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 26541da177e4SLinus Torvalds sdebug_every_nth_store); 26551da177e4SLinus Torvalds 26561da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 26571da177e4SLinus Torvalds { 26581da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 26591da177e4SLinus Torvalds } 26601da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 26611da177e4SLinus Torvalds const char * buf, size_t count) 26621da177e4SLinus Torvalds { 26631da177e4SLinus Torvalds int n; 26641da177e4SLinus Torvalds 26651da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 26661da177e4SLinus Torvalds scsi_debug_max_luns = n; 26671da177e4SLinus Torvalds sdebug_max_tgts_luns(); 26681da177e4SLinus Torvalds return count; 26691da177e4SLinus Torvalds } 26701da177e4SLinus Torvalds return -EINVAL; 26711da177e4SLinus Torvalds } 26721da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 26731da177e4SLinus Torvalds sdebug_max_luns_store); 26741da177e4SLinus Torvalds 26751da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 26761da177e4SLinus Torvalds { 26771da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 26781da177e4SLinus Torvalds } 26791da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 26801da177e4SLinus Torvalds 2681c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 2682c65b1445SDouglas Gilbert { 2683c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 2684c65b1445SDouglas Gilbert } 2685c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 2686c65b1445SDouglas Gilbert const char * buf, size_t count) 2687c65b1445SDouglas Gilbert { 2688c65b1445SDouglas Gilbert int n; 2689c65b1445SDouglas Gilbert 2690c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2691c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 2692c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 2693c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 2694c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 2695c65b1445SDouglas Gilbert } else 2696c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 2697c65b1445SDouglas Gilbert return count; 2698c65b1445SDouglas Gilbert } 2699c65b1445SDouglas Gilbert return -EINVAL; 2700c65b1445SDouglas Gilbert } 2701c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 2702c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 2703c65b1445SDouglas Gilbert 27041da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 27051da177e4SLinus Torvalds { 27061da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 27071da177e4SLinus Torvalds } 27081da177e4SLinus Torvalds 27091da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 27101da177e4SLinus Torvalds const char * buf, size_t count) 27111da177e4SLinus Torvalds { 27121da177e4SLinus Torvalds int delta_hosts; 27131da177e4SLinus Torvalds char work[20]; 27141da177e4SLinus Torvalds 27151da177e4SLinus Torvalds if (1 != sscanf(buf, "%10s", work)) 27161da177e4SLinus Torvalds return -EINVAL; 27171da177e4SLinus Torvalds { /* temporary hack around sscanf() problem with -ve nums */ 27181da177e4SLinus Torvalds int neg = 0; 27191da177e4SLinus Torvalds 27201da177e4SLinus Torvalds if ('-' == *work) 27211da177e4SLinus Torvalds neg = 1; 27221da177e4SLinus Torvalds if (1 != sscanf(work + neg, "%d", &delta_hosts)) 27231da177e4SLinus Torvalds return -EINVAL; 27241da177e4SLinus Torvalds if (neg) 27251da177e4SLinus Torvalds delta_hosts = -delta_hosts; 27261da177e4SLinus Torvalds } 27271da177e4SLinus Torvalds if (delta_hosts > 0) { 27281da177e4SLinus Torvalds do { 27291da177e4SLinus Torvalds sdebug_add_adapter(); 27301da177e4SLinus Torvalds } while (--delta_hosts); 27311da177e4SLinus Torvalds } else if (delta_hosts < 0) { 27321da177e4SLinus Torvalds do { 27331da177e4SLinus Torvalds sdebug_remove_adapter(); 27341da177e4SLinus Torvalds } while (++delta_hosts); 27351da177e4SLinus Torvalds } 27361da177e4SLinus Torvalds return count; 27371da177e4SLinus Torvalds } 27381da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 27391da177e4SLinus Torvalds sdebug_add_host_store); 27401da177e4SLinus Torvalds 274123183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 274223183910SDouglas Gilbert char * buf) 274323183910SDouglas Gilbert { 274423183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 274523183910SDouglas Gilbert } 274623183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 274723183910SDouglas Gilbert const char * buf, size_t count) 274823183910SDouglas Gilbert { 274923183910SDouglas Gilbert int n; 275023183910SDouglas Gilbert 275123183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 275223183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 275323183910SDouglas Gilbert return count; 275423183910SDouglas Gilbert } 275523183910SDouglas Gilbert return -EINVAL; 275623183910SDouglas Gilbert } 275723183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 275823183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 275923183910SDouglas Gilbert 276023183910SDouglas Gilbert /* Note: The following function creates attribute files in the 276123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 276223183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 276323183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 276423183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 276523183910SDouglas Gilbert */ 27666ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 27671da177e4SLinus Torvalds { 27686ecaff7fSRandy Dunlap int ret; 27696ecaff7fSRandy Dunlap 27706ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 27716ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 27726ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 27736ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 27746ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 277523183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 27766ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 277723183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 27786ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 277923183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 27806ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 27816ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 27826ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 278323183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 278423183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 27856ecaff7fSRandy Dunlap return ret; 27861da177e4SLinus Torvalds } 27871da177e4SLinus Torvalds 27881da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 27891da177e4SLinus Torvalds { 279023183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 279123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 27921da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 27931da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 27941da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 27951da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 279623183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 279723183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 27981da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 279923183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 28001da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 28011da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 28021da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 28031da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 28041da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 28051da177e4SLinus Torvalds } 28061da177e4SLinus Torvalds 28071da177e4SLinus Torvalds static int __init scsi_debug_init(void) 28081da177e4SLinus Torvalds { 2809c65b1445SDouglas Gilbert unsigned int sz; 28101da177e4SLinus Torvalds int host_to_add; 28111da177e4SLinus Torvalds int k; 28126ecaff7fSRandy Dunlap int ret; 28131da177e4SLinus Torvalds 28141da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 28151da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 2816c65b1445SDouglas Gilbert sdebug_store_size = (unsigned int)scsi_debug_dev_size_mb * 1048576; 2817c65b1445SDouglas Gilbert sdebug_store_sectors = sdebug_store_size / SECT_SIZE; 2818c65b1445SDouglas Gilbert if (scsi_debug_virtual_gb > 0) { 2819c65b1445SDouglas Gilbert sdebug_capacity = 2048 * 1024; 2820c65b1445SDouglas Gilbert sdebug_capacity *= scsi_debug_virtual_gb; 2821c65b1445SDouglas Gilbert } else 2822c65b1445SDouglas Gilbert sdebug_capacity = sdebug_store_sectors; 28231da177e4SLinus Torvalds 28241da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 28251da177e4SLinus Torvalds sdebug_heads = 8; 28261da177e4SLinus Torvalds sdebug_sectors_per = 32; 28271da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 28281da177e4SLinus Torvalds sdebug_heads = 32; 28291da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 28301da177e4SLinus Torvalds sdebug_heads = 64; 28311da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 28321da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 28331da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 28341da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 28351da177e4SLinus Torvalds sdebug_heads = 255; 28361da177e4SLinus Torvalds sdebug_sectors_per = 63; 28371da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 28381da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 28391da177e4SLinus Torvalds } 28401da177e4SLinus Torvalds 28411da177e4SLinus Torvalds sz = sdebug_store_size; 28421da177e4SLinus Torvalds fake_storep = vmalloc(sz); 28431da177e4SLinus Torvalds if (NULL == fake_storep) { 28441da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 28451da177e4SLinus Torvalds return -ENOMEM; 28461da177e4SLinus Torvalds } 28471da177e4SLinus Torvalds memset(fake_storep, 0, sz); 28481da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 28491da177e4SLinus Torvalds sdebug_build_parts(fake_storep); 28501da177e4SLinus Torvalds 28516ecaff7fSRandy Dunlap ret = device_register(&pseudo_primary); 28526ecaff7fSRandy Dunlap if (ret < 0) { 28536ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: device_register error: %d\n", 28546ecaff7fSRandy Dunlap ret); 28556ecaff7fSRandy Dunlap goto free_vm; 28566ecaff7fSRandy Dunlap } 28576ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 28586ecaff7fSRandy Dunlap if (ret < 0) { 28596ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 28606ecaff7fSRandy Dunlap ret); 28616ecaff7fSRandy Dunlap goto dev_unreg; 28626ecaff7fSRandy Dunlap } 28636ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 28646ecaff7fSRandy Dunlap if (ret < 0) { 28656ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 28666ecaff7fSRandy Dunlap ret); 28676ecaff7fSRandy Dunlap goto bus_unreg; 28686ecaff7fSRandy Dunlap } 28696ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 28706ecaff7fSRandy Dunlap if (ret < 0) { 28716ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 28726ecaff7fSRandy Dunlap ret); 28736ecaff7fSRandy Dunlap goto del_files; 28746ecaff7fSRandy Dunlap } 28751da177e4SLinus Torvalds 28766ecaff7fSRandy Dunlap init_all_queued(); 28771da177e4SLinus Torvalds 28781da177e4SLinus Torvalds sdebug_driver_template.proc_name = (char *)sdebug_proc_name; 28791da177e4SLinus Torvalds 28801da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 28811da177e4SLinus Torvalds scsi_debug_add_host = 0; 28821da177e4SLinus Torvalds 28831da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 28841da177e4SLinus Torvalds if (sdebug_add_adapter()) { 28851da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 28861da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 28871da177e4SLinus Torvalds break; 28881da177e4SLinus Torvalds } 28891da177e4SLinus Torvalds } 28901da177e4SLinus Torvalds 28911da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 28921da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 28931da177e4SLinus Torvalds scsi_debug_add_host); 28941da177e4SLinus Torvalds } 28951da177e4SLinus Torvalds return 0; 28966ecaff7fSRandy Dunlap 28976ecaff7fSRandy Dunlap del_files: 28986ecaff7fSRandy Dunlap do_remove_driverfs_files(); 28996ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 29006ecaff7fSRandy Dunlap bus_unreg: 29016ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 29026ecaff7fSRandy Dunlap dev_unreg: 29036ecaff7fSRandy Dunlap device_unregister(&pseudo_primary); 29046ecaff7fSRandy Dunlap free_vm: 29056ecaff7fSRandy Dunlap vfree(fake_storep); 29066ecaff7fSRandy Dunlap 29076ecaff7fSRandy Dunlap return ret; 29081da177e4SLinus Torvalds } 29091da177e4SLinus Torvalds 29101da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 29111da177e4SLinus Torvalds { 29121da177e4SLinus Torvalds int k = scsi_debug_add_host; 29131da177e4SLinus Torvalds 29141da177e4SLinus Torvalds stop_all_queued(); 29151da177e4SLinus Torvalds for (; k; k--) 29161da177e4SLinus Torvalds sdebug_remove_adapter(); 29171da177e4SLinus Torvalds do_remove_driverfs_files(); 29181da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 29191da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 29201da177e4SLinus Torvalds device_unregister(&pseudo_primary); 29211da177e4SLinus Torvalds 29221da177e4SLinus Torvalds vfree(fake_storep); 29231da177e4SLinus Torvalds } 29241da177e4SLinus Torvalds 29251da177e4SLinus Torvalds device_initcall(scsi_debug_init); 29261da177e4SLinus Torvalds module_exit(scsi_debug_exit); 29271da177e4SLinus Torvalds 292852c1da39SAdrian Bunk static void pseudo_0_release(struct device * dev) 29291da177e4SLinus Torvalds { 29301da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 29311da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); 29321da177e4SLinus Torvalds } 29331da177e4SLinus Torvalds 29341da177e4SLinus Torvalds static struct device pseudo_primary = { 29351da177e4SLinus Torvalds .bus_id = "pseudo_0", 29361da177e4SLinus Torvalds .release = pseudo_0_release, 29371da177e4SLinus Torvalds }; 29381da177e4SLinus Torvalds 29391da177e4SLinus Torvalds static int pseudo_lld_bus_match(struct device *dev, 29401da177e4SLinus Torvalds struct device_driver *dev_driver) 29411da177e4SLinus Torvalds { 29421da177e4SLinus Torvalds return 1; 29431da177e4SLinus Torvalds } 29441da177e4SLinus Torvalds 29451da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus = { 29461da177e4SLinus Torvalds .name = "pseudo", 29471da177e4SLinus Torvalds .match = pseudo_lld_bus_match, 2948bbbe3a41SRussell King .probe = sdebug_driver_probe, 2949bbbe3a41SRussell King .remove = sdebug_driver_remove, 29501da177e4SLinus Torvalds }; 29511da177e4SLinus Torvalds 29521da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 29531da177e4SLinus Torvalds { 29541da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29551da177e4SLinus Torvalds 29561da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29571da177e4SLinus Torvalds kfree(sdbg_host); 29581da177e4SLinus Torvalds } 29591da177e4SLinus Torvalds 29601da177e4SLinus Torvalds static int sdebug_add_adapter(void) 29611da177e4SLinus Torvalds { 29621da177e4SLinus Torvalds int k, devs_per_host; 29631da177e4SLinus Torvalds int error = 0; 29641da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29651da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 29661da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 29671da177e4SLinus Torvalds 296824669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 29691da177e4SLinus Torvalds if (NULL == sdbg_host) { 29701da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 29711da177e4SLinus Torvalds __FUNCTION__, __LINE__); 29721da177e4SLinus Torvalds return -ENOMEM; 29731da177e4SLinus Torvalds } 29741da177e4SLinus Torvalds 29751da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 29761da177e4SLinus Torvalds 29771da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 29781da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 297924669f75SJes Sorensen sdbg_devinfo = kzalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); 29801da177e4SLinus Torvalds if (NULL == sdbg_devinfo) { 29811da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 29821da177e4SLinus Torvalds __FUNCTION__, __LINE__); 29831da177e4SLinus Torvalds error = -ENOMEM; 29841da177e4SLinus Torvalds goto clean; 29851da177e4SLinus Torvalds } 29861da177e4SLinus Torvalds sdbg_devinfo->sdbg_host = sdbg_host; 29871da177e4SLinus Torvalds list_add_tail(&sdbg_devinfo->dev_list, 29881da177e4SLinus Torvalds &sdbg_host->dev_info_list); 29891da177e4SLinus Torvalds } 29901da177e4SLinus Torvalds 29911da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 29921da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 29931da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 29941da177e4SLinus Torvalds 29951da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 29961da177e4SLinus Torvalds sdbg_host->dev.parent = &pseudo_primary; 29971da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 29981da177e4SLinus Torvalds sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); 29991da177e4SLinus Torvalds 30001da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 30011da177e4SLinus Torvalds 30021da177e4SLinus Torvalds if (error) 30031da177e4SLinus Torvalds goto clean; 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds ++scsi_debug_add_host; 30061da177e4SLinus Torvalds return error; 30071da177e4SLinus Torvalds 30081da177e4SLinus Torvalds clean: 30091da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 30101da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 30111da177e4SLinus Torvalds dev_list); 30121da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 30131da177e4SLinus Torvalds kfree(sdbg_devinfo); 30141da177e4SLinus Torvalds } 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds kfree(sdbg_host); 30171da177e4SLinus Torvalds return error; 30181da177e4SLinus Torvalds } 30191da177e4SLinus Torvalds 30201da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 30211da177e4SLinus Torvalds { 30221da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 30231da177e4SLinus Torvalds 30241da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 30251da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 30261da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 30271da177e4SLinus Torvalds struct sdebug_host_info, host_list); 30281da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 30291da177e4SLinus Torvalds } 30301da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 30311da177e4SLinus Torvalds 30321da177e4SLinus Torvalds if (!sdbg_host) 30331da177e4SLinus Torvalds return; 30341da177e4SLinus Torvalds 30351da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 30361da177e4SLinus Torvalds --scsi_debug_add_host; 30371da177e4SLinus Torvalds } 30381da177e4SLinus Torvalds 30391da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 30401da177e4SLinus Torvalds { 30411da177e4SLinus Torvalds int error = 0; 30421da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 30431da177e4SLinus Torvalds struct Scsi_Host *hpnt; 30441da177e4SLinus Torvalds 30451da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 30461da177e4SLinus Torvalds 30471da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 30481da177e4SLinus Torvalds if (NULL == hpnt) { 30491da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); 30501da177e4SLinus Torvalds error = -ENODEV; 30511da177e4SLinus Torvalds return error; 30521da177e4SLinus Torvalds } 30531da177e4SLinus Torvalds 30541da177e4SLinus Torvalds sdbg_host->shost = hpnt; 30551da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 30561da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 30571da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 30581da177e4SLinus Torvalds else 30591da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 3060c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 30631da177e4SLinus Torvalds if (error) { 30641da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); 30651da177e4SLinus Torvalds error = -ENODEV; 30661da177e4SLinus Torvalds scsi_host_put(hpnt); 30671da177e4SLinus Torvalds } else 30681da177e4SLinus Torvalds scsi_scan_host(hpnt); 30691da177e4SLinus Torvalds 30701da177e4SLinus Torvalds 30711da177e4SLinus Torvalds return error; 30721da177e4SLinus Torvalds } 30731da177e4SLinus Torvalds 30741da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 30751da177e4SLinus Torvalds { 30761da177e4SLinus Torvalds struct list_head *lh, *lh_sf; 30771da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 30781da177e4SLinus Torvalds struct sdebug_dev_info *sdbg_devinfo; 30791da177e4SLinus Torvalds 30801da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 30811da177e4SLinus Torvalds 30821da177e4SLinus Torvalds if (!sdbg_host) { 30831da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 30841da177e4SLinus Torvalds __FUNCTION__); 30851da177e4SLinus Torvalds return -ENODEV; 30861da177e4SLinus Torvalds } 30871da177e4SLinus Torvalds 30881da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 30891da177e4SLinus Torvalds 30901da177e4SLinus Torvalds list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { 30911da177e4SLinus Torvalds sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, 30921da177e4SLinus Torvalds dev_list); 30931da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 30941da177e4SLinus Torvalds kfree(sdbg_devinfo); 30951da177e4SLinus Torvalds } 30961da177e4SLinus Torvalds 30971da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 30981da177e4SLinus Torvalds return 0; 30991da177e4SLinus Torvalds } 31001da177e4SLinus Torvalds 31011da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void) 31021da177e4SLinus Torvalds { 31031da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 31041da177e4SLinus Torvalds struct Scsi_Host *hpnt; 31051da177e4SLinus Torvalds 31061da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 31071da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 31081da177e4SLinus Torvalds hpnt = sdbg_host->shost; 31091da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && 31101da177e4SLinus Torvalds (scsi_debug_num_tgts > hpnt->this_id)) 31111da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 31121da177e4SLinus Torvalds else 31131da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 3114c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ 31151da177e4SLinus Torvalds } 31161da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 31171da177e4SLinus Torvalds } 3118