11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This version is more generic, simulating a variable number of disk 1023183910SDouglas Gilbert * (or disk like devices) sharing a common amount of RAM. To be more 1123183910SDouglas Gilbert * realistic, the simulated devices have the transport attributes of 1223183910SDouglas Gilbert * SAS disks. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * 151da177e4SLinus Torvalds * For documentation see http://www.torque.net/sg/sdebug26.html 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] 181da177e4SLinus Torvalds * dpg: work for devfs large number of disks [20010809] 191da177e4SLinus Torvalds * forked for lk 2.5 series [20011216, 20020101] 201da177e4SLinus Torvalds * use vmalloc() more inquiry+mode_sense [20020302] 211da177e4SLinus Torvalds * add timers for delayed responses [20020721] 221da177e4SLinus Torvalds * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] 231da177e4SLinus Torvalds * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] 241da177e4SLinus Torvalds * dpg: change style of boot options to "scsi_debug.num_tgts=2" and 251da177e4SLinus Torvalds * module options to "modprobe scsi_debug num_tgts=2" [20021221] 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #include <linux/kernel.h> 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/timer.h> 331da177e4SLinus Torvalds #include <linux/types.h> 341da177e4SLinus Torvalds #include <linux/string.h> 351da177e4SLinus Torvalds #include <linux/genhd.h> 361da177e4SLinus Torvalds #include <linux/fs.h> 371da177e4SLinus Torvalds #include <linux/init.h> 381da177e4SLinus Torvalds #include <linux/proc_fs.h> 391da177e4SLinus Torvalds #include <linux/vmalloc.h> 401da177e4SLinus Torvalds #include <linux/moduleparam.h> 41852e034dSJens Axboe #include <linux/scatterlist.h> 421da177e4SLinus Torvalds #include <linux/blkdev.h> 439ff26eefSFUJITA Tomonori 449ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 459ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 469ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 471da177e4SLinus Torvalds #include <scsi/scsi_host.h> 481da177e4SLinus Torvalds #include <scsi/scsicam.h> 49a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 501da177e4SLinus Torvalds 511da177e4SLinus Torvalds #include <linux/stat.h> 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds #include "scsi_logging.h" 541da177e4SLinus Torvalds 556f3cbf55SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.81" 566f3cbf55SDouglas Gilbert static const char * scsi_debug_version_date = "20070104"; 571da177e4SLinus Torvalds 586f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 59c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 60c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 611da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 62c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 631da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 641da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 651da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 66c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 671da177e4SLinus Torvalds #define POWERON_RESET 0x29 681da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 696f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 70c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 71c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 721da177e4SLinus Torvalds 736f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 746f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 756f3cbf55SDouglas Gilbert 761da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 771da177e4SLinus Torvalds 781da177e4SLinus Torvalds /* Default values for driver parameters */ 791da177e4SLinus Torvalds #define DEF_NUM_HOST 1 801da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 811da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 821da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 831da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 841da177e4SLinus Torvalds */ 851da177e4SLinus Torvalds #define DEF_DELAY 1 861da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 871da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 881da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 891da177e4SLinus Torvalds #define DEF_OPTS 0 901da177e4SLinus Torvalds #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 911da177e4SLinus Torvalds #define DEF_PTYPE 0 921da177e4SLinus Torvalds #define DEF_D_SENSE 0 93c65b1445SDouglas Gilbert #define DEF_NO_LUN_0 0 94c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB 0 9523183910SDouglas Gilbert #define DEF_FAKE_RW 0 9623183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1 971da177e4SLinus Torvalds 981da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 991da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1001da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1011da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1021da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1036f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 1041da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1051da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1061da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1071da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1086f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1096f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1101da177e4SLinus Torvalds * 1111da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1121da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1131da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1141da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1156f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1166f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1171da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1181da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1191da177e4SLinus Torvalds */ 1201da177e4SLinus Torvalds 1211da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1221da177e4SLinus Torvalds * sector on read commands: */ 1231da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1241da177e4SLinus Torvalds 1251da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1261da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1271da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 128c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1291da177e4SLinus Torvalds 1301da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1311da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1321da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1331da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1341da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 1351da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 1361da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1371da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1381da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1391da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1401da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 141c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 142c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 14323183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW; 14423183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 1451da177e4SLinus Torvalds 1461da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1491da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1501da177e4SLinus Torvalds 151c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 1521da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1551da177e4SLinus Torvalds may still need them */ 1561da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 1571da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 1581da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* default sector size is 512 bytes, 2**9 bytes */ 1611da177e4SLinus Torvalds #define POW2_SECT_SIZE 9 1621da177e4SLinus Torvalds #define SECT_SIZE (1 << POW2_SECT_SIZE) 1631da177e4SLinus Torvalds #define SECT_SIZE_PER(TGT) SECT_SIZE 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 1681da177e4SLinus Torvalds 1699e603ca0SFUJITA Tomonori #define SCSI_DEBUG_CANQUEUE 255 1709e603ca0SFUJITA Tomonori #define SCSI_DEBUG_MAX_CMD_LEN 16 1719e603ca0SFUJITA Tomonori 1721da177e4SLinus Torvalds struct sdebug_dev_info { 1731da177e4SLinus Torvalds struct list_head dev_list; 1741da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 1751da177e4SLinus Torvalds unsigned int channel; 1761da177e4SLinus Torvalds unsigned int target; 1771da177e4SLinus Torvalds unsigned int lun; 1781da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 179c65b1445SDouglas Gilbert unsigned int wlun; 1801da177e4SLinus Torvalds char reset; 181c65b1445SDouglas Gilbert char stopped; 1821da177e4SLinus Torvalds char used; 1831da177e4SLinus Torvalds }; 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds struct sdebug_host_info { 1861da177e4SLinus Torvalds struct list_head host_list; 1871da177e4SLinus Torvalds struct Scsi_Host *shost; 1881da177e4SLinus Torvalds struct device dev; 1891da177e4SLinus Torvalds struct list_head dev_info_list; 1901da177e4SLinus Torvalds }; 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds #define to_sdebug_host(d) \ 1931da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 1961da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds struct sdebug_queued_cmd { 2011da177e4SLinus Torvalds int in_use; 2021da177e4SLinus Torvalds struct timer_list cmnd_timer; 2031da177e4SLinus Torvalds done_funct_t done_funct; 2041da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2051da177e4SLinus Torvalds int scsi_result; 2061da177e4SLinus Torvalds }; 2071da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds static int num_aborts = 0; 2121da177e4SLinus Torvalds static int num_dev_resets = 0; 2131da177e4SLinus Torvalds static int num_bus_resets = 0; 2141da177e4SLinus Torvalds static int num_host_resets = 0; 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2171da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2201da177e4SLinus Torvalds 2211da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *); 2221da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *); 2231da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2261da177e4SLinus Torvalds .name = sdebug_proc_name, 2271da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2281da177e4SLinus Torvalds }; 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds static const int check_condition_result = 2311da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2321da177e4SLinus Torvalds 233c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 234c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 235c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 236c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 237c65b1445SDouglas Gilbert 2381da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev); 2391da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 2401da177e4SLinus Torvalds int asc, int asq); 2411da177e4SLinus Torvalds static void stop_all_queued(void); 2421da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd); 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds static int sdebug_add_adapter(void); 2451da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 2461da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void); 2471da177e4SLinus Torvalds 2481da177e4SLinus Torvalds static struct device pseudo_primary; 2491da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2501da177e4SLinus Torvalds 2513de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd, 2523de9f944SFUJITA Tomonori unsigned long long *lba, unsigned int *num) 2533de9f944SFUJITA Tomonori { 2543de9f944SFUJITA Tomonori switch (*cmd) { 2553de9f944SFUJITA Tomonori case WRITE_16: 2563de9f944SFUJITA Tomonori case READ_16: 257d5cdc989SFUJITA Tomonori *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | 258d5cdc989SFUJITA Tomonori (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | 259d5cdc989SFUJITA Tomonori (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | 260d5cdc989SFUJITA Tomonori (u64)cmd[3] << 48 | (u64)cmd[2] << 56; 261d5cdc989SFUJITA Tomonori 262d5cdc989SFUJITA Tomonori *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | 263d5cdc989SFUJITA Tomonori (u32)cmd[10] << 24; 2643de9f944SFUJITA Tomonori break; 2653de9f944SFUJITA Tomonori case WRITE_12: 2663de9f944SFUJITA Tomonori case READ_12: 267d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 268d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 269d5cdc989SFUJITA Tomonori 270d5cdc989SFUJITA Tomonori *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | 271d5cdc989SFUJITA Tomonori (u32)cmd[6] << 24; 2723de9f944SFUJITA Tomonori break; 2733de9f944SFUJITA Tomonori case WRITE_10: 2743de9f944SFUJITA Tomonori case READ_10: 275c639d14eSFUJITA Tomonori case XDWRITEREAD_10: 276d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 277d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 278d5cdc989SFUJITA Tomonori 279d5cdc989SFUJITA Tomonori *num = (u32)cmd[8] | (u32)cmd[7] << 8; 2803de9f944SFUJITA Tomonori break; 2813de9f944SFUJITA Tomonori case WRITE_6: 2823de9f944SFUJITA Tomonori case READ_6: 283d5cdc989SFUJITA Tomonori *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 284d5cdc989SFUJITA Tomonori (u32)(cmd[1] & 0x1f) << 16; 2853de9f944SFUJITA Tomonori *num = (0 == cmd[4]) ? 256 : cmd[4]; 2863de9f944SFUJITA Tomonori break; 2873de9f944SFUJITA Tomonori default: 2883de9f944SFUJITA Tomonori break; 2893de9f944SFUJITA Tomonori } 2903de9f944SFUJITA Tomonori } 2911da177e4SLinus Torvalds 2921da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 2931da177e4SLinus Torvalds { 2941da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 2951da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 2961da177e4SLinus Torvalds } 2971da177e4SLinus Torvalds return -EINVAL; 2981da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 2991da177e4SLinus Torvalds } 3001da177e4SLinus Torvalds 301c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 302c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 3031da177e4SLinus Torvalds { 3041da177e4SLinus Torvalds if (devip->reset) { 3051da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3061da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 3071da177e4SLinus Torvalds "attention: power on reset\n"); 3081da177e4SLinus Torvalds devip->reset = 0; 3091da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 3101da177e4SLinus Torvalds return check_condition_result; 3111da177e4SLinus Torvalds } 312c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 313c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 314c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 315c65b1445SDouglas Gilbert "ready: initializing command required\n"); 316c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 317c65b1445SDouglas Gilbert 0x2); 318c65b1445SDouglas Gilbert return check_condition_result; 319c65b1445SDouglas Gilbert } 3201da177e4SLinus Torvalds return 0; 3211da177e4SLinus Torvalds } 3221da177e4SLinus Torvalds 3231da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 3241da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 3251da177e4SLinus Torvalds int arr_len) 3261da177e4SLinus Torvalds { 32721a61829SFUJITA Tomonori int act_len; 328072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3291da177e4SLinus Torvalds 330072d0bb3SFUJITA Tomonori if (!sdb->length) 3311da177e4SLinus Torvalds return 0; 332072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 3331da177e4SLinus Torvalds return (DID_ERROR << 16); 33421a61829SFUJITA Tomonori 33521a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 33621a61829SFUJITA Tomonori arr, arr_len); 337072d0bb3SFUJITA Tomonori if (sdb->resid) 338072d0bb3SFUJITA Tomonori sdb->resid -= act_len; 339c65b1445SDouglas Gilbert else 34021a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 34121a61829SFUJITA Tomonori 3421da177e4SLinus Torvalds return 0; 3431da177e4SLinus Torvalds } 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 3461da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 34721a61829SFUJITA Tomonori int arr_len) 3481da177e4SLinus Torvalds { 34921a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 3501da177e4SLinus Torvalds return 0; 351072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 3521da177e4SLinus Torvalds return -1; 35321a61829SFUJITA Tomonori 35421a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3571da177e4SLinus Torvalds 3581da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 3591da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 3601da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 3611da177e4SLinus Torvalds 3625a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 3635a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 3645a09e398SHannes Reinecke const char * dev_id_str, 365c65b1445SDouglas Gilbert int dev_id_str_len) 3661da177e4SLinus Torvalds { 367c65b1445SDouglas Gilbert int num, port_a; 368c65b1445SDouglas Gilbert char b[32]; 3691da177e4SLinus Torvalds 370c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 3711da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 3721da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 3731da177e4SLinus Torvalds arr[1] = 0x1; 3741da177e4SLinus Torvalds arr[2] = 0x0; 3751da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 3761da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 3771da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 3781da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 3791da177e4SLinus Torvalds arr[3] = num; 3801da177e4SLinus Torvalds num += 4; 381c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 382c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 383c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 384c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 385c65b1445SDouglas Gilbert arr[num++] = 0x0; 386c65b1445SDouglas Gilbert arr[num++] = 0x8; 387c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 388c65b1445SDouglas Gilbert arr[num++] = 0x33; 389c65b1445SDouglas Gilbert arr[num++] = 0x33; 390c65b1445SDouglas Gilbert arr[num++] = 0x30; 391c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 392c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 393c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 394c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 395c65b1445SDouglas Gilbert /* Target relative port number */ 396c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 397c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 398c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 399c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 400c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 401c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 402c65b1445SDouglas Gilbert arr[num++] = 0x0; 403c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 404c65b1445SDouglas Gilbert } 405c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 406c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 407c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 408c65b1445SDouglas Gilbert arr[num++] = 0x0; 409c65b1445SDouglas Gilbert arr[num++] = 0x8; 410c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 411c65b1445SDouglas Gilbert arr[num++] = 0x22; 412c65b1445SDouglas Gilbert arr[num++] = 0x22; 413c65b1445SDouglas Gilbert arr[num++] = 0x20; 414c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 415c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 416c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 417c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 4185a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 4195a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 4205a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 4215a09e398SHannes Reinecke arr[num++] = 0x0; 4225a09e398SHannes Reinecke arr[num++] = 0x4; 4235a09e398SHannes Reinecke arr[num++] = 0; 4245a09e398SHannes Reinecke arr[num++] = 0; 4255a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 4265a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 427c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 428c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 429c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 430c65b1445SDouglas Gilbert arr[num++] = 0x0; 431c65b1445SDouglas Gilbert arr[num++] = 0x8; 432c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 433c65b1445SDouglas Gilbert arr[num++] = 0x22; 434c65b1445SDouglas Gilbert arr[num++] = 0x22; 435c65b1445SDouglas Gilbert arr[num++] = 0x20; 436c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 437c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 438c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 439c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 440c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 441c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 442c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 443c65b1445SDouglas Gilbert arr[num++] = 0x0; 444c65b1445SDouglas Gilbert arr[num++] = 24; 445c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 446c65b1445SDouglas Gilbert num += 12; 447c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 448c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 449c65b1445SDouglas Gilbert num += 8; 450c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 451c65b1445SDouglas Gilbert num += 4; 452c65b1445SDouglas Gilbert return num; 453c65b1445SDouglas Gilbert } 454c65b1445SDouglas Gilbert 455c65b1445SDouglas Gilbert 456c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 457c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 458c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 459c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 460c65b1445SDouglas Gilbert }; 461c65b1445SDouglas Gilbert 462c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 463c65b1445SDouglas Gilbert { 464c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 465c65b1445SDouglas Gilbert return sizeof(vpd84_data); 466c65b1445SDouglas Gilbert } 467c65b1445SDouglas Gilbert 468c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 469c65b1445SDouglas Gilbert { 470c65b1445SDouglas Gilbert int num = 0; 471c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 472c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 473c65b1445SDouglas Gilbert int plen, olen; 474c65b1445SDouglas Gilbert 475c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 476c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 477c65b1445SDouglas Gilbert arr[num++] = 0x0; 478c65b1445SDouglas Gilbert olen = strlen(na1); 479c65b1445SDouglas Gilbert plen = olen + 1; 480c65b1445SDouglas Gilbert if (plen % 4) 481c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 482c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 483c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 484c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 485c65b1445SDouglas Gilbert num += plen; 486c65b1445SDouglas Gilbert 487c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 488c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 489c65b1445SDouglas Gilbert arr[num++] = 0x0; 490c65b1445SDouglas Gilbert olen = strlen(na2); 491c65b1445SDouglas Gilbert plen = olen + 1; 492c65b1445SDouglas Gilbert if (plen % 4) 493c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 494c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 495c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 496c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 497c65b1445SDouglas Gilbert num += plen; 498c65b1445SDouglas Gilbert 499c65b1445SDouglas Gilbert return num; 500c65b1445SDouglas Gilbert } 501c65b1445SDouglas Gilbert 502c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 503c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 504c65b1445SDouglas Gilbert { 505c65b1445SDouglas Gilbert int num = 0; 506c65b1445SDouglas Gilbert int port_a, port_b; 507c65b1445SDouglas Gilbert 508c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 509c65b1445SDouglas Gilbert port_b = port_a + 1; 510c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 511c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 512c65b1445SDouglas Gilbert arr[num++] = 0x0; 513c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 514c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 515c65b1445SDouglas Gilbert num += 6; 516c65b1445SDouglas Gilbert arr[num++] = 0x0; 517c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 518c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 519c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 520c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 521c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 522c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 523c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 524c65b1445SDouglas Gilbert arr[num++] = 0x22; 525c65b1445SDouglas Gilbert arr[num++] = 0x22; 526c65b1445SDouglas Gilbert arr[num++] = 0x20; 527c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 528c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 529c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 530c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 531c65b1445SDouglas Gilbert 532c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 533c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 534c65b1445SDouglas Gilbert arr[num++] = 0x0; 535c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 536c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 537c65b1445SDouglas Gilbert num += 6; 538c65b1445SDouglas Gilbert arr[num++] = 0x0; 539c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 540c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 541c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 542c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 543c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 544c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 545c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 546c65b1445SDouglas Gilbert arr[num++] = 0x22; 547c65b1445SDouglas Gilbert arr[num++] = 0x22; 548c65b1445SDouglas Gilbert arr[num++] = 0x20; 549c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 550c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 551c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 552c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 553c65b1445SDouglas Gilbert 554c65b1445SDouglas Gilbert return num; 555c65b1445SDouglas Gilbert } 556c65b1445SDouglas Gilbert 557c65b1445SDouglas Gilbert 558c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 559c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 560c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 561c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 562c65b1445SDouglas Gilbert '1','2','3','4', 563c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 564c65b1445SDouglas Gilbert 0xec,0,0,0, 565c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 566c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 567c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 568c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 569c65b1445SDouglas Gilbert 0x53,0x41, 570c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 571c65b1445SDouglas Gilbert 0x20,0x20, 572c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 573c65b1445SDouglas Gilbert 0x10,0x80, 574c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 575c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 576c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 577c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 578c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 579c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 580c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 581c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 582c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 583c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 584c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 585c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 586c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 587c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 588c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 589c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 590c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 591c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 592c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 593c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 594c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 595c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 596c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 597c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 598c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 599c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 600c65b1445SDouglas Gilbert }; 601c65b1445SDouglas Gilbert 602c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 603c65b1445SDouglas Gilbert { 604c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 605c65b1445SDouglas Gilbert return sizeof(vpd89_data); 606c65b1445SDouglas Gilbert } 607c65b1445SDouglas Gilbert 608c65b1445SDouglas Gilbert 609c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 610c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 611c65b1445SDouglas Gilbert 0,0,0x4,0, 612c65b1445SDouglas Gilbert 0,0,0,64, 613c65b1445SDouglas Gilbert }; 614c65b1445SDouglas Gilbert 615c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 616c65b1445SDouglas Gilbert { 617c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 618c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 619c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 620c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 621c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 622c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 623c65b1445SDouglas Gilbert } 624c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 629c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 6321da177e4SLinus Torvalds struct sdebug_dev_info * devip) 6331da177e4SLinus Torvalds { 6341da177e4SLinus Torvalds unsigned char pq_pdt; 6355a09e398SHannes Reinecke unsigned char * arr; 6361da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 6375a09e398SHannes Reinecke int alloc_len, n, ret; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 6406f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 6416f3cbf55SDouglas Gilbert if (! arr) 6426f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 643c65b1445SDouglas Gilbert if (devip->wlun) 644c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 645c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 646c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 647c65b1445SDouglas Gilbert else 6481da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 6491da177e4SLinus Torvalds arr[0] = pq_pdt; 6501da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 6511da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 6521da177e4SLinus Torvalds 0); 6535a09e398SHannes Reinecke kfree(arr); 6541da177e4SLinus Torvalds return check_condition_result; 6551da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 6565a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 657c65b1445SDouglas Gilbert char lu_id_str[6]; 658c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 6591da177e4SLinus Torvalds 6605a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 6615a09e398SHannes Reinecke (devip->channel & 0x7f); 66223183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 66323183910SDouglas Gilbert host_no = 0; 664c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 665c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 666c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 667c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 668c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 6691da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 670c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 671c65b1445SDouglas Gilbert n = 4; 672c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 673c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 674c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 675c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 676c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 677c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 678c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 679c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 680c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 681c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 682c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 6831da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 684c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 6851da177e4SLinus Torvalds arr[3] = len; 686c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 6871da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 688c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 6895a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 6905a09e398SHannes Reinecke target_dev_id, lu_id_num, 6915a09e398SHannes Reinecke lu_id_str, len); 692c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 693c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 694c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 695c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 696c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 697c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 698c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 699c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 700c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 701c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 702c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 703c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 704c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 705c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 706c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 707c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 708c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 709c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 710c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 711c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 712c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 713c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 714c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 715c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 716c65b1445SDouglas Gilbert arr[2] = (n >> 8); 717c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 718c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 719c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 720c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 7211da177e4SLinus Torvalds } else { 7221da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 7231da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 7241da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 7255a09e398SHannes Reinecke kfree(arr); 7261da177e4SLinus Torvalds return check_condition_result; 7271da177e4SLinus Torvalds } 728c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 7295a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 730c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 7315a09e398SHannes Reinecke kfree(arr); 7325a09e398SHannes Reinecke return ret; 7331da177e4SLinus Torvalds } 7341da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 7351da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 7361da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 7371da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 7381da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 7395a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 7405a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 741c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 7421da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 743c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 7441da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 7451da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 7461da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 7471da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 748c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 749c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 750c65b1445SDouglas Gilbert n = 62; 7511da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 752c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 7531da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 754c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 7551da177e4SLinus Torvalds } 756c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 7575a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 7581da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 7595a09e398SHannes Reinecke kfree(arr); 7605a09e398SHannes Reinecke return ret; 7611da177e4SLinus Torvalds } 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 7641da177e4SLinus Torvalds struct sdebug_dev_info * devip) 7651da177e4SLinus Torvalds { 7661da177e4SLinus Torvalds unsigned char * sbuff; 7671da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 7681da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 769c65b1445SDouglas Gilbert int want_dsense; 7701da177e4SLinus Torvalds int len = 18; 7711da177e4SLinus Torvalds 772c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 7731da177e4SLinus Torvalds if (devip->reset == 1) 774c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 775c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 7761da177e4SLinus Torvalds sbuff = devip->sense_buff; 777c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 778c65b1445SDouglas Gilbert if (want_dsense) { 779c65b1445SDouglas Gilbert arr[0] = 0x72; 780c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 781c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 782c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 783c65b1445SDouglas Gilbert } else { 784c65b1445SDouglas Gilbert arr[0] = 0x70; 785c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 786c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 787c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 788c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 789c65b1445SDouglas Gilbert } 790c65b1445SDouglas Gilbert } else { 791c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 7921da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 7931da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 794c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 7951da177e4SLinus Torvalds arr[0] = 0x72; 7961da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 7971da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 7981da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 7991da177e4SLinus Torvalds len = 8; 800c65b1445SDouglas Gilbert } 801c65b1445SDouglas Gilbert } 802c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 8031da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 8041da177e4SLinus Torvalds } 8051da177e4SLinus Torvalds 806c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 807c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 808c65b1445SDouglas Gilbert { 809c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 810c65b1445SDouglas Gilbert int power_cond, errsts, start; 811c65b1445SDouglas Gilbert 812c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 813c65b1445SDouglas Gilbert return errsts; 814c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 815c65b1445SDouglas Gilbert if (power_cond) { 816c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 817c65b1445SDouglas Gilbert 0); 818c65b1445SDouglas Gilbert return check_condition_result; 819c65b1445SDouglas Gilbert } 820c65b1445SDouglas Gilbert start = cmd[4] & 1; 821c65b1445SDouglas Gilbert if (start == devip->stopped) 822c65b1445SDouglas Gilbert devip->stopped = !start; 823c65b1445SDouglas Gilbert return 0; 824c65b1445SDouglas Gilbert } 825c65b1445SDouglas Gilbert 82628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 82728898873SFUJITA Tomonori { 82828898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 82928898873SFUJITA Tomonori return 2048 * 1024 * scsi_debug_virtual_gb; 83028898873SFUJITA Tomonori else 83128898873SFUJITA Tomonori return sdebug_store_sectors; 83228898873SFUJITA Tomonori } 83328898873SFUJITA Tomonori 8341da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 8351da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 8361da177e4SLinus Torvalds struct sdebug_dev_info * devip) 8371da177e4SLinus Torvalds { 8381da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 839c65b1445SDouglas Gilbert unsigned int capac; 8401da177e4SLinus Torvalds int errsts; 8411da177e4SLinus Torvalds 842c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 8431da177e4SLinus Torvalds return errsts; 844c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 84528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 8461da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 847c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 848c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 8491da177e4SLinus Torvalds arr[0] = (capac >> 24); 8501da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 8511da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 8521da177e4SLinus Torvalds arr[3] = capac & 0xff; 853c65b1445SDouglas Gilbert } else { 854c65b1445SDouglas Gilbert arr[0] = 0xff; 855c65b1445SDouglas Gilbert arr[1] = 0xff; 856c65b1445SDouglas Gilbert arr[2] = 0xff; 857c65b1445SDouglas Gilbert arr[3] = 0xff; 858c65b1445SDouglas Gilbert } 8591da177e4SLinus Torvalds arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 8601da177e4SLinus Torvalds arr[7] = SECT_SIZE_PER(target) & 0xff; 8611da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 8621da177e4SLinus Torvalds } 8631da177e4SLinus Torvalds 864c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 865c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 866c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 867c65b1445SDouglas Gilbert { 868c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 869c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 870c65b1445SDouglas Gilbert unsigned long long capac; 871c65b1445SDouglas Gilbert int errsts, k, alloc_len; 872c65b1445SDouglas Gilbert 873c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 874c65b1445SDouglas Gilbert return errsts; 875c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 876c65b1445SDouglas Gilbert + cmd[13]); 877c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 87828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 879c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 880c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 881c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 882c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 883c65b1445SDouglas Gilbert arr[8] = (SECT_SIZE_PER(target) >> 24) & 0xff; 884c65b1445SDouglas Gilbert arr[9] = (SECT_SIZE_PER(target) >> 16) & 0xff; 885c65b1445SDouglas Gilbert arr[10] = (SECT_SIZE_PER(target) >> 8) & 0xff; 886c65b1445SDouglas Gilbert arr[11] = SECT_SIZE_PER(target) & 0xff; 887c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 888c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 889c65b1445SDouglas Gilbert } 890c65b1445SDouglas Gilbert 8915a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 8925a09e398SHannes Reinecke 8935a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 8945a09e398SHannes Reinecke struct sdebug_dev_info * devip) 8955a09e398SHannes Reinecke { 8965a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 8975a09e398SHannes Reinecke unsigned char * arr; 8985a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 8995a09e398SHannes Reinecke int n, ret, alen, rlen; 9005a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 9015a09e398SHannes Reinecke 9025a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 9035a09e398SHannes Reinecke + cmd[9]); 9045a09e398SHannes Reinecke 9056f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 9066f3cbf55SDouglas Gilbert if (! arr) 9076f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 9085a09e398SHannes Reinecke /* 9095a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 9105a09e398SHannes Reinecke * real and a fake port with no device connected. 9115a09e398SHannes Reinecke * So we create two port groups with one port each 9125a09e398SHannes Reinecke * and set the group with port B to unavailable. 9135a09e398SHannes Reinecke */ 9145a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 9155a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 9165a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 9175a09e398SHannes Reinecke (devip->channel & 0x7f); 9185a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 9195a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 9205a09e398SHannes Reinecke 9215a09e398SHannes Reinecke /* 9225a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 9235a09e398SHannes Reinecke */ 9245a09e398SHannes Reinecke n = 4; 9255a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 9265a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 9275a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 9285a09e398SHannes Reinecke } else { 9295a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 9305a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 9315a09e398SHannes Reinecke } 9325a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 9335a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 9345a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9355a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 9365a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 9375a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 9385a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9395a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9405a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 9415a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 9425a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 9435a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 9445a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 9455a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 9465a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9475a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 9485a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 9495a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 9505a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9515a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9525a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 9535a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 9545a09e398SHannes Reinecke 9555a09e398SHannes Reinecke rlen = n - 4; 9565a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 9575a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 9585a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 9595a09e398SHannes Reinecke arr[3] = rlen & 0xff; 9605a09e398SHannes Reinecke 9615a09e398SHannes Reinecke /* 9625a09e398SHannes Reinecke * Return the smallest value of either 9635a09e398SHannes Reinecke * - The allocated length 9645a09e398SHannes Reinecke * - The constructed command length 9655a09e398SHannes Reinecke * - The maximum array size 9665a09e398SHannes Reinecke */ 9675a09e398SHannes Reinecke rlen = min(alen,n); 9685a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 9695a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 9705a09e398SHannes Reinecke kfree(arr); 9715a09e398SHannes Reinecke return ret; 9725a09e398SHannes Reinecke } 9735a09e398SHannes Reinecke 9741da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 9751da177e4SLinus Torvalds 9761da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 9771da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 9781da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 9791da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 9801da177e4SLinus Torvalds 9811da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 9821da177e4SLinus Torvalds if (1 == pcontrol) 9831da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 9841da177e4SLinus Torvalds return sizeof(err_recov_pg); 9851da177e4SLinus Torvalds } 9861da177e4SLinus Torvalds 9871da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 9881da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 9891da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 9901da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 9911da177e4SLinus Torvalds 9921da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 9931da177e4SLinus Torvalds if (1 == pcontrol) 9941da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 9951da177e4SLinus Torvalds return sizeof(disconnect_pg); 9961da177e4SLinus Torvalds } 9971da177e4SLinus Torvalds 9981da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 9991da177e4SLinus Torvalds { /* Format device page for mode_sense */ 10001da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 10011da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 10021da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 10051da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 10061da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 10071da177e4SLinus Torvalds p[12] = (SECT_SIZE >> 8) & 0xff; 10081da177e4SLinus Torvalds p[13] = SECT_SIZE & 0xff; 10091da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 10101da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 10111da177e4SLinus Torvalds if (1 == pcontrol) 10121da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 10131da177e4SLinus Torvalds return sizeof(format_pg); 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 10171da177e4SLinus Torvalds { /* Caching page for mode_sense */ 10181da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 10191da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 10201da177e4SLinus Torvalds 10211da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 10221da177e4SLinus Torvalds if (1 == pcontrol) 10231da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 10241da177e4SLinus Torvalds return sizeof(caching_pg); 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 10281da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1029c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1030c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1031c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 10321da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 10331da177e4SLinus Torvalds 10341da177e4SLinus Torvalds if (scsi_debug_dsense) 10351da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1036c65b1445SDouglas Gilbert else 1037c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 10381da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 10391da177e4SLinus Torvalds if (1 == pcontrol) 1040c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1041c65b1445SDouglas Gilbert else if (2 == pcontrol) 1042c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 10431da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds 1046c65b1445SDouglas Gilbert 10471da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 10481da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1049c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 10501da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1051c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1052c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1053c65b1445SDouglas Gilbert 10541da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 10551da177e4SLinus Torvalds if (1 == pcontrol) 1056c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1057c65b1445SDouglas Gilbert else if (2 == pcontrol) 1058c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 10591da177e4SLinus Torvalds return sizeof(iec_m_pg); 10601da177e4SLinus Torvalds } 10611da177e4SLinus Torvalds 1062c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1063c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1064c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1065c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1066c65b1445SDouglas Gilbert 1067c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1068c65b1445SDouglas Gilbert if (1 == pcontrol) 1069c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1070c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1071c65b1445SDouglas Gilbert } 1072c65b1445SDouglas Gilbert 1073c65b1445SDouglas Gilbert 1074c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1075c65b1445SDouglas Gilbert int target_dev_id) 1076c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1077c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1078c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1079c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1080c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1081c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1082c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1083c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1084c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1085c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1086c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1087c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1088c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1089c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1090c65b1445SDouglas Gilbert }; 1091c65b1445SDouglas Gilbert int port_a, port_b; 1092c65b1445SDouglas Gilbert 1093c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1094c65b1445SDouglas Gilbert port_b = port_a + 1; 1095c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1096c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1097c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1098c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1099c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1100c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1101c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1102c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1103c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1104c65b1445SDouglas Gilbert if (1 == pcontrol) 1105c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1106c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1107c65b1445SDouglas Gilbert } 1108c65b1445SDouglas Gilbert 1109c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1110c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1111c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1112c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1113c65b1445SDouglas Gilbert }; 1114c65b1445SDouglas Gilbert 1115c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1116c65b1445SDouglas Gilbert if (1 == pcontrol) 1117c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1118c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1119c65b1445SDouglas Gilbert } 1120c65b1445SDouglas Gilbert 11211da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 11241da177e4SLinus Torvalds struct sdebug_dev_info * devip) 11251da177e4SLinus Torvalds { 112623183910SDouglas Gilbert unsigned char dbd, llbaa; 112723183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 11281da177e4SLinus Torvalds unsigned char dev_spec; 112923183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 11301da177e4SLinus Torvalds unsigned char * ap; 11311da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 11321da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 11331da177e4SLinus Torvalds 1134c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 11351da177e4SLinus Torvalds return errsts; 113623183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 11371da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 11381da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 11391da177e4SLinus Torvalds subpcode = cmd[3]; 11401da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 114123183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 114223183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 114323183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 114423183910SDouglas Gilbert else 114523183910SDouglas Gilbert bd_len = 0; 11461da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 11471da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 11481da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 11491da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 11501da177e4SLinus Torvalds 0); 11511da177e4SLinus Torvalds return check_condition_result; 11521da177e4SLinus Torvalds } 1153c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1154c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 115523183910SDouglas Gilbert /* set DPOFUA bit for disks */ 115623183910SDouglas Gilbert if (0 == scsi_debug_ptype) 115723183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 115823183910SDouglas Gilbert else 115923183910SDouglas Gilbert dev_spec = 0x0; 11601da177e4SLinus Torvalds if (msense_6) { 11611da177e4SLinus Torvalds arr[2] = dev_spec; 116223183910SDouglas Gilbert arr[3] = bd_len; 11631da177e4SLinus Torvalds offset = 4; 11641da177e4SLinus Torvalds } else { 11651da177e4SLinus Torvalds arr[3] = dev_spec; 116623183910SDouglas Gilbert if (16 == bd_len) 116723183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 116823183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 11691da177e4SLinus Torvalds offset = 8; 11701da177e4SLinus Torvalds } 11711da177e4SLinus Torvalds ap = arr + offset; 117228898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 117328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 117428898873SFUJITA Tomonori 117523183910SDouglas Gilbert if (8 == bd_len) { 117623183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 117723183910SDouglas Gilbert ap[0] = 0xff; 117823183910SDouglas Gilbert ap[1] = 0xff; 117923183910SDouglas Gilbert ap[2] = 0xff; 118023183910SDouglas Gilbert ap[3] = 0xff; 118123183910SDouglas Gilbert } else { 118223183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 118323183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 118423183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 118523183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 118623183910SDouglas Gilbert } 118723183910SDouglas Gilbert ap[6] = (SECT_SIZE_PER(target) >> 8) & 0xff; 118823183910SDouglas Gilbert ap[7] = SECT_SIZE_PER(target) & 0xff; 118923183910SDouglas Gilbert offset += bd_len; 119023183910SDouglas Gilbert ap = arr + offset; 119123183910SDouglas Gilbert } else if (16 == bd_len) { 119223183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 119323183910SDouglas Gilbert 119423183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 119523183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 119623183910SDouglas Gilbert ap[12] = (SECT_SIZE_PER(target) >> 24) & 0xff; 119723183910SDouglas Gilbert ap[13] = (SECT_SIZE_PER(target) >> 16) & 0xff; 119823183910SDouglas Gilbert ap[14] = (SECT_SIZE_PER(target) >> 8) & 0xff; 119923183910SDouglas Gilbert ap[15] = SECT_SIZE_PER(target) & 0xff; 120023183910SDouglas Gilbert offset += bd_len; 120123183910SDouglas Gilbert ap = arr + offset; 120223183910SDouglas Gilbert } 12031da177e4SLinus Torvalds 1204c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1205c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 12061da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 12071da177e4SLinus Torvalds 0); 12081da177e4SLinus Torvalds return check_condition_result; 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds switch (pcode) { 12111da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 12121da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 12131da177e4SLinus Torvalds offset += len; 12141da177e4SLinus Torvalds break; 12151da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 12161da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 12171da177e4SLinus Torvalds offset += len; 12181da177e4SLinus Torvalds break; 12191da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 12201da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 12211da177e4SLinus Torvalds offset += len; 12221da177e4SLinus Torvalds break; 12231da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 12241da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 12251da177e4SLinus Torvalds offset += len; 12261da177e4SLinus Torvalds break; 12271da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 12281da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 12291da177e4SLinus Torvalds offset += len; 12301da177e4SLinus Torvalds break; 1231c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1232c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1233c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1234c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1235c65b1445SDouglas Gilbert return check_condition_result; 1236c65b1445SDouglas Gilbert } 1237c65b1445SDouglas Gilbert len = 0; 1238c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1239c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1240c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1241c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1242c65b1445SDouglas Gilbert target_dev_id); 1243c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1244c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1245c65b1445SDouglas Gilbert offset += len; 1246c65b1445SDouglas Gilbert break; 12471da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 12481da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 12491da177e4SLinus Torvalds offset += len; 12501da177e4SLinus Torvalds break; 12511da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1252c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 12531da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 12541da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 12551da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 12561da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 12571da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1258c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1259c65b1445SDouglas Gilbert if (0xff == subpcode) { 1260c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1261c65b1445SDouglas Gilbert target, target_dev_id); 1262c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1263c65b1445SDouglas Gilbert } 12641da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1265c65b1445SDouglas Gilbert } else { 1266c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1267c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1268c65b1445SDouglas Gilbert return check_condition_result; 1269c65b1445SDouglas Gilbert } 12701da177e4SLinus Torvalds offset += len; 12711da177e4SLinus Torvalds break; 12721da177e4SLinus Torvalds default: 12731da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 12741da177e4SLinus Torvalds 0); 12751da177e4SLinus Torvalds return check_condition_result; 12761da177e4SLinus Torvalds } 12771da177e4SLinus Torvalds if (msense_6) 12781da177e4SLinus Torvalds arr[0] = offset - 1; 12791da177e4SLinus Torvalds else { 12801da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 12811da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 12821da177e4SLinus Torvalds } 12831da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 12841da177e4SLinus Torvalds } 12851da177e4SLinus Torvalds 1286c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1287c65b1445SDouglas Gilbert 1288c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1289c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1290c65b1445SDouglas Gilbert { 1291c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1292c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1293c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1294c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1295c65b1445SDouglas Gilbert 1296c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1297c65b1445SDouglas Gilbert return errsts; 1298c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1299c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1300c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1301c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1302c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1303c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1304c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1305c65b1445SDouglas Gilbert return check_condition_result; 1306c65b1445SDouglas Gilbert } 1307c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1308c65b1445SDouglas Gilbert if (-1 == res) 1309c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1310c65b1445SDouglas Gilbert else if ((res < param_len) && 1311c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1312c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1313c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1314c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1315c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 131623183910SDouglas Gilbert if (md_len > 2) { 1317c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1318c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1319c65b1445SDouglas Gilbert return check_condition_result; 1320c65b1445SDouglas Gilbert } 1321c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1322c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1323c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1324c65b1445SDouglas Gilbert if (ps) { 1325c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1326c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1327c65b1445SDouglas Gilbert return check_condition_result; 1328c65b1445SDouglas Gilbert } 1329c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1330c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1331c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1332c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1333c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1334c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1335c65b1445SDouglas Gilbert return check_condition_result; 1336c65b1445SDouglas Gilbert } 1337c65b1445SDouglas Gilbert switch (mpage) { 1338c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1339c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1340c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1341c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1342c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1343c65b1445SDouglas Gilbert return 0; 1344c65b1445SDouglas Gilbert } 1345c65b1445SDouglas Gilbert break; 1346c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1347c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1348c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1349c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1350c65b1445SDouglas Gilbert return 0; 1351c65b1445SDouglas Gilbert } 1352c65b1445SDouglas Gilbert break; 1353c65b1445SDouglas Gilbert default: 1354c65b1445SDouglas Gilbert break; 1355c65b1445SDouglas Gilbert } 1356c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1357c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1358c65b1445SDouglas Gilbert return check_condition_result; 1359c65b1445SDouglas Gilbert } 1360c65b1445SDouglas Gilbert 1361c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1362c65b1445SDouglas Gilbert { 1363c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1364c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1365c65b1445SDouglas Gilbert }; 1366c65b1445SDouglas Gilbert 1367c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1368c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1369c65b1445SDouglas Gilbert } 1370c65b1445SDouglas Gilbert 1371c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1372c65b1445SDouglas Gilbert { 1373c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1374c65b1445SDouglas Gilbert }; 1375c65b1445SDouglas Gilbert 1376c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1377c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1378c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1379c65b1445SDouglas Gilbert arr[5] = 0xff; 1380c65b1445SDouglas Gilbert } 1381c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1382c65b1445SDouglas Gilbert } 1383c65b1445SDouglas Gilbert 1384c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1385c65b1445SDouglas Gilbert 1386c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1387c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1388c65b1445SDouglas Gilbert { 138923183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1390c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1391c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1392c65b1445SDouglas Gilbert 1393c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1394c65b1445SDouglas Gilbert return errsts; 1395c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1396c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1397c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1398c65b1445SDouglas Gilbert if (ppc || sp) { 1399c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1400c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1401c65b1445SDouglas Gilbert return check_condition_result; 1402c65b1445SDouglas Gilbert } 1403c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1404c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 140523183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1406c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1407c65b1445SDouglas Gilbert arr[0] = pcode; 140823183910SDouglas Gilbert if (0 == subpcode) { 1409c65b1445SDouglas Gilbert switch (pcode) { 1410c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1411c65b1445SDouglas Gilbert n = 4; 1412c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1413c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1414c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1415c65b1445SDouglas Gilbert arr[3] = n - 4; 1416c65b1445SDouglas Gilbert break; 1417c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1418c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1419c65b1445SDouglas Gilbert break; 1420c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1421c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1422c65b1445SDouglas Gilbert break; 1423c65b1445SDouglas Gilbert default: 1424c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1425c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1426c65b1445SDouglas Gilbert return check_condition_result; 1427c65b1445SDouglas Gilbert } 142823183910SDouglas Gilbert } else if (0xff == subpcode) { 142923183910SDouglas Gilbert arr[0] |= 0x40; 143023183910SDouglas Gilbert arr[1] = subpcode; 143123183910SDouglas Gilbert switch (pcode) { 143223183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 143323183910SDouglas Gilbert n = 4; 143423183910SDouglas Gilbert arr[n++] = 0x0; 143523183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 143623183910SDouglas Gilbert arr[n++] = 0x0; 143723183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 143823183910SDouglas Gilbert arr[n++] = 0xd; 143923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 144023183910SDouglas Gilbert arr[n++] = 0x2f; 144123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 144223183910SDouglas Gilbert arr[3] = n - 4; 144323183910SDouglas Gilbert break; 144423183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 144523183910SDouglas Gilbert n = 4; 144623183910SDouglas Gilbert arr[n++] = 0xd; 144723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 144823183910SDouglas Gilbert arr[3] = n - 4; 144923183910SDouglas Gilbert break; 145023183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 145123183910SDouglas Gilbert n = 4; 145223183910SDouglas Gilbert arr[n++] = 0x2f; 145323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 145423183910SDouglas Gilbert arr[3] = n - 4; 145523183910SDouglas Gilbert break; 145623183910SDouglas Gilbert default: 145723183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 145823183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 145923183910SDouglas Gilbert return check_condition_result; 146023183910SDouglas Gilbert } 146123183910SDouglas Gilbert } else { 146223183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 146323183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 146423183910SDouglas Gilbert return check_condition_result; 146523183910SDouglas Gilbert } 1466c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1467c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1468c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1469c65b1445SDouglas Gilbert } 1470c65b1445SDouglas Gilbert 147119789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi, 147219789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 14731da177e4SLinus Torvalds { 1474c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 147519789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); 14761da177e4SLinus Torvalds return check_condition_result; 14771da177e4SLinus Torvalds } 1478c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1479c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 148019789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 1481c65b1445SDouglas Gilbert return check_condition_result; 1482c65b1445SDouglas Gilbert } 148319789100SFUJITA Tomonori return 0; 148419789100SFUJITA Tomonori } 148519789100SFUJITA Tomonori 148619789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd, 148719789100SFUJITA Tomonori struct sdebug_dev_info *devi, 148819789100SFUJITA Tomonori unsigned long long lba, unsigned int num, int write) 148919789100SFUJITA Tomonori { 149019789100SFUJITA Tomonori int ret; 149119789100SFUJITA Tomonori unsigned int block, rest = 0; 149219789100SFUJITA Tomonori int (*func)(struct scsi_cmnd *, unsigned char *, int); 149319789100SFUJITA Tomonori 149419789100SFUJITA Tomonori func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; 149519789100SFUJITA Tomonori 149619789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 149719789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 149819789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 149919789100SFUJITA Tomonori 150019789100SFUJITA Tomonori ret = func(scmd, fake_storep + (block * SECT_SIZE), 150119789100SFUJITA Tomonori (num - rest) * SECT_SIZE); 150219789100SFUJITA Tomonori if (!ret && rest) 150319789100SFUJITA Tomonori ret = func(scmd, fake_storep, rest * SECT_SIZE); 150419789100SFUJITA Tomonori 150519789100SFUJITA Tomonori return ret; 150619789100SFUJITA Tomonori } 150719789100SFUJITA Tomonori 150819789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 150919789100SFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 151019789100SFUJITA Tomonori { 151119789100SFUJITA Tomonori unsigned long iflags; 151219789100SFUJITA Tomonori int ret; 151319789100SFUJITA Tomonori 151419789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 151519789100SFUJITA Tomonori if (ret) 151619789100SFUJITA Tomonori return ret; 151719789100SFUJITA Tomonori 15181da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 1519c65b1445SDouglas Gilbert (lba <= OPT_MEDIUM_ERR_ADDR) && 1520c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1521c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 15221da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 15231da177e4SLinus Torvalds 0); 1524c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1525c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1526c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 1527c65b1445SDouglas Gilbert ret = OPT_MEDIUM_ERR_ADDR; 1528c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1529c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1530c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1531c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1532c65b1445SDouglas Gilbert } 15331da177e4SLinus Torvalds return check_condition_result; 15341da177e4SLinus Torvalds } 15351da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 153619789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 0); 15371da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 15381da177e4SLinus Torvalds return ret; 15391da177e4SLinus Torvalds } 15401da177e4SLinus Torvalds 1541c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 1542c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info *devip) 15431da177e4SLinus Torvalds { 15441da177e4SLinus Torvalds unsigned long iflags; 154519789100SFUJITA Tomonori int ret; 15461da177e4SLinus Torvalds 154719789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 154819789100SFUJITA Tomonori if (ret) 154919789100SFUJITA Tomonori return ret; 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 155219789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 1); 15531da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 155419789100SFUJITA Tomonori if (-1 == ret) 15551da177e4SLinus Torvalds return (DID_ERROR << 16); 155619789100SFUJITA Tomonori else if ((ret < (num * SECT_SIZE)) && 15571da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1558c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 155919789100SFUJITA Tomonori " IO sent=%d bytes\n", num * SECT_SIZE, ret); 15601da177e4SLinus Torvalds return 0; 15611da177e4SLinus Torvalds } 15621da177e4SLinus Torvalds 1563c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 15641da177e4SLinus Torvalds 15651da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 15661da177e4SLinus Torvalds struct sdebug_dev_info * devip) 15671da177e4SLinus Torvalds { 15681da177e4SLinus Torvalds unsigned int alloc_len; 1569c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 15701da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 15711da177e4SLinus Torvalds int select_report = (int)cmd[2]; 15721da177e4SLinus Torvalds struct scsi_lun *one_lun; 15731da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 1574c65b1445SDouglas Gilbert unsigned char * max_addr; 15751da177e4SLinus Torvalds 15761da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 1577c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 15781da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 15791da177e4SLinus Torvalds 0); 15801da177e4SLinus Torvalds return check_condition_result; 15811da177e4SLinus Torvalds } 15821da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 15831da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 15841da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 1585c65b1445SDouglas Gilbert if (1 == select_report) 1586c65b1445SDouglas Gilbert lun_cnt = 0; 1587c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 1588c65b1445SDouglas Gilbert --lun_cnt; 1589c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 1590c65b1445SDouglas Gilbert num = lun_cnt + wlun; 1591c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 1592c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 1593c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 1594c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 1595c65b1445SDouglas Gilbert if (n < num) { 1596c65b1445SDouglas Gilbert wlun = 0; 1597c65b1445SDouglas Gilbert lun_cnt = n; 1598c65b1445SDouglas Gilbert } 15991da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 1600c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 1601c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 1602c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 1603c65b1445SDouglas Gilbert i++, lun++) { 1604c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 16051da177e4SLinus Torvalds if (upper) 16061da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 16071da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 1608c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 16091da177e4SLinus Torvalds } 1610c65b1445SDouglas Gilbert if (wlun) { 1611c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 1612c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 1613c65b1445SDouglas Gilbert i++; 1614c65b1445SDouglas Gilbert } 1615c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 16161da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 16171da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 16181da177e4SLinus Torvalds } 16191da177e4SLinus Torvalds 1620c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 1621c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 1622c639d14eSFUJITA Tomonori { 1623c639d14eSFUJITA Tomonori int i, j, ret = -1; 1624c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 1625c639d14eSFUJITA Tomonori unsigned int offset; 1626c639d14eSFUJITA Tomonori struct scatterlist *sg; 1627c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 1628c639d14eSFUJITA Tomonori 1629c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 1630c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 1631c639d14eSFUJITA Tomonori if (!buf) 1632c639d14eSFUJITA Tomonori return ret; 1633c639d14eSFUJITA Tomonori 163421a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 1635c639d14eSFUJITA Tomonori 1636c639d14eSFUJITA Tomonori offset = 0; 1637c639d14eSFUJITA Tomonori for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { 1638c639d14eSFUJITA Tomonori kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); 1639c639d14eSFUJITA Tomonori if (!kaddr) 1640c639d14eSFUJITA Tomonori goto out; 1641c639d14eSFUJITA Tomonori 1642c639d14eSFUJITA Tomonori for (j = 0; j < sg->length; j++) 1643c639d14eSFUJITA Tomonori *(kaddr + sg->offset + j) ^= *(buf + offset + j); 1644c639d14eSFUJITA Tomonori 1645c639d14eSFUJITA Tomonori offset += sg->length; 1646c639d14eSFUJITA Tomonori kunmap_atomic(kaddr, KM_USER0); 1647c639d14eSFUJITA Tomonori } 1648c639d14eSFUJITA Tomonori ret = 0; 1649c639d14eSFUJITA Tomonori out: 1650c639d14eSFUJITA Tomonori kfree(buf); 1651c639d14eSFUJITA Tomonori 1652c639d14eSFUJITA Tomonori return ret; 1653c639d14eSFUJITA Tomonori } 1654c639d14eSFUJITA Tomonori 16551da177e4SLinus Torvalds /* When timer goes off this function is called. */ 16561da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 16571da177e4SLinus Torvalds { 16581da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 16591da177e4SLinus Torvalds unsigned long iflags; 16601da177e4SLinus Torvalds 16611da177e4SLinus Torvalds if (indx >= SCSI_DEBUG_CANQUEUE) { 16621da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 16631da177e4SLinus Torvalds "large\n"); 16641da177e4SLinus Torvalds return; 16651da177e4SLinus Torvalds } 16661da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 16671da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 16681da177e4SLinus Torvalds if (! sqcp->in_use) { 16691da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 16701da177e4SLinus Torvalds "interrupt\n"); 16711da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 16721da177e4SLinus Torvalds return; 16731da177e4SLinus Torvalds } 16741da177e4SLinus Torvalds sqcp->in_use = 0; 16751da177e4SLinus Torvalds if (sqcp->done_funct) { 16761da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 16771da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 16781da177e4SLinus Torvalds } 16791da177e4SLinus Torvalds sqcp->done_funct = NULL; 16801da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 16811da177e4SLinus Torvalds } 16821da177e4SLinus Torvalds 16831da177e4SLinus Torvalds static int scsi_debug_slave_alloc(struct scsi_device * sdp) 16841da177e4SLinus Torvalds { 16851da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1686c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 1687c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 1688c639d14eSFUJITA Tomonori set_bit(QUEUE_FLAG_BIDI, &sdp->request_queue->queue_flags); 16891da177e4SLinus Torvalds return 0; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds 16921da177e4SLinus Torvalds static int scsi_debug_slave_configure(struct scsi_device * sdp) 16931da177e4SLinus Torvalds { 16941da177e4SLinus Torvalds struct sdebug_dev_info * devip; 16951da177e4SLinus Torvalds 16961da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1697c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 1698c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 16991da177e4SLinus Torvalds if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 17001da177e4SLinus Torvalds sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 17011da177e4SLinus Torvalds devip = devInfoReg(sdp); 17026f3cbf55SDouglas Gilbert if (NULL == devip) 17036f3cbf55SDouglas Gilbert return 1; /* no resources, will be marked offline */ 17041da177e4SLinus Torvalds sdp->hostdata = devip; 17051da177e4SLinus Torvalds if (sdp->host->cmd_per_lun) 17061da177e4SLinus Torvalds scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 17071da177e4SLinus Torvalds sdp->host->cmd_per_lun); 1708c65b1445SDouglas Gilbert blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 17091da177e4SLinus Torvalds return 0; 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds 17121da177e4SLinus Torvalds static void scsi_debug_slave_destroy(struct scsi_device * sdp) 17131da177e4SLinus Torvalds { 17141da177e4SLinus Torvalds struct sdebug_dev_info * devip = 17151da177e4SLinus Torvalds (struct sdebug_dev_info *)sdp->hostdata; 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 1718c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 1719c65b1445SDouglas Gilbert sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 17201da177e4SLinus Torvalds if (devip) { 17211da177e4SLinus Torvalds /* make this slot avaliable for re-use */ 17221da177e4SLinus Torvalds devip->used = 0; 17231da177e4SLinus Torvalds sdp->hostdata = NULL; 17241da177e4SLinus Torvalds } 17251da177e4SLinus Torvalds } 17261da177e4SLinus Torvalds 17275cb2fc06SFUJITA Tomonori struct sdebug_dev_info *sdebug_device_create(struct sdebug_host_info *sdbg_host, 17285cb2fc06SFUJITA Tomonori gfp_t flags) 17295cb2fc06SFUJITA Tomonori { 17305cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 17315cb2fc06SFUJITA Tomonori 17325cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 17335cb2fc06SFUJITA Tomonori if (devip) { 17345cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 17355cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 17365cb2fc06SFUJITA Tomonori } 17375cb2fc06SFUJITA Tomonori return devip; 17385cb2fc06SFUJITA Tomonori } 17395cb2fc06SFUJITA Tomonori 17401da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 17411da177e4SLinus Torvalds { 17421da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 17431da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 17441da177e4SLinus Torvalds struct sdebug_dev_info * devip = 17451da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 17461da177e4SLinus Torvalds 17471da177e4SLinus Torvalds if (devip) 17481da177e4SLinus Torvalds return devip; 1749d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 17501da177e4SLinus Torvalds if (!sdbg_host) { 17511da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 17521da177e4SLinus Torvalds return NULL; 17531da177e4SLinus Torvalds } 17541da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 17551da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 17561da177e4SLinus Torvalds (devip->target == sdev->id) && 17571da177e4SLinus Torvalds (devip->lun == sdev->lun)) 17581da177e4SLinus Torvalds return devip; 17591da177e4SLinus Torvalds else { 17601da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 17611da177e4SLinus Torvalds open_devip = devip; 17621da177e4SLinus Torvalds } 17631da177e4SLinus Torvalds } 17645cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 17655cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 17665cb2fc06SFUJITA Tomonori if (!open_devip) { 17671da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 17681da177e4SLinus Torvalds __FUNCTION__, __LINE__); 17691da177e4SLinus Torvalds return NULL; 17701da177e4SLinus Torvalds } 17711da177e4SLinus Torvalds } 1772a75869d1SFUJITA Tomonori 17731da177e4SLinus Torvalds open_devip->channel = sdev->channel; 17741da177e4SLinus Torvalds open_devip->target = sdev->id; 17751da177e4SLinus Torvalds open_devip->lun = sdev->lun; 17761da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 17771da177e4SLinus Torvalds open_devip->reset = 1; 17781da177e4SLinus Torvalds open_devip->used = 1; 17791da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 17801da177e4SLinus Torvalds if (scsi_debug_dsense) 17811da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 17821da177e4SLinus Torvalds else { 17831da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 17841da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 17851da177e4SLinus Torvalds } 1786c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 1787c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 1788a75869d1SFUJITA Tomonori 17891da177e4SLinus Torvalds return open_devip; 17901da177e4SLinus Torvalds } 17911da177e4SLinus Torvalds 17921da177e4SLinus Torvalds static void mk_sense_buffer(struct sdebug_dev_info * devip, int key, 17931da177e4SLinus Torvalds int asc, int asq) 17941da177e4SLinus Torvalds { 17951da177e4SLinus Torvalds unsigned char *sbuff; 17961da177e4SLinus Torvalds 17971da177e4SLinus Torvalds sbuff = devip->sense_buff; 17981da177e4SLinus Torvalds memset(sbuff, 0, SDEBUG_SENSE_LEN); 1799a34c4e98SFUJITA Tomonori 1800a34c4e98SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 1801a34c4e98SFUJITA Tomonori 18021da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18031da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 18041da177e4SLinus Torvalds "[0x%x,0x%x,0x%x]\n", key, asc, asq); 18051da177e4SLinus Torvalds } 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 18081da177e4SLinus Torvalds { 18091da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18101da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 18111da177e4SLinus Torvalds ++num_aborts; 18121da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 18131da177e4SLinus Torvalds return SUCCESS; 18141da177e4SLinus Torvalds } 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 18171da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 18181da177e4SLinus Torvalds { 18191da177e4SLinus Torvalds int res; 18201da177e4SLinus Torvalds unsigned char *buf; 18211da177e4SLinus Torvalds 18221da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18231da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 18241da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 18251da177e4SLinus Torvalds if (buf) { 18261da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 18271da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 18281da177e4SLinus Torvalds kfree(buf); 18291da177e4SLinus Torvalds if (! res) 18301da177e4SLinus Torvalds return res; 18311da177e4SLinus Torvalds } 18321da177e4SLinus Torvalds info[0] = sdebug_heads; 18331da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 18341da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 18351da177e4SLinus Torvalds return 0; 18361da177e4SLinus Torvalds } 18371da177e4SLinus Torvalds 18381da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 18391da177e4SLinus Torvalds { 18401da177e4SLinus Torvalds struct sdebug_dev_info * devip; 18411da177e4SLinus Torvalds 18421da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18431da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 18441da177e4SLinus Torvalds ++num_dev_resets; 18451da177e4SLinus Torvalds if (SCpnt) { 18461da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 18471da177e4SLinus Torvalds if (devip) 18481da177e4SLinus Torvalds devip->reset = 1; 18491da177e4SLinus Torvalds } 18501da177e4SLinus Torvalds return SUCCESS; 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 18531da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 18541da177e4SLinus Torvalds { 18551da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 18561da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 18571da177e4SLinus Torvalds struct scsi_device * sdp; 18581da177e4SLinus Torvalds struct Scsi_Host * hp; 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18611da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 18621da177e4SLinus Torvalds ++num_bus_resets; 18631da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 1864d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 18651da177e4SLinus Torvalds if (sdbg_host) { 18661da177e4SLinus Torvalds list_for_each_entry(dev_info, 18671da177e4SLinus Torvalds &sdbg_host->dev_info_list, 18681da177e4SLinus Torvalds dev_list) 18691da177e4SLinus Torvalds dev_info->reset = 1; 18701da177e4SLinus Torvalds } 18711da177e4SLinus Torvalds } 18721da177e4SLinus Torvalds return SUCCESS; 18731da177e4SLinus Torvalds } 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 18761da177e4SLinus Torvalds { 18771da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 18781da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 18791da177e4SLinus Torvalds 18801da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18811da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 18821da177e4SLinus Torvalds ++num_host_resets; 18831da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 18841da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 18851da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 18861da177e4SLinus Torvalds dev_list) 18871da177e4SLinus Torvalds dev_info->reset = 1; 18881da177e4SLinus Torvalds } 18891da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 18901da177e4SLinus Torvalds stop_all_queued(); 18911da177e4SLinus Torvalds return SUCCESS; 18921da177e4SLinus Torvalds } 18931da177e4SLinus Torvalds 18941da177e4SLinus Torvalds /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 18951da177e4SLinus Torvalds static int stop_queued_cmnd(struct scsi_cmnd * cmnd) 18961da177e4SLinus Torvalds { 18971da177e4SLinus Torvalds unsigned long iflags; 18981da177e4SLinus Torvalds int k; 18991da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 19021da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 19031da177e4SLinus Torvalds sqcp = &queued_arr[k]; 19041da177e4SLinus Torvalds if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 19051da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 19061da177e4SLinus Torvalds sqcp->in_use = 0; 19071da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 19081da177e4SLinus Torvalds break; 19091da177e4SLinus Torvalds } 19101da177e4SLinus Torvalds } 19111da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 19121da177e4SLinus Torvalds return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; 19131da177e4SLinus Torvalds } 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds /* Deletes (stops) timers of all queued commands */ 19161da177e4SLinus Torvalds static void stop_all_queued(void) 19171da177e4SLinus Torvalds { 19181da177e4SLinus Torvalds unsigned long iflags; 19191da177e4SLinus Torvalds int k; 19201da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 19231da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 19241da177e4SLinus Torvalds sqcp = &queued_arr[k]; 19251da177e4SLinus Torvalds if (sqcp->in_use && sqcp->a_cmnd) { 19261da177e4SLinus Torvalds del_timer_sync(&sqcp->cmnd_timer); 19271da177e4SLinus Torvalds sqcp->in_use = 0; 19281da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 19291da177e4SLinus Torvalds } 19301da177e4SLinus Torvalds } 19311da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 19321da177e4SLinus Torvalds } 19331da177e4SLinus Torvalds 19341da177e4SLinus Torvalds /* Initializes timers in queued array */ 19351da177e4SLinus Torvalds static void __init init_all_queued(void) 19361da177e4SLinus Torvalds { 19371da177e4SLinus Torvalds unsigned long iflags; 19381da177e4SLinus Torvalds int k; 19391da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 19421da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 19431da177e4SLinus Torvalds sqcp = &queued_arr[k]; 19441da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 19451da177e4SLinus Torvalds sqcp->in_use = 0; 19461da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 19471da177e4SLinus Torvalds } 19481da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 19491da177e4SLinus Torvalds } 19501da177e4SLinus Torvalds 1951f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 19525f2578e5SFUJITA Tomonori unsigned long store_size) 19531da177e4SLinus Torvalds { 19541da177e4SLinus Torvalds struct partition * pp; 19551da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 19561da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 19571da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 19581da177e4SLinus Torvalds 19591da177e4SLinus Torvalds /* assume partition table already zeroed */ 1960f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 19611da177e4SLinus Torvalds return; 19621da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 19631da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 19641da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 19651da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 19661da177e4SLinus Torvalds } 1967c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 19681da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 19691da177e4SLinus Torvalds / scsi_debug_num_parts; 19701da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 19711da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 19721da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 19731da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 19741da177e4SLinus Torvalds * heads_by_sects; 19751da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 19761da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 19771da177e4SLinus Torvalds 19781da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 19791da177e4SLinus Torvalds ramp[511] = 0xAA; 19801da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 19811da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 19821da177e4SLinus Torvalds start_sec = starts[k]; 19831da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 19841da177e4SLinus Torvalds pp->boot_ind = 0; 19851da177e4SLinus Torvalds 19861da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 19871da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 19881da177e4SLinus Torvalds / sdebug_sectors_per; 19891da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 19921da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 19931da177e4SLinus Torvalds / sdebug_sectors_per; 19941da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds pp->start_sect = start_sec; 19971da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 19981da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 19991da177e4SLinus Torvalds } 20001da177e4SLinus Torvalds } 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 20031da177e4SLinus Torvalds struct sdebug_dev_info * devip, 20041da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 20051da177e4SLinus Torvalds { 20061da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 20071da177e4SLinus Torvalds if (scsi_result) { 20081da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 20091da177e4SLinus Torvalds 2010c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2011c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2012c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds } 20151da177e4SLinus Torvalds if (cmnd && devip) { 20161da177e4SLinus Torvalds /* simulate autosense by this driver */ 20171da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 20181da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 20191da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 20201da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 20211da177e4SLinus Torvalds } 20221da177e4SLinus Torvalds if (delta_jiff <= 0) { 20231da177e4SLinus Torvalds if (cmnd) 20241da177e4SLinus Torvalds cmnd->result = scsi_result; 20251da177e4SLinus Torvalds if (done) 20261da177e4SLinus Torvalds done(cmnd); 20271da177e4SLinus Torvalds return 0; 20281da177e4SLinus Torvalds } else { 20291da177e4SLinus Torvalds unsigned long iflags; 20301da177e4SLinus Torvalds int k; 20311da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 20341da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 20351da177e4SLinus Torvalds sqcp = &queued_arr[k]; 20361da177e4SLinus Torvalds if (! sqcp->in_use) 20371da177e4SLinus Torvalds break; 20381da177e4SLinus Torvalds } 20391da177e4SLinus Torvalds if (k >= SCSI_DEBUG_CANQUEUE) { 20401da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20411da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 20421da177e4SLinus Torvalds return 1; /* report busy to mid level */ 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds sqcp->in_use = 1; 20451da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 20461da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 20471da177e4SLinus Torvalds sqcp->done_funct = done; 20481da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 20491da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 20501da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 20511da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 20521da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20531da177e4SLinus Torvalds if (cmnd) 20541da177e4SLinus Torvalds cmnd->result = 0; 20551da177e4SLinus Torvalds return 0; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds } 20581da177e4SLinus Torvalds 205923183910SDouglas Gilbert /* Note: The following macros create attribute files in the 206023183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 206123183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 206223183910SDouglas Gilbert as it can when the corresponding attribute in the 206323183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 206423183910SDouglas Gilbert */ 2065c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 2066c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2067c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 2068c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2069c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 207023183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 2071c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 2072c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 2073c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2074c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 2075c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 2076c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2077c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 2078c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 207923183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 208023183910SDouglas Gilbert S_IRUGO | S_IWUSR); 20811da177e4SLinus Torvalds 20821da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 20831da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 20841da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 20851da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 20881da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2089c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 2090c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2091beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 209223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 2093c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 2094c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 20951da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2096c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 20976f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 20981da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 20991da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2100c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 210123183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 21021da177e4SLinus Torvalds 21031da177e4SLinus Torvalds 21041da177e4SLinus Torvalds static char sdebug_info[256]; 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 21071da177e4SLinus Torvalds { 21081da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 21091da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 21101da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 21111da177e4SLinus Torvalds scsi_debug_opts); 21121da177e4SLinus Torvalds return sdebug_info; 21131da177e4SLinus Torvalds } 21141da177e4SLinus Torvalds 21151da177e4SLinus Torvalds /* scsi_debug_proc_info 21161da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 21171da177e4SLinus Torvalds */ 21181da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 21191da177e4SLinus Torvalds int length, int inout) 21201da177e4SLinus Torvalds { 21211da177e4SLinus Torvalds int len, pos, begin; 21221da177e4SLinus Torvalds int orig_length; 21231da177e4SLinus Torvalds 21241da177e4SLinus Torvalds orig_length = length; 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds if (inout == 1) { 21271da177e4SLinus Torvalds char arr[16]; 21281da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 21291da177e4SLinus Torvalds 21301da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 21311da177e4SLinus Torvalds return -EACCES; 21321da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 21331da177e4SLinus Torvalds arr[minLen] = '\0'; 21341da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 21351da177e4SLinus Torvalds return -EINVAL; 21361da177e4SLinus Torvalds scsi_debug_opts = pos; 21371da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 21381da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 21391da177e4SLinus Torvalds return length; 21401da177e4SLinus Torvalds } 21411da177e4SLinus Torvalds begin = 0; 21421da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 21431da177e4SLinus Torvalds "%s [%s]\n" 21441da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 21451da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 21461da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 21471da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 21481da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 21491da177e4SLinus Torvalds "host_resets=%d\n", 21501da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 21511da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 21521da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 21531da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 21541da177e4SLinus Torvalds SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 21551da177e4SLinus Torvalds num_aborts, num_dev_resets, num_bus_resets, num_host_resets); 21561da177e4SLinus Torvalds if (pos < offset) { 21571da177e4SLinus Torvalds len = 0; 21581da177e4SLinus Torvalds begin = pos; 21591da177e4SLinus Torvalds } 21601da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 21611da177e4SLinus Torvalds len -= (offset - begin); 21621da177e4SLinus Torvalds if (len > length) 21631da177e4SLinus Torvalds len = length; 21641da177e4SLinus Torvalds return len; 21651da177e4SLinus Torvalds } 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 21681da177e4SLinus Torvalds { 21691da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 21701da177e4SLinus Torvalds } 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 21731da177e4SLinus Torvalds const char * buf, size_t count) 21741da177e4SLinus Torvalds { 21751da177e4SLinus Torvalds int delay; 21761da177e4SLinus Torvalds char work[20]; 21771da177e4SLinus Torvalds 21781da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 21791da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 21801da177e4SLinus Torvalds scsi_debug_delay = delay; 21811da177e4SLinus Torvalds return count; 21821da177e4SLinus Torvalds } 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds return -EINVAL; 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 21871da177e4SLinus Torvalds sdebug_delay_store); 21881da177e4SLinus Torvalds 21891da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 21901da177e4SLinus Torvalds { 21911da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds 21941da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 21951da177e4SLinus Torvalds const char * buf, size_t count) 21961da177e4SLinus Torvalds { 21971da177e4SLinus Torvalds int opts; 21981da177e4SLinus Torvalds char work[20]; 21991da177e4SLinus Torvalds 22001da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 22011da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 22021da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 22031da177e4SLinus Torvalds goto opts_done; 22041da177e4SLinus Torvalds } else { 22051da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 22061da177e4SLinus Torvalds goto opts_done; 22071da177e4SLinus Torvalds } 22081da177e4SLinus Torvalds } 22091da177e4SLinus Torvalds return -EINVAL; 22101da177e4SLinus Torvalds opts_done: 22111da177e4SLinus Torvalds scsi_debug_opts = opts; 22121da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 22131da177e4SLinus Torvalds return count; 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 22161da177e4SLinus Torvalds sdebug_opts_store); 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 22191da177e4SLinus Torvalds { 22201da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 22231da177e4SLinus Torvalds const char * buf, size_t count) 22241da177e4SLinus Torvalds { 22251da177e4SLinus Torvalds int n; 22261da177e4SLinus Torvalds 22271da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 22281da177e4SLinus Torvalds scsi_debug_ptype = n; 22291da177e4SLinus Torvalds return count; 22301da177e4SLinus Torvalds } 22311da177e4SLinus Torvalds return -EINVAL; 22321da177e4SLinus Torvalds } 22331da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 22341da177e4SLinus Torvalds 22351da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 22361da177e4SLinus Torvalds { 22371da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 22381da177e4SLinus Torvalds } 22391da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 22401da177e4SLinus Torvalds const char * buf, size_t count) 22411da177e4SLinus Torvalds { 22421da177e4SLinus Torvalds int n; 22431da177e4SLinus Torvalds 22441da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 22451da177e4SLinus Torvalds scsi_debug_dsense = n; 22461da177e4SLinus Torvalds return count; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds return -EINVAL; 22491da177e4SLinus Torvalds } 22501da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 22511da177e4SLinus Torvalds sdebug_dsense_store); 22521da177e4SLinus Torvalds 225323183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 225423183910SDouglas Gilbert { 225523183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 225623183910SDouglas Gilbert } 225723183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 225823183910SDouglas Gilbert const char * buf, size_t count) 225923183910SDouglas Gilbert { 226023183910SDouglas Gilbert int n; 226123183910SDouglas Gilbert 226223183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 226323183910SDouglas Gilbert scsi_debug_fake_rw = n; 226423183910SDouglas Gilbert return count; 226523183910SDouglas Gilbert } 226623183910SDouglas Gilbert return -EINVAL; 226723183910SDouglas Gilbert } 226823183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 226923183910SDouglas Gilbert sdebug_fake_rw_store); 227023183910SDouglas Gilbert 2271c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2272c65b1445SDouglas Gilbert { 2273c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2274c65b1445SDouglas Gilbert } 2275c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2276c65b1445SDouglas Gilbert const char * buf, size_t count) 2277c65b1445SDouglas Gilbert { 2278c65b1445SDouglas Gilbert int n; 2279c65b1445SDouglas Gilbert 2280c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2281c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2282c65b1445SDouglas Gilbert return count; 2283c65b1445SDouglas Gilbert } 2284c65b1445SDouglas Gilbert return -EINVAL; 2285c65b1445SDouglas Gilbert } 2286c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 2287c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 2288c65b1445SDouglas Gilbert 22891da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 22901da177e4SLinus Torvalds { 22911da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 22921da177e4SLinus Torvalds } 22931da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 22941da177e4SLinus Torvalds const char * buf, size_t count) 22951da177e4SLinus Torvalds { 22961da177e4SLinus Torvalds int n; 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 22991da177e4SLinus Torvalds scsi_debug_num_tgts = n; 23001da177e4SLinus Torvalds sdebug_max_tgts_luns(); 23011da177e4SLinus Torvalds return count; 23021da177e4SLinus Torvalds } 23031da177e4SLinus Torvalds return -EINVAL; 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 23061da177e4SLinus Torvalds sdebug_num_tgts_store); 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 23091da177e4SLinus Torvalds { 23101da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 23111da177e4SLinus Torvalds } 23121da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 23131da177e4SLinus Torvalds 23141da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 23151da177e4SLinus Torvalds { 23161da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 23171da177e4SLinus Torvalds } 23181da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 23191da177e4SLinus Torvalds 23201da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 23211da177e4SLinus Torvalds { 23221da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 23231da177e4SLinus Torvalds } 23241da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 23251da177e4SLinus Torvalds const char * buf, size_t count) 23261da177e4SLinus Torvalds { 23271da177e4SLinus Torvalds int nth; 23281da177e4SLinus Torvalds 23291da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 23301da177e4SLinus Torvalds scsi_debug_every_nth = nth; 23311da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 23321da177e4SLinus Torvalds return count; 23331da177e4SLinus Torvalds } 23341da177e4SLinus Torvalds return -EINVAL; 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 23371da177e4SLinus Torvalds sdebug_every_nth_store); 23381da177e4SLinus Torvalds 23391da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 23401da177e4SLinus Torvalds { 23411da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 23421da177e4SLinus Torvalds } 23431da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 23441da177e4SLinus Torvalds const char * buf, size_t count) 23451da177e4SLinus Torvalds { 23461da177e4SLinus Torvalds int n; 23471da177e4SLinus Torvalds 23481da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 23491da177e4SLinus Torvalds scsi_debug_max_luns = n; 23501da177e4SLinus Torvalds sdebug_max_tgts_luns(); 23511da177e4SLinus Torvalds return count; 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds return -EINVAL; 23541da177e4SLinus Torvalds } 23551da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 23561da177e4SLinus Torvalds sdebug_max_luns_store); 23571da177e4SLinus Torvalds 23581da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 23591da177e4SLinus Torvalds { 23601da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 23631da177e4SLinus Torvalds 2364c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 2365c65b1445SDouglas Gilbert { 2366c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 2367c65b1445SDouglas Gilbert } 2368c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 2369c65b1445SDouglas Gilbert const char * buf, size_t count) 2370c65b1445SDouglas Gilbert { 2371c65b1445SDouglas Gilbert int n; 2372c65b1445SDouglas Gilbert 2373c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2374c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 237528898873SFUJITA Tomonori 237628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 237728898873SFUJITA Tomonori 2378c65b1445SDouglas Gilbert return count; 2379c65b1445SDouglas Gilbert } 2380c65b1445SDouglas Gilbert return -EINVAL; 2381c65b1445SDouglas Gilbert } 2382c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 2383c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 2384c65b1445SDouglas Gilbert 23851da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 23861da177e4SLinus Torvalds { 23871da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 23881da177e4SLinus Torvalds } 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 23911da177e4SLinus Torvalds const char * buf, size_t count) 23921da177e4SLinus Torvalds { 23931da177e4SLinus Torvalds int delta_hosts; 23941da177e4SLinus Torvalds 2395f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 23961da177e4SLinus Torvalds return -EINVAL; 23971da177e4SLinus Torvalds if (delta_hosts > 0) { 23981da177e4SLinus Torvalds do { 23991da177e4SLinus Torvalds sdebug_add_adapter(); 24001da177e4SLinus Torvalds } while (--delta_hosts); 24011da177e4SLinus Torvalds } else if (delta_hosts < 0) { 24021da177e4SLinus Torvalds do { 24031da177e4SLinus Torvalds sdebug_remove_adapter(); 24041da177e4SLinus Torvalds } while (++delta_hosts); 24051da177e4SLinus Torvalds } 24061da177e4SLinus Torvalds return count; 24071da177e4SLinus Torvalds } 24081da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 24091da177e4SLinus Torvalds sdebug_add_host_store); 24101da177e4SLinus Torvalds 241123183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 241223183910SDouglas Gilbert char * buf) 241323183910SDouglas Gilbert { 241423183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 241523183910SDouglas Gilbert } 241623183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 241723183910SDouglas Gilbert const char * buf, size_t count) 241823183910SDouglas Gilbert { 241923183910SDouglas Gilbert int n; 242023183910SDouglas Gilbert 242123183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 242223183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 242323183910SDouglas Gilbert return count; 242423183910SDouglas Gilbert } 242523183910SDouglas Gilbert return -EINVAL; 242623183910SDouglas Gilbert } 242723183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 242823183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 242923183910SDouglas Gilbert 243023183910SDouglas Gilbert /* Note: The following function creates attribute files in the 243123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 243223183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 243323183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 243423183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 243523183910SDouglas Gilbert */ 24366ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 24371da177e4SLinus Torvalds { 24386ecaff7fSRandy Dunlap int ret; 24396ecaff7fSRandy Dunlap 24406ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 24416ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 24426ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 24436ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 24446ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 244523183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 24466ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 244723183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 24486ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 244923183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 24506ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 24516ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 24526ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 245323183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 245423183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 24556ecaff7fSRandy Dunlap return ret; 24561da177e4SLinus Torvalds } 24571da177e4SLinus Torvalds 24581da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 24591da177e4SLinus Torvalds { 246023183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 246123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 24621da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 24631da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 24641da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 24651da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 246623183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 246723183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 24681da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 246923183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 24701da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 24711da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 24721da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 24731da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 24741da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 24751da177e4SLinus Torvalds } 24761da177e4SLinus Torvalds 24771da177e4SLinus Torvalds static int __init scsi_debug_init(void) 24781da177e4SLinus Torvalds { 24795f2578e5SFUJITA Tomonori unsigned long sz; 24801da177e4SLinus Torvalds int host_to_add; 24811da177e4SLinus Torvalds int k; 24826ecaff7fSRandy Dunlap int ret; 24831da177e4SLinus Torvalds 24841da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 24851da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 24865f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 2487f58b0efbSFUJITA Tomonori sdebug_store_sectors = sz / SECT_SIZE; 248828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 24891da177e4SLinus Torvalds 24901da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 24911da177e4SLinus Torvalds sdebug_heads = 8; 24921da177e4SLinus Torvalds sdebug_sectors_per = 32; 24931da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 24941da177e4SLinus Torvalds sdebug_heads = 32; 24951da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 24961da177e4SLinus Torvalds sdebug_heads = 64; 24971da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 24981da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 24991da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 25001da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 25011da177e4SLinus Torvalds sdebug_heads = 255; 25021da177e4SLinus Torvalds sdebug_sectors_per = 63; 25031da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 25041da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 25051da177e4SLinus Torvalds } 25061da177e4SLinus Torvalds 25071da177e4SLinus Torvalds fake_storep = vmalloc(sz); 25081da177e4SLinus Torvalds if (NULL == fake_storep) { 25091da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 25101da177e4SLinus Torvalds return -ENOMEM; 25111da177e4SLinus Torvalds } 25121da177e4SLinus Torvalds memset(fake_storep, 0, sz); 25131da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 2514f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 25151da177e4SLinus Torvalds 25166ecaff7fSRandy Dunlap ret = device_register(&pseudo_primary); 25176ecaff7fSRandy Dunlap if (ret < 0) { 25186ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: device_register error: %d\n", 25196ecaff7fSRandy Dunlap ret); 25206ecaff7fSRandy Dunlap goto free_vm; 25216ecaff7fSRandy Dunlap } 25226ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 25236ecaff7fSRandy Dunlap if (ret < 0) { 25246ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 25256ecaff7fSRandy Dunlap ret); 25266ecaff7fSRandy Dunlap goto dev_unreg; 25276ecaff7fSRandy Dunlap } 25286ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 25296ecaff7fSRandy Dunlap if (ret < 0) { 25306ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 25316ecaff7fSRandy Dunlap ret); 25326ecaff7fSRandy Dunlap goto bus_unreg; 25336ecaff7fSRandy Dunlap } 25346ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 25356ecaff7fSRandy Dunlap if (ret < 0) { 25366ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 25376ecaff7fSRandy Dunlap ret); 25386ecaff7fSRandy Dunlap goto del_files; 25396ecaff7fSRandy Dunlap } 25401da177e4SLinus Torvalds 25416ecaff7fSRandy Dunlap init_all_queued(); 25421da177e4SLinus Torvalds 25431da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 25441da177e4SLinus Torvalds scsi_debug_add_host = 0; 25451da177e4SLinus Torvalds 25461da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 25471da177e4SLinus Torvalds if (sdebug_add_adapter()) { 25481da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 25491da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 25501da177e4SLinus Torvalds break; 25511da177e4SLinus Torvalds } 25521da177e4SLinus Torvalds } 25531da177e4SLinus Torvalds 25541da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 25551da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 25561da177e4SLinus Torvalds scsi_debug_add_host); 25571da177e4SLinus Torvalds } 25581da177e4SLinus Torvalds return 0; 25596ecaff7fSRandy Dunlap 25606ecaff7fSRandy Dunlap del_files: 25616ecaff7fSRandy Dunlap do_remove_driverfs_files(); 25626ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 25636ecaff7fSRandy Dunlap bus_unreg: 25646ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 25656ecaff7fSRandy Dunlap dev_unreg: 25666ecaff7fSRandy Dunlap device_unregister(&pseudo_primary); 25676ecaff7fSRandy Dunlap free_vm: 25686ecaff7fSRandy Dunlap vfree(fake_storep); 25696ecaff7fSRandy Dunlap 25706ecaff7fSRandy Dunlap return ret; 25711da177e4SLinus Torvalds } 25721da177e4SLinus Torvalds 25731da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 25741da177e4SLinus Torvalds { 25751da177e4SLinus Torvalds int k = scsi_debug_add_host; 25761da177e4SLinus Torvalds 25771da177e4SLinus Torvalds stop_all_queued(); 25781da177e4SLinus Torvalds for (; k; k--) 25791da177e4SLinus Torvalds sdebug_remove_adapter(); 25801da177e4SLinus Torvalds do_remove_driverfs_files(); 25811da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 25821da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 25831da177e4SLinus Torvalds device_unregister(&pseudo_primary); 25841da177e4SLinus Torvalds 25851da177e4SLinus Torvalds vfree(fake_storep); 25861da177e4SLinus Torvalds } 25871da177e4SLinus Torvalds 25881da177e4SLinus Torvalds device_initcall(scsi_debug_init); 25891da177e4SLinus Torvalds module_exit(scsi_debug_exit); 25901da177e4SLinus Torvalds 259152c1da39SAdrian Bunk static void pseudo_0_release(struct device * dev) 25921da177e4SLinus Torvalds { 25931da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25941da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); 25951da177e4SLinus Torvalds } 25961da177e4SLinus Torvalds 25971da177e4SLinus Torvalds static struct device pseudo_primary = { 25981da177e4SLinus Torvalds .bus_id = "pseudo_0", 25991da177e4SLinus Torvalds .release = pseudo_0_release, 26001da177e4SLinus Torvalds }; 26011da177e4SLinus Torvalds 26021da177e4SLinus Torvalds static int pseudo_lld_bus_match(struct device *dev, 26031da177e4SLinus Torvalds struct device_driver *dev_driver) 26041da177e4SLinus Torvalds { 26051da177e4SLinus Torvalds return 1; 26061da177e4SLinus Torvalds } 26071da177e4SLinus Torvalds 26081da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus = { 26091da177e4SLinus Torvalds .name = "pseudo", 26101da177e4SLinus Torvalds .match = pseudo_lld_bus_match, 2611bbbe3a41SRussell King .probe = sdebug_driver_probe, 2612bbbe3a41SRussell King .remove = sdebug_driver_remove, 26131da177e4SLinus Torvalds }; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 26161da177e4SLinus Torvalds { 26171da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 26181da177e4SLinus Torvalds 26191da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 26201da177e4SLinus Torvalds kfree(sdbg_host); 26211da177e4SLinus Torvalds } 26221da177e4SLinus Torvalds 26231da177e4SLinus Torvalds static int sdebug_add_adapter(void) 26241da177e4SLinus Torvalds { 26251da177e4SLinus Torvalds int k, devs_per_host; 26261da177e4SLinus Torvalds int error = 0; 26271da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 26288b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 26291da177e4SLinus Torvalds 263024669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 26311da177e4SLinus Torvalds if (NULL == sdbg_host) { 26321da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 26331da177e4SLinus Torvalds __FUNCTION__, __LINE__); 26341da177e4SLinus Torvalds return -ENOMEM; 26351da177e4SLinus Torvalds } 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 26381da177e4SLinus Torvalds 26391da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 26401da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 26415cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 26425cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 26431da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 26441da177e4SLinus Torvalds __FUNCTION__, __LINE__); 26451da177e4SLinus Torvalds error = -ENOMEM; 26461da177e4SLinus Torvalds goto clean; 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds } 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 26511da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 26521da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 26531da177e4SLinus Torvalds 26541da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 26551da177e4SLinus Torvalds sdbg_host->dev.parent = &pseudo_primary; 26561da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 26571da177e4SLinus Torvalds sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); 26581da177e4SLinus Torvalds 26591da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 26601da177e4SLinus Torvalds 26611da177e4SLinus Torvalds if (error) 26621da177e4SLinus Torvalds goto clean; 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds ++scsi_debug_add_host; 26651da177e4SLinus Torvalds return error; 26661da177e4SLinus Torvalds 26671da177e4SLinus Torvalds clean: 26688b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 26698b40228fSFUJITA Tomonori dev_list) { 26701da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 26711da177e4SLinus Torvalds kfree(sdbg_devinfo); 26721da177e4SLinus Torvalds } 26731da177e4SLinus Torvalds 26741da177e4SLinus Torvalds kfree(sdbg_host); 26751da177e4SLinus Torvalds return error; 26761da177e4SLinus Torvalds } 26771da177e4SLinus Torvalds 26781da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 26791da177e4SLinus Torvalds { 26801da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 26811da177e4SLinus Torvalds 26821da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 26831da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 26841da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 26851da177e4SLinus Torvalds struct sdebug_host_info, host_list); 26861da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 26871da177e4SLinus Torvalds } 26881da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 26891da177e4SLinus Torvalds 26901da177e4SLinus Torvalds if (!sdbg_host) 26911da177e4SLinus Torvalds return; 26921da177e4SLinus Torvalds 26931da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 26941da177e4SLinus Torvalds --scsi_debug_add_host; 26951da177e4SLinus Torvalds } 26961da177e4SLinus Torvalds 2697639db475SFUJITA Tomonori static 2698639db475SFUJITA Tomonori int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) 2699639db475SFUJITA Tomonori { 2700639db475SFUJITA Tomonori unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 2701639db475SFUJITA Tomonori int len, k; 2702639db475SFUJITA Tomonori unsigned int num; 2703639db475SFUJITA Tomonori unsigned long long lba; 2704639db475SFUJITA Tomonori int errsts = 0; 2705639db475SFUJITA Tomonori int target = SCpnt->device->id; 2706639db475SFUJITA Tomonori struct sdebug_dev_info *devip = NULL; 2707639db475SFUJITA Tomonori int inj_recovered = 0; 2708639db475SFUJITA Tomonori int inj_transport = 0; 2709639db475SFUJITA Tomonori int delay_override = 0; 2710639db475SFUJITA Tomonori 2711639db475SFUJITA Tomonori scsi_set_resid(SCpnt, 0); 2712639db475SFUJITA Tomonori if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 2713639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: cmd "); 2714639db475SFUJITA Tomonori for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 2715639db475SFUJITA Tomonori printk("%02x ", (int)cmd[k]); 2716639db475SFUJITA Tomonori printk("\n"); 2717639db475SFUJITA Tomonori } 2718639db475SFUJITA Tomonori 2719639db475SFUJITA Tomonori if (target == SCpnt->device->host->hostt->this_id) { 2720639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: initiator's id used as " 2721639db475SFUJITA Tomonori "target!\n"); 2722639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2723639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2724639db475SFUJITA Tomonori } 2725639db475SFUJITA Tomonori 2726639db475SFUJITA Tomonori if ((SCpnt->device->lun >= scsi_debug_max_luns) && 2727639db475SFUJITA Tomonori (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 2728639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2729639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2730639db475SFUJITA Tomonori devip = devInfoReg(SCpnt->device); 2731639db475SFUJITA Tomonori if (NULL == devip) 2732639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2733639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2734639db475SFUJITA Tomonori 2735639db475SFUJITA Tomonori if ((scsi_debug_every_nth != 0) && 2736639db475SFUJITA Tomonori (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 2737639db475SFUJITA Tomonori scsi_debug_cmnd_count = 0; 2738639db475SFUJITA Tomonori if (scsi_debug_every_nth < -1) 2739639db475SFUJITA Tomonori scsi_debug_every_nth = -1; 2740639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 2741639db475SFUJITA Tomonori return 0; /* ignore command causing timeout */ 2742639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 2743639db475SFUJITA Tomonori inj_recovered = 1; /* to reads and writes below */ 2744639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 2745639db475SFUJITA Tomonori inj_transport = 1; /* to reads and writes below */ 2746639db475SFUJITA Tomonori } 2747639db475SFUJITA Tomonori 2748639db475SFUJITA Tomonori if (devip->wlun) { 2749639db475SFUJITA Tomonori switch (*cmd) { 2750639db475SFUJITA Tomonori case INQUIRY: 2751639db475SFUJITA Tomonori case REQUEST_SENSE: 2752639db475SFUJITA Tomonori case TEST_UNIT_READY: 2753639db475SFUJITA Tomonori case REPORT_LUNS: 2754639db475SFUJITA Tomonori break; /* only allowable wlun commands */ 2755639db475SFUJITA Tomonori default: 2756639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2757639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 2758639db475SFUJITA Tomonori "not supported for wlun\n", *cmd); 2759639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2760639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2761639db475SFUJITA Tomonori errsts = check_condition_result; 2762639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 2763639db475SFUJITA Tomonori 0); 2764639db475SFUJITA Tomonori } 2765639db475SFUJITA Tomonori } 2766639db475SFUJITA Tomonori 2767639db475SFUJITA Tomonori switch (*cmd) { 2768639db475SFUJITA Tomonori case INQUIRY: /* mandatory, ignore unit attention */ 2769639db475SFUJITA Tomonori delay_override = 1; 2770639db475SFUJITA Tomonori errsts = resp_inquiry(SCpnt, target, devip); 2771639db475SFUJITA Tomonori break; 2772639db475SFUJITA Tomonori case REQUEST_SENSE: /* mandatory, ignore unit attention */ 2773639db475SFUJITA Tomonori delay_override = 1; 2774639db475SFUJITA Tomonori errsts = resp_requests(SCpnt, devip); 2775639db475SFUJITA Tomonori break; 2776639db475SFUJITA Tomonori case REZERO_UNIT: /* actually this is REWIND for SSC */ 2777639db475SFUJITA Tomonori case START_STOP: 2778639db475SFUJITA Tomonori errsts = resp_start_stop(SCpnt, devip); 2779639db475SFUJITA Tomonori break; 2780639db475SFUJITA Tomonori case ALLOW_MEDIUM_REMOVAL: 2781639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2782639db475SFUJITA Tomonori if (errsts) 2783639db475SFUJITA Tomonori break; 2784639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2785639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Medium removal %s\n", 2786639db475SFUJITA Tomonori cmd[4] ? "inhibited" : "enabled"); 2787639db475SFUJITA Tomonori break; 2788639db475SFUJITA Tomonori case SEND_DIAGNOSTIC: /* mandatory */ 2789639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2790639db475SFUJITA Tomonori break; 2791639db475SFUJITA Tomonori case TEST_UNIT_READY: /* mandatory */ 2792639db475SFUJITA Tomonori delay_override = 1; 2793639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2794639db475SFUJITA Tomonori break; 2795639db475SFUJITA Tomonori case RESERVE: 2796639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2797639db475SFUJITA Tomonori break; 2798639db475SFUJITA Tomonori case RESERVE_10: 2799639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2800639db475SFUJITA Tomonori break; 2801639db475SFUJITA Tomonori case RELEASE: 2802639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2803639db475SFUJITA Tomonori break; 2804639db475SFUJITA Tomonori case RELEASE_10: 2805639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2806639db475SFUJITA Tomonori break; 2807639db475SFUJITA Tomonori case READ_CAPACITY: 2808639db475SFUJITA Tomonori errsts = resp_readcap(SCpnt, devip); 2809639db475SFUJITA Tomonori break; 2810639db475SFUJITA Tomonori case SERVICE_ACTION_IN: 2811639db475SFUJITA Tomonori if (SAI_READ_CAPACITY_16 != cmd[1]) { 2812639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2813639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2814639db475SFUJITA Tomonori errsts = check_condition_result; 2815639db475SFUJITA Tomonori break; 2816639db475SFUJITA Tomonori } 2817639db475SFUJITA Tomonori errsts = resp_readcap16(SCpnt, devip); 2818639db475SFUJITA Tomonori break; 2819639db475SFUJITA Tomonori case MAINTENANCE_IN: 2820639db475SFUJITA Tomonori if (MI_REPORT_TARGET_PGS != cmd[1]) { 2821639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2822639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2823639db475SFUJITA Tomonori errsts = check_condition_result; 2824639db475SFUJITA Tomonori break; 2825639db475SFUJITA Tomonori } 2826639db475SFUJITA Tomonori errsts = resp_report_tgtpgs(SCpnt, devip); 2827639db475SFUJITA Tomonori break; 2828639db475SFUJITA Tomonori case READ_16: 2829639db475SFUJITA Tomonori case READ_12: 2830639db475SFUJITA Tomonori case READ_10: 2831639db475SFUJITA Tomonori case READ_6: 2832639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2833639db475SFUJITA Tomonori if (errsts) 2834639db475SFUJITA Tomonori break; 2835639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2836639db475SFUJITA Tomonori break; 2837639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2838639db475SFUJITA Tomonori errsts = resp_read(SCpnt, lba, num, devip); 2839639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 2840639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 2841639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 2842639db475SFUJITA Tomonori errsts = check_condition_result; 2843639db475SFUJITA Tomonori } else if (inj_transport && (0 == errsts)) { 2844639db475SFUJITA Tomonori mk_sense_buffer(devip, ABORTED_COMMAND, 2845639db475SFUJITA Tomonori TRANSPORT_PROBLEM, ACK_NAK_TO); 2846639db475SFUJITA Tomonori errsts = check_condition_result; 2847639db475SFUJITA Tomonori } 2848639db475SFUJITA Tomonori break; 2849639db475SFUJITA Tomonori case REPORT_LUNS: /* mandatory, ignore unit attention */ 2850639db475SFUJITA Tomonori delay_override = 1; 2851639db475SFUJITA Tomonori errsts = resp_report_luns(SCpnt, devip); 2852639db475SFUJITA Tomonori break; 2853639db475SFUJITA Tomonori case VERIFY: /* 10 byte SBC-2 command */ 2854639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2855639db475SFUJITA Tomonori break; 2856639db475SFUJITA Tomonori case WRITE_16: 2857639db475SFUJITA Tomonori case WRITE_12: 2858639db475SFUJITA Tomonori case WRITE_10: 2859639db475SFUJITA Tomonori case WRITE_6: 2860639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2861639db475SFUJITA Tomonori if (errsts) 2862639db475SFUJITA Tomonori break; 2863639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2864639db475SFUJITA Tomonori break; 2865639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2866639db475SFUJITA Tomonori errsts = resp_write(SCpnt, lba, num, devip); 2867639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 2868639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 2869639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 2870639db475SFUJITA Tomonori errsts = check_condition_result; 2871639db475SFUJITA Tomonori } 2872639db475SFUJITA Tomonori break; 2873639db475SFUJITA Tomonori case MODE_SENSE: 2874639db475SFUJITA Tomonori case MODE_SENSE_10: 2875639db475SFUJITA Tomonori errsts = resp_mode_sense(SCpnt, target, devip); 2876639db475SFUJITA Tomonori break; 2877639db475SFUJITA Tomonori case MODE_SELECT: 2878639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 1, devip); 2879639db475SFUJITA Tomonori break; 2880639db475SFUJITA Tomonori case MODE_SELECT_10: 2881639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 0, devip); 2882639db475SFUJITA Tomonori break; 2883639db475SFUJITA Tomonori case LOG_SENSE: 2884639db475SFUJITA Tomonori errsts = resp_log_sense(SCpnt, devip); 2885639db475SFUJITA Tomonori break; 2886639db475SFUJITA Tomonori case SYNCHRONIZE_CACHE: 2887639db475SFUJITA Tomonori delay_override = 1; 2888639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2889639db475SFUJITA Tomonori break; 2890639db475SFUJITA Tomonori case WRITE_BUFFER: 2891639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2892639db475SFUJITA Tomonori break; 2893639db475SFUJITA Tomonori case XDWRITEREAD_10: 2894639db475SFUJITA Tomonori if (!scsi_bidi_cmnd(SCpnt)) { 2895639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2896639db475SFUJITA Tomonori INVALID_FIELD_IN_CDB, 0); 2897639db475SFUJITA Tomonori errsts = check_condition_result; 2898639db475SFUJITA Tomonori break; 2899639db475SFUJITA Tomonori } 2900639db475SFUJITA Tomonori 2901639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2902639db475SFUJITA Tomonori if (errsts) 2903639db475SFUJITA Tomonori break; 2904639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2905639db475SFUJITA Tomonori break; 2906639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2907639db475SFUJITA Tomonori errsts = resp_read(SCpnt, lba, num, devip); 2908639db475SFUJITA Tomonori if (errsts) 2909639db475SFUJITA Tomonori break; 2910639db475SFUJITA Tomonori errsts = resp_write(SCpnt, lba, num, devip); 2911639db475SFUJITA Tomonori if (errsts) 2912639db475SFUJITA Tomonori break; 2913639db475SFUJITA Tomonori errsts = resp_xdwriteread(SCpnt, lba, num, devip); 2914639db475SFUJITA Tomonori break; 2915639db475SFUJITA Tomonori default: 2916639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2917639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 2918639db475SFUJITA Tomonori "supported\n", *cmd); 2919639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2920639db475SFUJITA Tomonori if (errsts) 2921639db475SFUJITA Tomonori break; /* Unit attention takes precedence */ 2922639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 2923639db475SFUJITA Tomonori errsts = check_condition_result; 2924639db475SFUJITA Tomonori break; 2925639db475SFUJITA Tomonori } 2926639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 2927639db475SFUJITA Tomonori (delay_override ? 0 : scsi_debug_delay)); 2928639db475SFUJITA Tomonori } 2929639db475SFUJITA Tomonori 29309e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 29319e603ca0SFUJITA Tomonori .proc_info = scsi_debug_proc_info, 29329e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 29339e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 29349e603ca0SFUJITA Tomonori .info = scsi_debug_info, 29359e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 29369e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 29379e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 29389e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 29399e603ca0SFUJITA Tomonori .queuecommand = scsi_debug_queuecommand, 29409e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 29419e603ca0SFUJITA Tomonori .eh_bus_reset_handler = scsi_debug_bus_reset, 29429e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 29439e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 29449e603ca0SFUJITA Tomonori .bios_param = scsi_debug_biosparam, 29459e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 29469e603ca0SFUJITA Tomonori .this_id = 7, 29479e603ca0SFUJITA Tomonori .sg_tablesize = 256, 29489e603ca0SFUJITA Tomonori .cmd_per_lun = 16, 29499e603ca0SFUJITA Tomonori .max_sectors = 0xffff, 29509e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 29519e603ca0SFUJITA Tomonori .module = THIS_MODULE, 29529e603ca0SFUJITA Tomonori }; 29539e603ca0SFUJITA Tomonori 29541da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 29551da177e4SLinus Torvalds { 29561da177e4SLinus Torvalds int error = 0; 29571da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29581da177e4SLinus Torvalds struct Scsi_Host *hpnt; 29591da177e4SLinus Torvalds 29601da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29611da177e4SLinus Torvalds 29621da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 29631da177e4SLinus Torvalds if (NULL == hpnt) { 29641da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); 29651da177e4SLinus Torvalds error = -ENODEV; 29661da177e4SLinus Torvalds return error; 29671da177e4SLinus Torvalds } 29681da177e4SLinus Torvalds 29691da177e4SLinus Torvalds sdbg_host->shost = hpnt; 29701da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 29711da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 29721da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 29731da177e4SLinus Torvalds else 29741da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 2975c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 29761da177e4SLinus Torvalds 29771da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 29781da177e4SLinus Torvalds if (error) { 29791da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); 29801da177e4SLinus Torvalds error = -ENODEV; 29811da177e4SLinus Torvalds scsi_host_put(hpnt); 29821da177e4SLinus Torvalds } else 29831da177e4SLinus Torvalds scsi_scan_host(hpnt); 29841da177e4SLinus Torvalds 29851da177e4SLinus Torvalds 29861da177e4SLinus Torvalds return error; 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds 29891da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 29901da177e4SLinus Torvalds { 29911da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29928b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 29931da177e4SLinus Torvalds 29941da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29951da177e4SLinus Torvalds 29961da177e4SLinus Torvalds if (!sdbg_host) { 29971da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 29981da177e4SLinus Torvalds __FUNCTION__); 29991da177e4SLinus Torvalds return -ENODEV; 30001da177e4SLinus Torvalds } 30011da177e4SLinus Torvalds 30021da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 30031da177e4SLinus Torvalds 30048b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 30058b40228fSFUJITA Tomonori dev_list) { 30061da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 30071da177e4SLinus Torvalds kfree(sdbg_devinfo); 30081da177e4SLinus Torvalds } 30091da177e4SLinus Torvalds 30101da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 30111da177e4SLinus Torvalds return 0; 30121da177e4SLinus Torvalds } 30131da177e4SLinus Torvalds 30141da177e4SLinus Torvalds static void sdebug_max_tgts_luns(void) 30151da177e4SLinus Torvalds { 30161da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 30171da177e4SLinus Torvalds struct Scsi_Host *hpnt; 30181da177e4SLinus Torvalds 30191da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 30201da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 30211da177e4SLinus Torvalds hpnt = sdbg_host->shost; 30221da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && 30231da177e4SLinus Torvalds (scsi_debug_num_tgts > hpnt->this_id)) 30241da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 30251da177e4SLinus Torvalds else 30261da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 3027c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* scsi_debug_max_luns; */ 30281da177e4SLinus Torvalds } 30291da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 30301da177e4SLinus Torvalds } 3031