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 97597136abSMartin K. Petersen #define DEF_SECTOR_SIZE 512 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1001da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1011da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1021da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1031da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1046f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 1051da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1061da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1071da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1081da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1096f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1106f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1111da177e4SLinus Torvalds * 1121da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1131da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1141da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1151da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1166f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1176f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1181da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1191da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1201da177e4SLinus Torvalds */ 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1231da177e4SLinus Torvalds * sector on read commands: */ 1241da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1271da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1281da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 129c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1321da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1331da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1341da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1351da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 1361da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 1371da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1381da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1391da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1401da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1411da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 142c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 143c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 14423183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW; 14523183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 146597136abSMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1511da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1521da177e4SLinus Torvalds 153c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 1541da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1571da177e4SLinus Torvalds may still need them */ 1581da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 1591da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 1601da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 1651da177e4SLinus Torvalds 1669e603ca0SFUJITA Tomonori #define SCSI_DEBUG_CANQUEUE 255 1679e603ca0SFUJITA Tomonori #define SCSI_DEBUG_MAX_CMD_LEN 16 1689e603ca0SFUJITA Tomonori 1691da177e4SLinus Torvalds struct sdebug_dev_info { 1701da177e4SLinus Torvalds struct list_head dev_list; 1711da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 1721da177e4SLinus Torvalds unsigned int channel; 1731da177e4SLinus Torvalds unsigned int target; 1741da177e4SLinus Torvalds unsigned int lun; 1751da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 176c65b1445SDouglas Gilbert unsigned int wlun; 1771da177e4SLinus Torvalds char reset; 178c65b1445SDouglas Gilbert char stopped; 1791da177e4SLinus Torvalds char used; 1801da177e4SLinus Torvalds }; 1811da177e4SLinus Torvalds 1821da177e4SLinus Torvalds struct sdebug_host_info { 1831da177e4SLinus Torvalds struct list_head host_list; 1841da177e4SLinus Torvalds struct Scsi_Host *shost; 1851da177e4SLinus Torvalds struct device dev; 1861da177e4SLinus Torvalds struct list_head dev_info_list; 1871da177e4SLinus Torvalds }; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds #define to_sdebug_host(d) \ 1901da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 1911da177e4SLinus Torvalds 1921da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 1931da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds struct sdebug_queued_cmd { 1981da177e4SLinus Torvalds int in_use; 1991da177e4SLinus Torvalds struct timer_list cmnd_timer; 2001da177e4SLinus Torvalds done_funct_t done_funct; 2011da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2021da177e4SLinus Torvalds int scsi_result; 2031da177e4SLinus Torvalds }; 2041da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds static int num_aborts = 0; 2091da177e4SLinus Torvalds static int num_dev_resets = 0; 2101da177e4SLinus Torvalds static int num_bus_resets = 0; 2111da177e4SLinus Torvalds static int num_host_resets = 0; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2141da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2191da177e4SLinus Torvalds 2201da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2211da177e4SLinus Torvalds .name = sdebug_proc_name, 2221da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2231da177e4SLinus Torvalds }; 2241da177e4SLinus Torvalds 2251da177e4SLinus Torvalds static const int check_condition_result = 2261da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2271da177e4SLinus Torvalds 228c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 229c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 230c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 231c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 232c65b1445SDouglas Gilbert 2331da177e4SLinus Torvalds static int sdebug_add_adapter(void); 2341da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 2351da177e4SLinus Torvalds 2368dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 2378dea0d02SFUJITA Tomonori { 2388dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 2398dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 2408dea0d02SFUJITA Tomonori 2418dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 2428dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 2438dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 2448dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 2458dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 2468dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 2478dea0d02SFUJITA Tomonori else 2488dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 2498dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 2508dea0d02SFUJITA Tomonori hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; 2518dea0d02SFUJITA Tomonori } 2528dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 2538dea0d02SFUJITA Tomonori } 2548dea0d02SFUJITA Tomonori 2558dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, 2568dea0d02SFUJITA Tomonori int asc, int asq) 2578dea0d02SFUJITA Tomonori { 2588dea0d02SFUJITA Tomonori unsigned char *sbuff; 2598dea0d02SFUJITA Tomonori 2608dea0d02SFUJITA Tomonori sbuff = devip->sense_buff; 2618dea0d02SFUJITA Tomonori memset(sbuff, 0, SDEBUG_SENSE_LEN); 2628dea0d02SFUJITA Tomonori 2638dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 2648dea0d02SFUJITA Tomonori 2658dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2668dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 2678dea0d02SFUJITA Tomonori "[0x%x,0x%x,0x%x]\n", key, asc, asq); 2688dea0d02SFUJITA Tomonori } 2691da177e4SLinus Torvalds 2703de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd, 2713de9f944SFUJITA Tomonori unsigned long long *lba, unsigned int *num) 2723de9f944SFUJITA Tomonori { 2733de9f944SFUJITA Tomonori switch (*cmd) { 2743de9f944SFUJITA Tomonori case WRITE_16: 2753de9f944SFUJITA Tomonori case READ_16: 276d5cdc989SFUJITA Tomonori *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | 277d5cdc989SFUJITA Tomonori (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | 278d5cdc989SFUJITA Tomonori (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | 279d5cdc989SFUJITA Tomonori (u64)cmd[3] << 48 | (u64)cmd[2] << 56; 280d5cdc989SFUJITA Tomonori 281d5cdc989SFUJITA Tomonori *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | 282d5cdc989SFUJITA Tomonori (u32)cmd[10] << 24; 2833de9f944SFUJITA Tomonori break; 2843de9f944SFUJITA Tomonori case WRITE_12: 2853de9f944SFUJITA Tomonori case READ_12: 286d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 287d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 288d5cdc989SFUJITA Tomonori 289d5cdc989SFUJITA Tomonori *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | 290d5cdc989SFUJITA Tomonori (u32)cmd[6] << 24; 2913de9f944SFUJITA Tomonori break; 2923de9f944SFUJITA Tomonori case WRITE_10: 2933de9f944SFUJITA Tomonori case READ_10: 294c639d14eSFUJITA Tomonori case XDWRITEREAD_10: 295d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 296d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 297d5cdc989SFUJITA Tomonori 298d5cdc989SFUJITA Tomonori *num = (u32)cmd[8] | (u32)cmd[7] << 8; 2993de9f944SFUJITA Tomonori break; 3003de9f944SFUJITA Tomonori case WRITE_6: 3013de9f944SFUJITA Tomonori case READ_6: 302d5cdc989SFUJITA Tomonori *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 303d5cdc989SFUJITA Tomonori (u32)(cmd[1] & 0x1f) << 16; 3043de9f944SFUJITA Tomonori *num = (0 == cmd[4]) ? 256 : cmd[4]; 3053de9f944SFUJITA Tomonori break; 3063de9f944SFUJITA Tomonori default: 3073de9f944SFUJITA Tomonori break; 3083de9f944SFUJITA Tomonori } 3093de9f944SFUJITA Tomonori } 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 3121da177e4SLinus Torvalds { 3131da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 3141da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds return -EINVAL; 3171da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 3181da177e4SLinus Torvalds } 3191da177e4SLinus Torvalds 320c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 321c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 3221da177e4SLinus Torvalds { 3231da177e4SLinus Torvalds if (devip->reset) { 3241da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3251da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 3261da177e4SLinus Torvalds "attention: power on reset\n"); 3271da177e4SLinus Torvalds devip->reset = 0; 3281da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 3291da177e4SLinus Torvalds return check_condition_result; 3301da177e4SLinus Torvalds } 331c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 332c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 333c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 334c65b1445SDouglas Gilbert "ready: initializing command required\n"); 335c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 336c65b1445SDouglas Gilbert 0x2); 337c65b1445SDouglas Gilbert return check_condition_result; 338c65b1445SDouglas Gilbert } 3391da177e4SLinus Torvalds return 0; 3401da177e4SLinus Torvalds } 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 3431da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 3441da177e4SLinus Torvalds int arr_len) 3451da177e4SLinus Torvalds { 34621a61829SFUJITA Tomonori int act_len; 347072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3481da177e4SLinus Torvalds 349072d0bb3SFUJITA Tomonori if (!sdb->length) 3501da177e4SLinus Torvalds return 0; 351072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 3521da177e4SLinus Torvalds return (DID_ERROR << 16); 35321a61829SFUJITA Tomonori 35421a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 35521a61829SFUJITA Tomonori arr, arr_len); 356072d0bb3SFUJITA Tomonori if (sdb->resid) 357072d0bb3SFUJITA Tomonori sdb->resid -= act_len; 358c65b1445SDouglas Gilbert else 35921a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 36021a61829SFUJITA Tomonori 3611da177e4SLinus Torvalds return 0; 3621da177e4SLinus Torvalds } 3631da177e4SLinus Torvalds 3641da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 3651da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 36621a61829SFUJITA Tomonori int arr_len) 3671da177e4SLinus Torvalds { 36821a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 3691da177e4SLinus Torvalds return 0; 370072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 3711da177e4SLinus Torvalds return -1; 37221a61829SFUJITA Tomonori 37321a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 3741da177e4SLinus Torvalds } 3751da177e4SLinus Torvalds 3761da177e4SLinus Torvalds 3771da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 3781da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 3791da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 3801da177e4SLinus Torvalds 3815a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 3825a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 3835a09e398SHannes Reinecke const char * dev_id_str, 384c65b1445SDouglas Gilbert int dev_id_str_len) 3851da177e4SLinus Torvalds { 386c65b1445SDouglas Gilbert int num, port_a; 387c65b1445SDouglas Gilbert char b[32]; 3881da177e4SLinus Torvalds 389c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 3901da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 3911da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 3921da177e4SLinus Torvalds arr[1] = 0x1; 3931da177e4SLinus Torvalds arr[2] = 0x0; 3941da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 3951da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 3961da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 3971da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 3981da177e4SLinus Torvalds arr[3] = num; 3991da177e4SLinus Torvalds num += 4; 400c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 401c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 402c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 403c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 404c65b1445SDouglas Gilbert arr[num++] = 0x0; 405c65b1445SDouglas Gilbert arr[num++] = 0x8; 406c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 407c65b1445SDouglas Gilbert arr[num++] = 0x33; 408c65b1445SDouglas Gilbert arr[num++] = 0x33; 409c65b1445SDouglas Gilbert arr[num++] = 0x30; 410c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 411c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 412c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 413c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 414c65b1445SDouglas Gilbert /* Target relative port number */ 415c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 416c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 417c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 418c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 419c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 420c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 421c65b1445SDouglas Gilbert arr[num++] = 0x0; 422c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 423c65b1445SDouglas Gilbert } 424c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 425c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 426c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 427c65b1445SDouglas Gilbert arr[num++] = 0x0; 428c65b1445SDouglas Gilbert arr[num++] = 0x8; 429c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 430c65b1445SDouglas Gilbert arr[num++] = 0x22; 431c65b1445SDouglas Gilbert arr[num++] = 0x22; 432c65b1445SDouglas Gilbert arr[num++] = 0x20; 433c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 434c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 435c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 436c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 4375a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 4385a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 4395a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 4405a09e398SHannes Reinecke arr[num++] = 0x0; 4415a09e398SHannes Reinecke arr[num++] = 0x4; 4425a09e398SHannes Reinecke arr[num++] = 0; 4435a09e398SHannes Reinecke arr[num++] = 0; 4445a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 4455a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 446c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 447c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 448c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 449c65b1445SDouglas Gilbert arr[num++] = 0x0; 450c65b1445SDouglas Gilbert arr[num++] = 0x8; 451c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 452c65b1445SDouglas Gilbert arr[num++] = 0x22; 453c65b1445SDouglas Gilbert arr[num++] = 0x22; 454c65b1445SDouglas Gilbert arr[num++] = 0x20; 455c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 456c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 457c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 458c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 459c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 460c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 461c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 462c65b1445SDouglas Gilbert arr[num++] = 0x0; 463c65b1445SDouglas Gilbert arr[num++] = 24; 464c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 465c65b1445SDouglas Gilbert num += 12; 466c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 467c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 468c65b1445SDouglas Gilbert num += 8; 469c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 470c65b1445SDouglas Gilbert num += 4; 471c65b1445SDouglas Gilbert return num; 472c65b1445SDouglas Gilbert } 473c65b1445SDouglas Gilbert 474c65b1445SDouglas Gilbert 475c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 476c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 477c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 478c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 479c65b1445SDouglas Gilbert }; 480c65b1445SDouglas Gilbert 481c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 482c65b1445SDouglas Gilbert { 483c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 484c65b1445SDouglas Gilbert return sizeof(vpd84_data); 485c65b1445SDouglas Gilbert } 486c65b1445SDouglas Gilbert 487c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 488c65b1445SDouglas Gilbert { 489c65b1445SDouglas Gilbert int num = 0; 490c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 491c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 492c65b1445SDouglas Gilbert int plen, olen; 493c65b1445SDouglas Gilbert 494c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 495c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 496c65b1445SDouglas Gilbert arr[num++] = 0x0; 497c65b1445SDouglas Gilbert olen = strlen(na1); 498c65b1445SDouglas Gilbert plen = olen + 1; 499c65b1445SDouglas Gilbert if (plen % 4) 500c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 501c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 502c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 503c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 504c65b1445SDouglas Gilbert num += plen; 505c65b1445SDouglas Gilbert 506c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 507c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 508c65b1445SDouglas Gilbert arr[num++] = 0x0; 509c65b1445SDouglas Gilbert olen = strlen(na2); 510c65b1445SDouglas Gilbert plen = olen + 1; 511c65b1445SDouglas Gilbert if (plen % 4) 512c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 513c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 514c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 515c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 516c65b1445SDouglas Gilbert num += plen; 517c65b1445SDouglas Gilbert 518c65b1445SDouglas Gilbert return num; 519c65b1445SDouglas Gilbert } 520c65b1445SDouglas Gilbert 521c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 522c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 523c65b1445SDouglas Gilbert { 524c65b1445SDouglas Gilbert int num = 0; 525c65b1445SDouglas Gilbert int port_a, port_b; 526c65b1445SDouglas Gilbert 527c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 528c65b1445SDouglas Gilbert port_b = port_a + 1; 529c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 530c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 531c65b1445SDouglas Gilbert arr[num++] = 0x0; 532c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 533c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 534c65b1445SDouglas Gilbert num += 6; 535c65b1445SDouglas Gilbert arr[num++] = 0x0; 536c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 537c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 538c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 539c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 540c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 541c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 542c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 543c65b1445SDouglas Gilbert arr[num++] = 0x22; 544c65b1445SDouglas Gilbert arr[num++] = 0x22; 545c65b1445SDouglas Gilbert arr[num++] = 0x20; 546c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 547c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 548c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 549c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 550c65b1445SDouglas Gilbert 551c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 552c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 553c65b1445SDouglas Gilbert arr[num++] = 0x0; 554c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 555c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 556c65b1445SDouglas Gilbert num += 6; 557c65b1445SDouglas Gilbert arr[num++] = 0x0; 558c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 559c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 560c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 561c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 562c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 563c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 564c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 565c65b1445SDouglas Gilbert arr[num++] = 0x22; 566c65b1445SDouglas Gilbert arr[num++] = 0x22; 567c65b1445SDouglas Gilbert arr[num++] = 0x20; 568c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 569c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 570c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 571c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 572c65b1445SDouglas Gilbert 573c65b1445SDouglas Gilbert return num; 574c65b1445SDouglas Gilbert } 575c65b1445SDouglas Gilbert 576c65b1445SDouglas Gilbert 577c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 578c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 579c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 580c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 581c65b1445SDouglas Gilbert '1','2','3','4', 582c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 583c65b1445SDouglas Gilbert 0xec,0,0,0, 584c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 585c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 586c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 587c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 588c65b1445SDouglas Gilbert 0x53,0x41, 589c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 590c65b1445SDouglas Gilbert 0x20,0x20, 591c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 592c65b1445SDouglas Gilbert 0x10,0x80, 593c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 594c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 595c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 596c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 597c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 598c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 599c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 600c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 601c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 602c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 603c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 604c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 605c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 606c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 607c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 608c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 609c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 610c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 611c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 612c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 613c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 614c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 615c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 616c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 617c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 618c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 619c65b1445SDouglas Gilbert }; 620c65b1445SDouglas Gilbert 621c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 622c65b1445SDouglas Gilbert { 623c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 624c65b1445SDouglas Gilbert return sizeof(vpd89_data); 625c65b1445SDouglas Gilbert } 626c65b1445SDouglas Gilbert 627c65b1445SDouglas Gilbert 628c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 629c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 630c65b1445SDouglas Gilbert 0,0,0x4,0, 631c65b1445SDouglas Gilbert 0,0,0,64, 632c65b1445SDouglas Gilbert }; 633c65b1445SDouglas Gilbert 634c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 635c65b1445SDouglas Gilbert { 636c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 637c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 638c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 639c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 640c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 641c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 642c65b1445SDouglas Gilbert } 643c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 6441da177e4SLinus Torvalds } 6451da177e4SLinus Torvalds 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 648c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 6511da177e4SLinus Torvalds struct sdebug_dev_info * devip) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds unsigned char pq_pdt; 6545a09e398SHannes Reinecke unsigned char * arr; 6551da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 6565a09e398SHannes Reinecke int alloc_len, n, ret; 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 6596f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 6606f3cbf55SDouglas Gilbert if (! arr) 6616f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 662c65b1445SDouglas Gilbert if (devip->wlun) 663c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 664c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 665c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 666c65b1445SDouglas Gilbert else 6671da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 6681da177e4SLinus Torvalds arr[0] = pq_pdt; 6691da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 6701da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 6711da177e4SLinus Torvalds 0); 6725a09e398SHannes Reinecke kfree(arr); 6731da177e4SLinus Torvalds return check_condition_result; 6741da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 6755a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 676c65b1445SDouglas Gilbert char lu_id_str[6]; 677c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 6781da177e4SLinus Torvalds 6795a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 6805a09e398SHannes Reinecke (devip->channel & 0x7f); 68123183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 68223183910SDouglas Gilbert host_no = 0; 683c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 684c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 685c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 686c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 687c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 6881da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 689c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 690c65b1445SDouglas Gilbert n = 4; 691c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 692c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 693c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 694c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 695c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 696c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 697c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 698c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 699c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 700c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 701c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 7021da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 703c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 7041da177e4SLinus Torvalds arr[3] = len; 705c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 7061da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 707c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 7085a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 7095a09e398SHannes Reinecke target_dev_id, lu_id_num, 7105a09e398SHannes Reinecke lu_id_str, len); 711c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 712c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 713c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 714c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 715c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 716c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 717c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 718c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 719c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 720c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 721c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 722c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 723c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 724c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 725c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 726c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 727c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 728c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 729c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 730c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 731c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 732c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 733c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 734c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 735c65b1445SDouglas Gilbert arr[2] = (n >> 8); 736c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 737c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 738c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 739c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 7401da177e4SLinus Torvalds } else { 7411da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 7421da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 7431da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 7445a09e398SHannes Reinecke kfree(arr); 7451da177e4SLinus Torvalds return check_condition_result; 7461da177e4SLinus Torvalds } 747c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 7485a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 749c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 7505a09e398SHannes Reinecke kfree(arr); 7515a09e398SHannes Reinecke return ret; 7521da177e4SLinus Torvalds } 7531da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 7541da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 7551da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 7561da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 7571da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 7585a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 7595a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 760c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 7611da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 762c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 7631da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 7641da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 7651da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 7661da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 767c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 768c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 769c65b1445SDouglas Gilbert n = 62; 7701da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 771c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 7721da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 773c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 7741da177e4SLinus Torvalds } 775c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 7765a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 7771da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 7785a09e398SHannes Reinecke kfree(arr); 7795a09e398SHannes Reinecke return ret; 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 7831da177e4SLinus Torvalds struct sdebug_dev_info * devip) 7841da177e4SLinus Torvalds { 7851da177e4SLinus Torvalds unsigned char * sbuff; 7861da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 7871da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 788c65b1445SDouglas Gilbert int want_dsense; 7891da177e4SLinus Torvalds int len = 18; 7901da177e4SLinus Torvalds 791c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 7921da177e4SLinus Torvalds if (devip->reset == 1) 793c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 794c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 7951da177e4SLinus Torvalds sbuff = devip->sense_buff; 796c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 797c65b1445SDouglas Gilbert if (want_dsense) { 798c65b1445SDouglas Gilbert arr[0] = 0x72; 799c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 800c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 801c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 802c65b1445SDouglas Gilbert } else { 803c65b1445SDouglas Gilbert arr[0] = 0x70; 804c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 805c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 806c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 807c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 808c65b1445SDouglas Gilbert } 809c65b1445SDouglas Gilbert } else { 810c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 8111da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 8121da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 813c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 8141da177e4SLinus Torvalds arr[0] = 0x72; 8151da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 8161da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 8171da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 8181da177e4SLinus Torvalds len = 8; 819c65b1445SDouglas Gilbert } 820c65b1445SDouglas Gilbert } 821c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 8221da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 8231da177e4SLinus Torvalds } 8241da177e4SLinus Torvalds 825c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 826c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 827c65b1445SDouglas Gilbert { 828c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 829c65b1445SDouglas Gilbert int power_cond, errsts, start; 830c65b1445SDouglas Gilbert 831c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 832c65b1445SDouglas Gilbert return errsts; 833c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 834c65b1445SDouglas Gilbert if (power_cond) { 835c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 836c65b1445SDouglas Gilbert 0); 837c65b1445SDouglas Gilbert return check_condition_result; 838c65b1445SDouglas Gilbert } 839c65b1445SDouglas Gilbert start = cmd[4] & 1; 840c65b1445SDouglas Gilbert if (start == devip->stopped) 841c65b1445SDouglas Gilbert devip->stopped = !start; 842c65b1445SDouglas Gilbert return 0; 843c65b1445SDouglas Gilbert } 844c65b1445SDouglas Gilbert 84528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 84628898873SFUJITA Tomonori { 84728898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 84828898873SFUJITA Tomonori return 2048 * 1024 * scsi_debug_virtual_gb; 84928898873SFUJITA Tomonori else 85028898873SFUJITA Tomonori return sdebug_store_sectors; 85128898873SFUJITA Tomonori } 85228898873SFUJITA Tomonori 8531da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 8541da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 8551da177e4SLinus Torvalds struct sdebug_dev_info * devip) 8561da177e4SLinus Torvalds { 8571da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 858c65b1445SDouglas Gilbert unsigned int capac; 8591da177e4SLinus Torvalds int errsts; 8601da177e4SLinus Torvalds 861c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 8621da177e4SLinus Torvalds return errsts; 863c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 86428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 8651da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 866c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 867c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 8681da177e4SLinus Torvalds arr[0] = (capac >> 24); 8691da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 8701da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 8711da177e4SLinus Torvalds arr[3] = capac & 0xff; 872c65b1445SDouglas Gilbert } else { 873c65b1445SDouglas Gilbert arr[0] = 0xff; 874c65b1445SDouglas Gilbert arr[1] = 0xff; 875c65b1445SDouglas Gilbert arr[2] = 0xff; 876c65b1445SDouglas Gilbert arr[3] = 0xff; 877c65b1445SDouglas Gilbert } 878597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 879597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 8801da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 8811da177e4SLinus Torvalds } 8821da177e4SLinus Torvalds 883c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 884c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 885c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 886c65b1445SDouglas Gilbert { 887c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 888c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 889c65b1445SDouglas Gilbert unsigned long long capac; 890c65b1445SDouglas Gilbert int errsts, k, alloc_len; 891c65b1445SDouglas Gilbert 892c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 893c65b1445SDouglas Gilbert return errsts; 894c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 895c65b1445SDouglas Gilbert + cmd[13]); 896c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 89728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 898c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 899c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 900c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 901c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 902597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 903597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 904597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 905597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 906c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 907c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 908c65b1445SDouglas Gilbert } 909c65b1445SDouglas Gilbert 9105a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 9115a09e398SHannes Reinecke 9125a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 9135a09e398SHannes Reinecke struct sdebug_dev_info * devip) 9145a09e398SHannes Reinecke { 9155a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 9165a09e398SHannes Reinecke unsigned char * arr; 9175a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 9185a09e398SHannes Reinecke int n, ret, alen, rlen; 9195a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 9205a09e398SHannes Reinecke 9215a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 9225a09e398SHannes Reinecke + cmd[9]); 9235a09e398SHannes Reinecke 9246f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 9256f3cbf55SDouglas Gilbert if (! arr) 9266f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 9275a09e398SHannes Reinecke /* 9285a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 9295a09e398SHannes Reinecke * real and a fake port with no device connected. 9305a09e398SHannes Reinecke * So we create two port groups with one port each 9315a09e398SHannes Reinecke * and set the group with port B to unavailable. 9325a09e398SHannes Reinecke */ 9335a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 9345a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 9355a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 9365a09e398SHannes Reinecke (devip->channel & 0x7f); 9375a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 9385a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 9395a09e398SHannes Reinecke 9405a09e398SHannes Reinecke /* 9415a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 9425a09e398SHannes Reinecke */ 9435a09e398SHannes Reinecke n = 4; 9445a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 9455a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 9465a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 9475a09e398SHannes Reinecke } else { 9485a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 9495a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 9505a09e398SHannes Reinecke } 9515a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 9525a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 9535a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9545a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 9555a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 9565a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 9575a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9585a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9595a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 9605a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 9615a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 9625a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 9635a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 9645a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 9655a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9665a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 9675a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 9685a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 9695a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9705a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 9715a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 9725a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 9735a09e398SHannes Reinecke 9745a09e398SHannes Reinecke rlen = n - 4; 9755a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 9765a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 9775a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 9785a09e398SHannes Reinecke arr[3] = rlen & 0xff; 9795a09e398SHannes Reinecke 9805a09e398SHannes Reinecke /* 9815a09e398SHannes Reinecke * Return the smallest value of either 9825a09e398SHannes Reinecke * - The allocated length 9835a09e398SHannes Reinecke * - The constructed command length 9845a09e398SHannes Reinecke * - The maximum array size 9855a09e398SHannes Reinecke */ 9865a09e398SHannes Reinecke rlen = min(alen,n); 9875a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 9885a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 9895a09e398SHannes Reinecke kfree(arr); 9905a09e398SHannes Reinecke return ret; 9915a09e398SHannes Reinecke } 9925a09e398SHannes Reinecke 9931da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 9941da177e4SLinus Torvalds 9951da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 9961da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 9971da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 9981da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 9991da177e4SLinus Torvalds 10001da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 10011da177e4SLinus Torvalds if (1 == pcontrol) 10021da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 10031da177e4SLinus Torvalds return sizeof(err_recov_pg); 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds 10061da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 10071da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 10081da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 10091da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 10101da177e4SLinus Torvalds 10111da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 10121da177e4SLinus Torvalds if (1 == pcontrol) 10131da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 10141da177e4SLinus Torvalds return sizeof(disconnect_pg); 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds 10171da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 10181da177e4SLinus Torvalds { /* Format device page for mode_sense */ 10191da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 10201da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 10211da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 10221da177e4SLinus Torvalds 10231da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 10241da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 10251da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1026597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1027597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 10281da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 10291da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 10301da177e4SLinus Torvalds if (1 == pcontrol) 10311da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 10321da177e4SLinus Torvalds return sizeof(format_pg); 10331da177e4SLinus Torvalds } 10341da177e4SLinus Torvalds 10351da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 10361da177e4SLinus Torvalds { /* Caching page for mode_sense */ 10371da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 10381da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 10411da177e4SLinus Torvalds if (1 == pcontrol) 10421da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 10431da177e4SLinus Torvalds return sizeof(caching_pg); 10441da177e4SLinus Torvalds } 10451da177e4SLinus Torvalds 10461da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 10471da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1048c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1049c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1050c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 10511da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 10521da177e4SLinus Torvalds 10531da177e4SLinus Torvalds if (scsi_debug_dsense) 10541da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1055c65b1445SDouglas Gilbert else 1056c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 10571da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 10581da177e4SLinus Torvalds if (1 == pcontrol) 1059c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1060c65b1445SDouglas Gilbert else if (2 == pcontrol) 1061c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 10621da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 10631da177e4SLinus Torvalds } 10641da177e4SLinus Torvalds 1065c65b1445SDouglas Gilbert 10661da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 10671da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1068c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 10691da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1070c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1071c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1072c65b1445SDouglas Gilbert 10731da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 10741da177e4SLinus Torvalds if (1 == pcontrol) 1075c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1076c65b1445SDouglas Gilbert else if (2 == pcontrol) 1077c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 10781da177e4SLinus Torvalds return sizeof(iec_m_pg); 10791da177e4SLinus Torvalds } 10801da177e4SLinus Torvalds 1081c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1082c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1083c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1084c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1085c65b1445SDouglas Gilbert 1086c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1087c65b1445SDouglas Gilbert if (1 == pcontrol) 1088c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1089c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1090c65b1445SDouglas Gilbert } 1091c65b1445SDouglas Gilbert 1092c65b1445SDouglas Gilbert 1093c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1094c65b1445SDouglas Gilbert int target_dev_id) 1095c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1096c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1097c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1098c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1099c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1100c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1101c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1102c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1103c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1104c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1105c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1106c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1107c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1108c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1109c65b1445SDouglas Gilbert }; 1110c65b1445SDouglas Gilbert int port_a, port_b; 1111c65b1445SDouglas Gilbert 1112c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1113c65b1445SDouglas Gilbert port_b = port_a + 1; 1114c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1115c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1116c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1117c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1118c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1119c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1120c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1121c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1122c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1123c65b1445SDouglas Gilbert if (1 == pcontrol) 1124c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1125c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1126c65b1445SDouglas Gilbert } 1127c65b1445SDouglas Gilbert 1128c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1129c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1130c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1131c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1132c65b1445SDouglas Gilbert }; 1133c65b1445SDouglas Gilbert 1134c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1135c65b1445SDouglas Gilbert if (1 == pcontrol) 1136c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1137c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1138c65b1445SDouglas Gilbert } 1139c65b1445SDouglas Gilbert 11401da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 11411da177e4SLinus Torvalds 11421da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 11431da177e4SLinus Torvalds struct sdebug_dev_info * devip) 11441da177e4SLinus Torvalds { 114523183910SDouglas Gilbert unsigned char dbd, llbaa; 114623183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 11471da177e4SLinus Torvalds unsigned char dev_spec; 114823183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 11491da177e4SLinus Torvalds unsigned char * ap; 11501da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 11511da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 11521da177e4SLinus Torvalds 1153c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 11541da177e4SLinus Torvalds return errsts; 115523183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 11561da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 11571da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 11581da177e4SLinus Torvalds subpcode = cmd[3]; 11591da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 116023183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 116123183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 116223183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 116323183910SDouglas Gilbert else 116423183910SDouglas Gilbert bd_len = 0; 11651da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 11661da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 11671da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 11681da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 11691da177e4SLinus Torvalds 0); 11701da177e4SLinus Torvalds return check_condition_result; 11711da177e4SLinus Torvalds } 1172c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1173c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 117423183910SDouglas Gilbert /* set DPOFUA bit for disks */ 117523183910SDouglas Gilbert if (0 == scsi_debug_ptype) 117623183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 117723183910SDouglas Gilbert else 117823183910SDouglas Gilbert dev_spec = 0x0; 11791da177e4SLinus Torvalds if (msense_6) { 11801da177e4SLinus Torvalds arr[2] = dev_spec; 118123183910SDouglas Gilbert arr[3] = bd_len; 11821da177e4SLinus Torvalds offset = 4; 11831da177e4SLinus Torvalds } else { 11841da177e4SLinus Torvalds arr[3] = dev_spec; 118523183910SDouglas Gilbert if (16 == bd_len) 118623183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 118723183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 11881da177e4SLinus Torvalds offset = 8; 11891da177e4SLinus Torvalds } 11901da177e4SLinus Torvalds ap = arr + offset; 119128898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 119228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 119328898873SFUJITA Tomonori 119423183910SDouglas Gilbert if (8 == bd_len) { 119523183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 119623183910SDouglas Gilbert ap[0] = 0xff; 119723183910SDouglas Gilbert ap[1] = 0xff; 119823183910SDouglas Gilbert ap[2] = 0xff; 119923183910SDouglas Gilbert ap[3] = 0xff; 120023183910SDouglas Gilbert } else { 120123183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 120223183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 120323183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 120423183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 120523183910SDouglas Gilbert } 1206597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 1207597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 120823183910SDouglas Gilbert offset += bd_len; 120923183910SDouglas Gilbert ap = arr + offset; 121023183910SDouglas Gilbert } else if (16 == bd_len) { 121123183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 121223183910SDouglas Gilbert 121323183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 121423183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 1215597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 1216597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 1217597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 1218597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 121923183910SDouglas Gilbert offset += bd_len; 122023183910SDouglas Gilbert ap = arr + offset; 122123183910SDouglas Gilbert } 12221da177e4SLinus Torvalds 1223c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1224c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 12251da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 12261da177e4SLinus Torvalds 0); 12271da177e4SLinus Torvalds return check_condition_result; 12281da177e4SLinus Torvalds } 12291da177e4SLinus Torvalds switch (pcode) { 12301da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 12311da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 12321da177e4SLinus Torvalds offset += len; 12331da177e4SLinus Torvalds break; 12341da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 12351da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 12361da177e4SLinus Torvalds offset += len; 12371da177e4SLinus Torvalds break; 12381da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 12391da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 12401da177e4SLinus Torvalds offset += len; 12411da177e4SLinus Torvalds break; 12421da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 12431da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 12441da177e4SLinus Torvalds offset += len; 12451da177e4SLinus Torvalds break; 12461da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 12471da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 12481da177e4SLinus Torvalds offset += len; 12491da177e4SLinus Torvalds break; 1250c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1251c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1252c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1253c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1254c65b1445SDouglas Gilbert return check_condition_result; 1255c65b1445SDouglas Gilbert } 1256c65b1445SDouglas Gilbert len = 0; 1257c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1258c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1259c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1260c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1261c65b1445SDouglas Gilbert target_dev_id); 1262c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1263c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1264c65b1445SDouglas Gilbert offset += len; 1265c65b1445SDouglas Gilbert break; 12661da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 12671da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 12681da177e4SLinus Torvalds offset += len; 12691da177e4SLinus Torvalds break; 12701da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1271c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 12721da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 12731da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 12741da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 12751da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 12761da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1277c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1278c65b1445SDouglas Gilbert if (0xff == subpcode) { 1279c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1280c65b1445SDouglas Gilbert target, target_dev_id); 1281c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1282c65b1445SDouglas Gilbert } 12831da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1284c65b1445SDouglas Gilbert } else { 1285c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1286c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1287c65b1445SDouglas Gilbert return check_condition_result; 1288c65b1445SDouglas Gilbert } 12891da177e4SLinus Torvalds offset += len; 12901da177e4SLinus Torvalds break; 12911da177e4SLinus Torvalds default: 12921da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 12931da177e4SLinus Torvalds 0); 12941da177e4SLinus Torvalds return check_condition_result; 12951da177e4SLinus Torvalds } 12961da177e4SLinus Torvalds if (msense_6) 12971da177e4SLinus Torvalds arr[0] = offset - 1; 12981da177e4SLinus Torvalds else { 12991da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 13001da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 13011da177e4SLinus Torvalds } 13021da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 13031da177e4SLinus Torvalds } 13041da177e4SLinus Torvalds 1305c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1306c65b1445SDouglas Gilbert 1307c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1308c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1309c65b1445SDouglas Gilbert { 1310c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1311c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1312c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1313c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1314c65b1445SDouglas Gilbert 1315c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1316c65b1445SDouglas Gilbert return errsts; 1317c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1318c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1319c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1320c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1321c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1322c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1323c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1324c65b1445SDouglas Gilbert return check_condition_result; 1325c65b1445SDouglas Gilbert } 1326c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1327c65b1445SDouglas Gilbert if (-1 == res) 1328c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1329c65b1445SDouglas Gilbert else if ((res < param_len) && 1330c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1331c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1332c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1333c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1334c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 133523183910SDouglas Gilbert if (md_len > 2) { 1336c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1337c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1338c65b1445SDouglas Gilbert return check_condition_result; 1339c65b1445SDouglas Gilbert } 1340c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1341c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1342c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1343c65b1445SDouglas Gilbert if (ps) { 1344c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1345c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1346c65b1445SDouglas Gilbert return check_condition_result; 1347c65b1445SDouglas Gilbert } 1348c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1349c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1350c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1351c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1352c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1353c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1354c65b1445SDouglas Gilbert return check_condition_result; 1355c65b1445SDouglas Gilbert } 1356c65b1445SDouglas Gilbert switch (mpage) { 1357c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1358c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1359c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1360c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1361c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1362c65b1445SDouglas Gilbert return 0; 1363c65b1445SDouglas Gilbert } 1364c65b1445SDouglas Gilbert break; 1365c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1366c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1367c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1368c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1369c65b1445SDouglas Gilbert return 0; 1370c65b1445SDouglas Gilbert } 1371c65b1445SDouglas Gilbert break; 1372c65b1445SDouglas Gilbert default: 1373c65b1445SDouglas Gilbert break; 1374c65b1445SDouglas Gilbert } 1375c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1376c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1377c65b1445SDouglas Gilbert return check_condition_result; 1378c65b1445SDouglas Gilbert } 1379c65b1445SDouglas Gilbert 1380c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1381c65b1445SDouglas Gilbert { 1382c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1383c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1384c65b1445SDouglas Gilbert }; 1385c65b1445SDouglas Gilbert 1386c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1387c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1388c65b1445SDouglas Gilbert } 1389c65b1445SDouglas Gilbert 1390c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1391c65b1445SDouglas Gilbert { 1392c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1393c65b1445SDouglas Gilbert }; 1394c65b1445SDouglas Gilbert 1395c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1396c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1397c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1398c65b1445SDouglas Gilbert arr[5] = 0xff; 1399c65b1445SDouglas Gilbert } 1400c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1401c65b1445SDouglas Gilbert } 1402c65b1445SDouglas Gilbert 1403c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1404c65b1445SDouglas Gilbert 1405c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1406c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1407c65b1445SDouglas Gilbert { 140823183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1409c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1410c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1411c65b1445SDouglas Gilbert 1412c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1413c65b1445SDouglas Gilbert return errsts; 1414c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1415c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1416c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1417c65b1445SDouglas Gilbert if (ppc || sp) { 1418c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1419c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1420c65b1445SDouglas Gilbert return check_condition_result; 1421c65b1445SDouglas Gilbert } 1422c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1423c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 142423183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1425c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1426c65b1445SDouglas Gilbert arr[0] = pcode; 142723183910SDouglas Gilbert if (0 == subpcode) { 1428c65b1445SDouglas Gilbert switch (pcode) { 1429c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1430c65b1445SDouglas Gilbert n = 4; 1431c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1432c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1433c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1434c65b1445SDouglas Gilbert arr[3] = n - 4; 1435c65b1445SDouglas Gilbert break; 1436c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1437c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1438c65b1445SDouglas Gilbert break; 1439c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1440c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1441c65b1445SDouglas Gilbert break; 1442c65b1445SDouglas Gilbert default: 1443c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1444c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1445c65b1445SDouglas Gilbert return check_condition_result; 1446c65b1445SDouglas Gilbert } 144723183910SDouglas Gilbert } else if (0xff == subpcode) { 144823183910SDouglas Gilbert arr[0] |= 0x40; 144923183910SDouglas Gilbert arr[1] = subpcode; 145023183910SDouglas Gilbert switch (pcode) { 145123183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 145223183910SDouglas Gilbert n = 4; 145323183910SDouglas Gilbert arr[n++] = 0x0; 145423183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 145523183910SDouglas Gilbert arr[n++] = 0x0; 145623183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 145723183910SDouglas Gilbert arr[n++] = 0xd; 145823183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 145923183910SDouglas Gilbert arr[n++] = 0x2f; 146023183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 146123183910SDouglas Gilbert arr[3] = n - 4; 146223183910SDouglas Gilbert break; 146323183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 146423183910SDouglas Gilbert n = 4; 146523183910SDouglas Gilbert arr[n++] = 0xd; 146623183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 146723183910SDouglas Gilbert arr[3] = n - 4; 146823183910SDouglas Gilbert break; 146923183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 147023183910SDouglas Gilbert n = 4; 147123183910SDouglas Gilbert arr[n++] = 0x2f; 147223183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 147323183910SDouglas Gilbert arr[3] = n - 4; 147423183910SDouglas Gilbert break; 147523183910SDouglas Gilbert default: 147623183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 147723183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 147823183910SDouglas Gilbert return check_condition_result; 147923183910SDouglas Gilbert } 148023183910SDouglas Gilbert } else { 148123183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 148223183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 148323183910SDouglas Gilbert return check_condition_result; 148423183910SDouglas Gilbert } 1485c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1486c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1487c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1488c65b1445SDouglas Gilbert } 1489c65b1445SDouglas Gilbert 149019789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi, 149119789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 14921da177e4SLinus Torvalds { 1493c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 149419789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); 14951da177e4SLinus Torvalds return check_condition_result; 14961da177e4SLinus Torvalds } 1497c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1498c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 149919789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 1500c65b1445SDouglas Gilbert return check_condition_result; 1501c65b1445SDouglas Gilbert } 150219789100SFUJITA Tomonori return 0; 150319789100SFUJITA Tomonori } 150419789100SFUJITA Tomonori 150519789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd, 150619789100SFUJITA Tomonori struct sdebug_dev_info *devi, 150719789100SFUJITA Tomonori unsigned long long lba, unsigned int num, int write) 150819789100SFUJITA Tomonori { 150919789100SFUJITA Tomonori int ret; 151019789100SFUJITA Tomonori unsigned int block, rest = 0; 151119789100SFUJITA Tomonori int (*func)(struct scsi_cmnd *, unsigned char *, int); 151219789100SFUJITA Tomonori 151319789100SFUJITA Tomonori func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; 151419789100SFUJITA Tomonori 151519789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 151619789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 151719789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 151819789100SFUJITA Tomonori 1519597136abSMartin K. Petersen ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), 1520597136abSMartin K. Petersen (num - rest) * scsi_debug_sector_size); 152119789100SFUJITA Tomonori if (!ret && rest) 1522597136abSMartin K. Petersen ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); 152319789100SFUJITA Tomonori 152419789100SFUJITA Tomonori return ret; 152519789100SFUJITA Tomonori } 152619789100SFUJITA Tomonori 152719789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 152819789100SFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 152919789100SFUJITA Tomonori { 153019789100SFUJITA Tomonori unsigned long iflags; 153119789100SFUJITA Tomonori int ret; 153219789100SFUJITA Tomonori 153319789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 153419789100SFUJITA Tomonori if (ret) 153519789100SFUJITA Tomonori return ret; 153619789100SFUJITA Tomonori 15371da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 1538c65b1445SDouglas Gilbert (lba <= OPT_MEDIUM_ERR_ADDR) && 1539c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1540c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 15411da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 15421da177e4SLinus Torvalds 0); 1543c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1544c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1545c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 1546c65b1445SDouglas Gilbert ret = OPT_MEDIUM_ERR_ADDR; 1547c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1548c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1549c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1550c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1551c65b1445SDouglas Gilbert } 15521da177e4SLinus Torvalds return check_condition_result; 15531da177e4SLinus Torvalds } 15541da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 155519789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 0); 15561da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 15571da177e4SLinus Torvalds return ret; 15581da177e4SLinus Torvalds } 15591da177e4SLinus Torvalds 1560c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 1561c65b1445SDouglas Gilbert unsigned int num, struct sdebug_dev_info *devip) 15621da177e4SLinus Torvalds { 15631da177e4SLinus Torvalds unsigned long iflags; 156419789100SFUJITA Tomonori int ret; 15651da177e4SLinus Torvalds 156619789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 156719789100SFUJITA Tomonori if (ret) 156819789100SFUJITA Tomonori return ret; 15691da177e4SLinus Torvalds 15701da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 157119789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 1); 15721da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 157319789100SFUJITA Tomonori if (-1 == ret) 15741da177e4SLinus Torvalds return (DID_ERROR << 16); 1575597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 15761da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1577c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 1578597136abSMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 15791da177e4SLinus Torvalds return 0; 15801da177e4SLinus Torvalds } 15811da177e4SLinus Torvalds 1582c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 15831da177e4SLinus Torvalds 15841da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 15851da177e4SLinus Torvalds struct sdebug_dev_info * devip) 15861da177e4SLinus Torvalds { 15871da177e4SLinus Torvalds unsigned int alloc_len; 1588c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 15891da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 15901da177e4SLinus Torvalds int select_report = (int)cmd[2]; 15911da177e4SLinus Torvalds struct scsi_lun *one_lun; 15921da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 1593c65b1445SDouglas Gilbert unsigned char * max_addr; 15941da177e4SLinus Torvalds 15951da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 1596c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 15971da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 15981da177e4SLinus Torvalds 0); 15991da177e4SLinus Torvalds return check_condition_result; 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 16021da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 16031da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 1604c65b1445SDouglas Gilbert if (1 == select_report) 1605c65b1445SDouglas Gilbert lun_cnt = 0; 1606c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 1607c65b1445SDouglas Gilbert --lun_cnt; 1608c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 1609c65b1445SDouglas Gilbert num = lun_cnt + wlun; 1610c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 1611c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 1612c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 1613c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 1614c65b1445SDouglas Gilbert if (n < num) { 1615c65b1445SDouglas Gilbert wlun = 0; 1616c65b1445SDouglas Gilbert lun_cnt = n; 1617c65b1445SDouglas Gilbert } 16181da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 1619c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 1620c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 1621c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 1622c65b1445SDouglas Gilbert i++, lun++) { 1623c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 16241da177e4SLinus Torvalds if (upper) 16251da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 16261da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 1627c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 16281da177e4SLinus Torvalds } 1629c65b1445SDouglas Gilbert if (wlun) { 1630c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 1631c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 1632c65b1445SDouglas Gilbert i++; 1633c65b1445SDouglas Gilbert } 1634c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 16351da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 16361da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 16371da177e4SLinus Torvalds } 16381da177e4SLinus Torvalds 1639c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 1640c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 1641c639d14eSFUJITA Tomonori { 1642c639d14eSFUJITA Tomonori int i, j, ret = -1; 1643c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 1644c639d14eSFUJITA Tomonori unsigned int offset; 1645c639d14eSFUJITA Tomonori struct scatterlist *sg; 1646c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 1647c639d14eSFUJITA Tomonori 1648c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 1649c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 1650c639d14eSFUJITA Tomonori if (!buf) 1651c639d14eSFUJITA Tomonori return ret; 1652c639d14eSFUJITA Tomonori 165321a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 1654c639d14eSFUJITA Tomonori 1655c639d14eSFUJITA Tomonori offset = 0; 1656c639d14eSFUJITA Tomonori for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { 1657c639d14eSFUJITA Tomonori kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); 1658c639d14eSFUJITA Tomonori if (!kaddr) 1659c639d14eSFUJITA Tomonori goto out; 1660c639d14eSFUJITA Tomonori 1661c639d14eSFUJITA Tomonori for (j = 0; j < sg->length; j++) 1662c639d14eSFUJITA Tomonori *(kaddr + sg->offset + j) ^= *(buf + offset + j); 1663c639d14eSFUJITA Tomonori 1664c639d14eSFUJITA Tomonori offset += sg->length; 1665c639d14eSFUJITA Tomonori kunmap_atomic(kaddr, KM_USER0); 1666c639d14eSFUJITA Tomonori } 1667c639d14eSFUJITA Tomonori ret = 0; 1668c639d14eSFUJITA Tomonori out: 1669c639d14eSFUJITA Tomonori kfree(buf); 1670c639d14eSFUJITA Tomonori 1671c639d14eSFUJITA Tomonori return ret; 1672c639d14eSFUJITA Tomonori } 1673c639d14eSFUJITA Tomonori 16741da177e4SLinus Torvalds /* When timer goes off this function is called. */ 16751da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 16761da177e4SLinus Torvalds { 16771da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 16781da177e4SLinus Torvalds unsigned long iflags; 16791da177e4SLinus Torvalds 16801da177e4SLinus Torvalds if (indx >= SCSI_DEBUG_CANQUEUE) { 16811da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 16821da177e4SLinus Torvalds "large\n"); 16831da177e4SLinus Torvalds return; 16841da177e4SLinus Torvalds } 16851da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 16861da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 16871da177e4SLinus Torvalds if (! sqcp->in_use) { 16881da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 16891da177e4SLinus Torvalds "interrupt\n"); 16901da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 16911da177e4SLinus Torvalds return; 16921da177e4SLinus Torvalds } 16931da177e4SLinus Torvalds sqcp->in_use = 0; 16941da177e4SLinus Torvalds if (sqcp->done_funct) { 16951da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 16961da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 16971da177e4SLinus Torvalds } 16981da177e4SLinus Torvalds sqcp->done_funct = NULL; 16991da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 17001da177e4SLinus Torvalds } 17011da177e4SLinus Torvalds 17021da177e4SLinus Torvalds 17038dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 17048dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 17055cb2fc06SFUJITA Tomonori { 17065cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 17075cb2fc06SFUJITA Tomonori 17085cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 17095cb2fc06SFUJITA Tomonori if (devip) { 17105cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 17115cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 17125cb2fc06SFUJITA Tomonori } 17135cb2fc06SFUJITA Tomonori return devip; 17145cb2fc06SFUJITA Tomonori } 17155cb2fc06SFUJITA Tomonori 17161da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 17171da177e4SLinus Torvalds { 17181da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 17191da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 17201da177e4SLinus Torvalds struct sdebug_dev_info * devip = 17211da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 17221da177e4SLinus Torvalds 17231da177e4SLinus Torvalds if (devip) 17241da177e4SLinus Torvalds return devip; 1725d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 17261da177e4SLinus Torvalds if (!sdbg_host) { 17271da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 17281da177e4SLinus Torvalds return NULL; 17291da177e4SLinus Torvalds } 17301da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 17311da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 17321da177e4SLinus Torvalds (devip->target == sdev->id) && 17331da177e4SLinus Torvalds (devip->lun == sdev->lun)) 17341da177e4SLinus Torvalds return devip; 17351da177e4SLinus Torvalds else { 17361da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 17371da177e4SLinus Torvalds open_devip = devip; 17381da177e4SLinus Torvalds } 17391da177e4SLinus Torvalds } 17405cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 17415cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 17425cb2fc06SFUJITA Tomonori if (!open_devip) { 17431da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 17441da177e4SLinus Torvalds __FUNCTION__, __LINE__); 17451da177e4SLinus Torvalds return NULL; 17461da177e4SLinus Torvalds } 17471da177e4SLinus Torvalds } 1748a75869d1SFUJITA Tomonori 17491da177e4SLinus Torvalds open_devip->channel = sdev->channel; 17501da177e4SLinus Torvalds open_devip->target = sdev->id; 17511da177e4SLinus Torvalds open_devip->lun = sdev->lun; 17521da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 17531da177e4SLinus Torvalds open_devip->reset = 1; 17541da177e4SLinus Torvalds open_devip->used = 1; 17551da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 17561da177e4SLinus Torvalds if (scsi_debug_dsense) 17571da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 17581da177e4SLinus Torvalds else { 17591da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 17601da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 17611da177e4SLinus Torvalds } 1762c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 1763c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 1764a75869d1SFUJITA Tomonori 17651da177e4SLinus Torvalds return open_devip; 17661da177e4SLinus Torvalds } 17671da177e4SLinus Torvalds 17688dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 17691da177e4SLinus Torvalds { 17708dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 17718dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 17728dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 177375ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 17748dea0d02SFUJITA Tomonori return 0; 17758dea0d02SFUJITA Tomonori } 17761da177e4SLinus Torvalds 17778dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 17788dea0d02SFUJITA Tomonori { 17798dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 1780a34c4e98SFUJITA Tomonori 17811da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 17828dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 17838dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 17848dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 17858dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 17868dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 17878dea0d02SFUJITA Tomonori if (NULL == devip) 17888dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 17898dea0d02SFUJITA Tomonori sdp->hostdata = devip; 17908dea0d02SFUJITA Tomonori if (sdp->host->cmd_per_lun) 17918dea0d02SFUJITA Tomonori scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 17928dea0d02SFUJITA Tomonori sdp->host->cmd_per_lun); 17938dea0d02SFUJITA Tomonori blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 17948dea0d02SFUJITA Tomonori return 0; 17958dea0d02SFUJITA Tomonori } 17968dea0d02SFUJITA Tomonori 17978dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 17988dea0d02SFUJITA Tomonori { 17998dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 18008dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 18018dea0d02SFUJITA Tomonori 18028dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18038dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 18048dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 18058dea0d02SFUJITA Tomonori if (devip) { 18068dea0d02SFUJITA Tomonori /* make this slot avaliable for re-use */ 18078dea0d02SFUJITA Tomonori devip->used = 0; 18088dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 18098dea0d02SFUJITA Tomonori } 18108dea0d02SFUJITA Tomonori } 18118dea0d02SFUJITA Tomonori 18128dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 18138dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 18148dea0d02SFUJITA Tomonori { 18158dea0d02SFUJITA Tomonori unsigned long iflags; 18168dea0d02SFUJITA Tomonori int k; 18178dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 18188dea0d02SFUJITA Tomonori 18198dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 18208dea0d02SFUJITA Tomonori for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 18218dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 18228dea0d02SFUJITA Tomonori if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 18238dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 18248dea0d02SFUJITA Tomonori sqcp->in_use = 0; 18258dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 18268dea0d02SFUJITA Tomonori break; 18278dea0d02SFUJITA Tomonori } 18288dea0d02SFUJITA Tomonori } 18298dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 18308dea0d02SFUJITA Tomonori return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0; 18318dea0d02SFUJITA Tomonori } 18328dea0d02SFUJITA Tomonori 18338dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */ 18348dea0d02SFUJITA Tomonori static void stop_all_queued(void) 18358dea0d02SFUJITA Tomonori { 18368dea0d02SFUJITA Tomonori unsigned long iflags; 18378dea0d02SFUJITA Tomonori int k; 18388dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 18398dea0d02SFUJITA Tomonori 18408dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 18418dea0d02SFUJITA Tomonori for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 18428dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 18438dea0d02SFUJITA Tomonori if (sqcp->in_use && sqcp->a_cmnd) { 18448dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 18458dea0d02SFUJITA Tomonori sqcp->in_use = 0; 18468dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 18478dea0d02SFUJITA Tomonori } 18488dea0d02SFUJITA Tomonori } 18498dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 18501da177e4SLinus Torvalds } 18511da177e4SLinus Torvalds 18521da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 18531da177e4SLinus Torvalds { 18541da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18551da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 18561da177e4SLinus Torvalds ++num_aborts; 18571da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 18581da177e4SLinus Torvalds return SUCCESS; 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds 18611da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 18621da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 18631da177e4SLinus Torvalds { 18641da177e4SLinus Torvalds int res; 18651da177e4SLinus Torvalds unsigned char *buf; 18661da177e4SLinus Torvalds 18671da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18681da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 18691da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 18701da177e4SLinus Torvalds if (buf) { 18711da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 18721da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 18731da177e4SLinus Torvalds kfree(buf); 18741da177e4SLinus Torvalds if (! res) 18751da177e4SLinus Torvalds return res; 18761da177e4SLinus Torvalds } 18771da177e4SLinus Torvalds info[0] = sdebug_heads; 18781da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 18791da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 18801da177e4SLinus Torvalds return 0; 18811da177e4SLinus Torvalds } 18821da177e4SLinus Torvalds 18831da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 18841da177e4SLinus Torvalds { 18851da177e4SLinus Torvalds struct sdebug_dev_info * devip; 18861da177e4SLinus Torvalds 18871da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 18881da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 18891da177e4SLinus Torvalds ++num_dev_resets; 18901da177e4SLinus Torvalds if (SCpnt) { 18911da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 18921da177e4SLinus Torvalds if (devip) 18931da177e4SLinus Torvalds devip->reset = 1; 18941da177e4SLinus Torvalds } 18951da177e4SLinus Torvalds return SUCCESS; 18961da177e4SLinus Torvalds } 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 18991da177e4SLinus Torvalds { 19001da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 19011da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 19021da177e4SLinus Torvalds struct scsi_device * sdp; 19031da177e4SLinus Torvalds struct Scsi_Host * hp; 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 19061da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 19071da177e4SLinus Torvalds ++num_bus_resets; 19081da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 1909d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 19101da177e4SLinus Torvalds if (sdbg_host) { 19111da177e4SLinus Torvalds list_for_each_entry(dev_info, 19121da177e4SLinus Torvalds &sdbg_host->dev_info_list, 19131da177e4SLinus Torvalds dev_list) 19141da177e4SLinus Torvalds dev_info->reset = 1; 19151da177e4SLinus Torvalds } 19161da177e4SLinus Torvalds } 19171da177e4SLinus Torvalds return SUCCESS; 19181da177e4SLinus Torvalds } 19191da177e4SLinus Torvalds 19201da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 19231da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 19241da177e4SLinus Torvalds 19251da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 19261da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 19271da177e4SLinus Torvalds ++num_host_resets; 19281da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 19291da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 19301da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 19311da177e4SLinus Torvalds dev_list) 19321da177e4SLinus Torvalds dev_info->reset = 1; 19331da177e4SLinus Torvalds } 19341da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 19351da177e4SLinus Torvalds stop_all_queued(); 19361da177e4SLinus Torvalds return SUCCESS; 19371da177e4SLinus Torvalds } 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds /* Initializes timers in queued array */ 19401da177e4SLinus Torvalds static void __init init_all_queued(void) 19411da177e4SLinus Torvalds { 19421da177e4SLinus Torvalds unsigned long iflags; 19431da177e4SLinus Torvalds int k; 19441da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 19471da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 19481da177e4SLinus Torvalds sqcp = &queued_arr[k]; 19491da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 19501da177e4SLinus Torvalds sqcp->in_use = 0; 19511da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 19521da177e4SLinus Torvalds } 19531da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 19541da177e4SLinus Torvalds } 19551da177e4SLinus Torvalds 1956f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 19575f2578e5SFUJITA Tomonori unsigned long store_size) 19581da177e4SLinus Torvalds { 19591da177e4SLinus Torvalds struct partition * pp; 19601da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 19611da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 19621da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 19631da177e4SLinus Torvalds 19641da177e4SLinus Torvalds /* assume partition table already zeroed */ 1965f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 19661da177e4SLinus Torvalds return; 19671da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 19681da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 19691da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 19701da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 19711da177e4SLinus Torvalds } 1972c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 19731da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 19741da177e4SLinus Torvalds / scsi_debug_num_parts; 19751da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 19761da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 19771da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 19781da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 19791da177e4SLinus Torvalds * heads_by_sects; 19801da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 19811da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 19821da177e4SLinus Torvalds 19831da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 19841da177e4SLinus Torvalds ramp[511] = 0xAA; 19851da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 19861da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 19871da177e4SLinus Torvalds start_sec = starts[k]; 19881da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 19891da177e4SLinus Torvalds pp->boot_ind = 0; 19901da177e4SLinus Torvalds 19911da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 19921da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 19931da177e4SLinus Torvalds / sdebug_sectors_per; 19941da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 19971da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 19981da177e4SLinus Torvalds / sdebug_sectors_per; 19991da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 20001da177e4SLinus Torvalds 20011da177e4SLinus Torvalds pp->start_sect = start_sec; 20021da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 20031da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 20041da177e4SLinus Torvalds } 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds 20071da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 20081da177e4SLinus Torvalds struct sdebug_dev_info * devip, 20091da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 20101da177e4SLinus Torvalds { 20111da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 20121da177e4SLinus Torvalds if (scsi_result) { 20131da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 20141da177e4SLinus Torvalds 2015c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2016c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2017c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 20181da177e4SLinus Torvalds } 20191da177e4SLinus Torvalds } 20201da177e4SLinus Torvalds if (cmnd && devip) { 20211da177e4SLinus Torvalds /* simulate autosense by this driver */ 20221da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 20231da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 20241da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 20251da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 20261da177e4SLinus Torvalds } 20271da177e4SLinus Torvalds if (delta_jiff <= 0) { 20281da177e4SLinus Torvalds if (cmnd) 20291da177e4SLinus Torvalds cmnd->result = scsi_result; 20301da177e4SLinus Torvalds if (done) 20311da177e4SLinus Torvalds done(cmnd); 20321da177e4SLinus Torvalds return 0; 20331da177e4SLinus Torvalds } else { 20341da177e4SLinus Torvalds unsigned long iflags; 20351da177e4SLinus Torvalds int k; 20361da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 20371da177e4SLinus Torvalds 20381da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 20391da177e4SLinus Torvalds for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 20401da177e4SLinus Torvalds sqcp = &queued_arr[k]; 20411da177e4SLinus Torvalds if (! sqcp->in_use) 20421da177e4SLinus Torvalds break; 20431da177e4SLinus Torvalds } 20441da177e4SLinus Torvalds if (k >= SCSI_DEBUG_CANQUEUE) { 20451da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20461da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 20471da177e4SLinus Torvalds return 1; /* report busy to mid level */ 20481da177e4SLinus Torvalds } 20491da177e4SLinus Torvalds sqcp->in_use = 1; 20501da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 20511da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 20521da177e4SLinus Torvalds sqcp->done_funct = done; 20531da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 20541da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 20551da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 20561da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 20571da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 20581da177e4SLinus Torvalds if (cmnd) 20591da177e4SLinus Torvalds cmnd->result = 0; 20601da177e4SLinus Torvalds return 0; 20611da177e4SLinus Torvalds } 20621da177e4SLinus Torvalds } 206323183910SDouglas Gilbert /* Note: The following macros create attribute files in the 206423183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 206523183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 206623183910SDouglas Gilbert as it can when the corresponding attribute in the 206723183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 206823183910SDouglas Gilbert */ 2069c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 2070c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2071c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 2072c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2073c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 207423183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 2075c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 2076c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 2077c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2078c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 2079c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 2080c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2081c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 2082c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 208323183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 208423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 2085597136abSMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 20861da177e4SLinus Torvalds 20871da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 20881da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 20891da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 20901da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 20911da177e4SLinus Torvalds 20921da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 20931da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2094c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 2095c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2096beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 209723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 2098c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 2099c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 21001da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2101c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 21026f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 21031da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 21041da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2105c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 210623183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 2107597136abSMartin K. Petersen MODULE_PARM_DESC(sector_size, "hardware sector size in bytes (def=512)"); 21081da177e4SLinus Torvalds 21091da177e4SLinus Torvalds 21101da177e4SLinus Torvalds static char sdebug_info[256]; 21111da177e4SLinus Torvalds 21121da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 21131da177e4SLinus Torvalds { 21141da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 21151da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 21161da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 21171da177e4SLinus Torvalds scsi_debug_opts); 21181da177e4SLinus Torvalds return sdebug_info; 21191da177e4SLinus Torvalds } 21201da177e4SLinus Torvalds 21211da177e4SLinus Torvalds /* scsi_debug_proc_info 21221da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 21231da177e4SLinus Torvalds */ 21241da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 21251da177e4SLinus Torvalds int length, int inout) 21261da177e4SLinus Torvalds { 21271da177e4SLinus Torvalds int len, pos, begin; 21281da177e4SLinus Torvalds int orig_length; 21291da177e4SLinus Torvalds 21301da177e4SLinus Torvalds orig_length = length; 21311da177e4SLinus Torvalds 21321da177e4SLinus Torvalds if (inout == 1) { 21331da177e4SLinus Torvalds char arr[16]; 21341da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 21351da177e4SLinus Torvalds 21361da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 21371da177e4SLinus Torvalds return -EACCES; 21381da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 21391da177e4SLinus Torvalds arr[minLen] = '\0'; 21401da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 21411da177e4SLinus Torvalds return -EINVAL; 21421da177e4SLinus Torvalds scsi_debug_opts = pos; 21431da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 21441da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 21451da177e4SLinus Torvalds return length; 21461da177e4SLinus Torvalds } 21471da177e4SLinus Torvalds begin = 0; 21481da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 21491da177e4SLinus Torvalds "%s [%s]\n" 21501da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 21511da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 21521da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 21531da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 21541da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 21551da177e4SLinus Torvalds "host_resets=%d\n", 21561da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 21571da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 21581da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 21591da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 2160597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 2161597136abSMartin K. Petersen sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, 2162597136abSMartin K. Petersen num_host_resets); 21631da177e4SLinus Torvalds if (pos < offset) { 21641da177e4SLinus Torvalds len = 0; 21651da177e4SLinus Torvalds begin = pos; 21661da177e4SLinus Torvalds } 21671da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 21681da177e4SLinus Torvalds len -= (offset - begin); 21691da177e4SLinus Torvalds if (len > length) 21701da177e4SLinus Torvalds len = length; 21711da177e4SLinus Torvalds return len; 21721da177e4SLinus Torvalds } 21731da177e4SLinus Torvalds 21741da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 21751da177e4SLinus Torvalds { 21761da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 21771da177e4SLinus Torvalds } 21781da177e4SLinus Torvalds 21791da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 21801da177e4SLinus Torvalds const char * buf, size_t count) 21811da177e4SLinus Torvalds { 21821da177e4SLinus Torvalds int delay; 21831da177e4SLinus Torvalds char work[20]; 21841da177e4SLinus Torvalds 21851da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 21861da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 21871da177e4SLinus Torvalds scsi_debug_delay = delay; 21881da177e4SLinus Torvalds return count; 21891da177e4SLinus Torvalds } 21901da177e4SLinus Torvalds } 21911da177e4SLinus Torvalds return -EINVAL; 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 21941da177e4SLinus Torvalds sdebug_delay_store); 21951da177e4SLinus Torvalds 21961da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 21971da177e4SLinus Torvalds { 21981da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 21991da177e4SLinus Torvalds } 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 22021da177e4SLinus Torvalds const char * buf, size_t count) 22031da177e4SLinus Torvalds { 22041da177e4SLinus Torvalds int opts; 22051da177e4SLinus Torvalds char work[20]; 22061da177e4SLinus Torvalds 22071da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 22081da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 22091da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 22101da177e4SLinus Torvalds goto opts_done; 22111da177e4SLinus Torvalds } else { 22121da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 22131da177e4SLinus Torvalds goto opts_done; 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds } 22161da177e4SLinus Torvalds return -EINVAL; 22171da177e4SLinus Torvalds opts_done: 22181da177e4SLinus Torvalds scsi_debug_opts = opts; 22191da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 22201da177e4SLinus Torvalds return count; 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 22231da177e4SLinus Torvalds sdebug_opts_store); 22241da177e4SLinus Torvalds 22251da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 22261da177e4SLinus Torvalds { 22271da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 22281da177e4SLinus Torvalds } 22291da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 22301da177e4SLinus Torvalds const char * buf, size_t count) 22311da177e4SLinus Torvalds { 22321da177e4SLinus Torvalds int n; 22331da177e4SLinus Torvalds 22341da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 22351da177e4SLinus Torvalds scsi_debug_ptype = n; 22361da177e4SLinus Torvalds return count; 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds return -EINVAL; 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 22411da177e4SLinus Torvalds 22421da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 22431da177e4SLinus Torvalds { 22441da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 22451da177e4SLinus Torvalds } 22461da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 22471da177e4SLinus Torvalds const char * buf, size_t count) 22481da177e4SLinus Torvalds { 22491da177e4SLinus Torvalds int n; 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 22521da177e4SLinus Torvalds scsi_debug_dsense = n; 22531da177e4SLinus Torvalds return count; 22541da177e4SLinus Torvalds } 22551da177e4SLinus Torvalds return -EINVAL; 22561da177e4SLinus Torvalds } 22571da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 22581da177e4SLinus Torvalds sdebug_dsense_store); 22591da177e4SLinus Torvalds 226023183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 226123183910SDouglas Gilbert { 226223183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 226323183910SDouglas Gilbert } 226423183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 226523183910SDouglas Gilbert const char * buf, size_t count) 226623183910SDouglas Gilbert { 226723183910SDouglas Gilbert int n; 226823183910SDouglas Gilbert 226923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 227023183910SDouglas Gilbert scsi_debug_fake_rw = n; 227123183910SDouglas Gilbert return count; 227223183910SDouglas Gilbert } 227323183910SDouglas Gilbert return -EINVAL; 227423183910SDouglas Gilbert } 227523183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 227623183910SDouglas Gilbert sdebug_fake_rw_store); 227723183910SDouglas Gilbert 2278c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2279c65b1445SDouglas Gilbert { 2280c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2281c65b1445SDouglas Gilbert } 2282c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2283c65b1445SDouglas Gilbert const char * buf, size_t count) 2284c65b1445SDouglas Gilbert { 2285c65b1445SDouglas Gilbert int n; 2286c65b1445SDouglas Gilbert 2287c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2288c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2289c65b1445SDouglas Gilbert return count; 2290c65b1445SDouglas Gilbert } 2291c65b1445SDouglas Gilbert return -EINVAL; 2292c65b1445SDouglas Gilbert } 2293c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 2294c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 2295c65b1445SDouglas Gilbert 22961da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 22971da177e4SLinus Torvalds { 22981da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 22991da177e4SLinus Torvalds } 23001da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 23011da177e4SLinus Torvalds const char * buf, size_t count) 23021da177e4SLinus Torvalds { 23031da177e4SLinus Torvalds int n; 23041da177e4SLinus Torvalds 23051da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 23061da177e4SLinus Torvalds scsi_debug_num_tgts = n; 23071da177e4SLinus Torvalds sdebug_max_tgts_luns(); 23081da177e4SLinus Torvalds return count; 23091da177e4SLinus Torvalds } 23101da177e4SLinus Torvalds return -EINVAL; 23111da177e4SLinus Torvalds } 23121da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 23131da177e4SLinus Torvalds sdebug_num_tgts_store); 23141da177e4SLinus Torvalds 23151da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 23161da177e4SLinus Torvalds { 23171da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 23181da177e4SLinus Torvalds } 23191da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 23201da177e4SLinus Torvalds 23211da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 23221da177e4SLinus Torvalds { 23231da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 23241da177e4SLinus Torvalds } 23251da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 23261da177e4SLinus Torvalds 23271da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 23281da177e4SLinus Torvalds { 23291da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 23301da177e4SLinus Torvalds } 23311da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 23321da177e4SLinus Torvalds const char * buf, size_t count) 23331da177e4SLinus Torvalds { 23341da177e4SLinus Torvalds int nth; 23351da177e4SLinus Torvalds 23361da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 23371da177e4SLinus Torvalds scsi_debug_every_nth = nth; 23381da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 23391da177e4SLinus Torvalds return count; 23401da177e4SLinus Torvalds } 23411da177e4SLinus Torvalds return -EINVAL; 23421da177e4SLinus Torvalds } 23431da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 23441da177e4SLinus Torvalds sdebug_every_nth_store); 23451da177e4SLinus Torvalds 23461da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 23471da177e4SLinus Torvalds { 23481da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 23491da177e4SLinus Torvalds } 23501da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 23511da177e4SLinus Torvalds const char * buf, size_t count) 23521da177e4SLinus Torvalds { 23531da177e4SLinus Torvalds int n; 23541da177e4SLinus Torvalds 23551da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 23561da177e4SLinus Torvalds scsi_debug_max_luns = n; 23571da177e4SLinus Torvalds sdebug_max_tgts_luns(); 23581da177e4SLinus Torvalds return count; 23591da177e4SLinus Torvalds } 23601da177e4SLinus Torvalds return -EINVAL; 23611da177e4SLinus Torvalds } 23621da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 23631da177e4SLinus Torvalds sdebug_max_luns_store); 23641da177e4SLinus Torvalds 23651da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 23661da177e4SLinus Torvalds { 23671da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 23681da177e4SLinus Torvalds } 23691da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 23701da177e4SLinus Torvalds 2371c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 2372c65b1445SDouglas Gilbert { 2373c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 2374c65b1445SDouglas Gilbert } 2375c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 2376c65b1445SDouglas Gilbert const char * buf, size_t count) 2377c65b1445SDouglas Gilbert { 2378c65b1445SDouglas Gilbert int n; 2379c65b1445SDouglas Gilbert 2380c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2381c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 238228898873SFUJITA Tomonori 238328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 238428898873SFUJITA Tomonori 2385c65b1445SDouglas Gilbert return count; 2386c65b1445SDouglas Gilbert } 2387c65b1445SDouglas Gilbert return -EINVAL; 2388c65b1445SDouglas Gilbert } 2389c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 2390c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 2391c65b1445SDouglas Gilbert 23921da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 23931da177e4SLinus Torvalds { 23941da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 23951da177e4SLinus Torvalds } 23961da177e4SLinus Torvalds 23971da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 23981da177e4SLinus Torvalds const char * buf, size_t count) 23991da177e4SLinus Torvalds { 24001da177e4SLinus Torvalds int delta_hosts; 24011da177e4SLinus Torvalds 2402f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 24031da177e4SLinus Torvalds return -EINVAL; 24041da177e4SLinus Torvalds if (delta_hosts > 0) { 24051da177e4SLinus Torvalds do { 24061da177e4SLinus Torvalds sdebug_add_adapter(); 24071da177e4SLinus Torvalds } while (--delta_hosts); 24081da177e4SLinus Torvalds } else if (delta_hosts < 0) { 24091da177e4SLinus Torvalds do { 24101da177e4SLinus Torvalds sdebug_remove_adapter(); 24111da177e4SLinus Torvalds } while (++delta_hosts); 24121da177e4SLinus Torvalds } 24131da177e4SLinus Torvalds return count; 24141da177e4SLinus Torvalds } 24151da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 24161da177e4SLinus Torvalds sdebug_add_host_store); 24171da177e4SLinus Torvalds 241823183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 241923183910SDouglas Gilbert char * buf) 242023183910SDouglas Gilbert { 242123183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 242223183910SDouglas Gilbert } 242323183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 242423183910SDouglas Gilbert const char * buf, size_t count) 242523183910SDouglas Gilbert { 242623183910SDouglas Gilbert int n; 242723183910SDouglas Gilbert 242823183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 242923183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 243023183910SDouglas Gilbert return count; 243123183910SDouglas Gilbert } 243223183910SDouglas Gilbert return -EINVAL; 243323183910SDouglas Gilbert } 243423183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 243523183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 243623183910SDouglas Gilbert 2437597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) 2438597136abSMartin K. Petersen { 2439597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 2440597136abSMartin K. Petersen } 2441597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); 2442597136abSMartin K. Petersen 244323183910SDouglas Gilbert /* Note: The following function creates attribute files in the 244423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 244523183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 244623183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 244723183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 244823183910SDouglas Gilbert */ 24496ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 24501da177e4SLinus Torvalds { 24516ecaff7fSRandy Dunlap int ret; 24526ecaff7fSRandy Dunlap 24536ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 24546ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 24556ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 24566ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 24576ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 245823183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 24596ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 246023183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 24616ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 246223183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 24636ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 24646ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 24656ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 246623183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 246723183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 2468597136abSMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 24696ecaff7fSRandy Dunlap return ret; 24701da177e4SLinus Torvalds } 24711da177e4SLinus Torvalds 24721da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 24731da177e4SLinus Torvalds { 2474597136abSMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 247523183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 247623183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 24771da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 24781da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 24791da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 24801da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 248123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 248223183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 24831da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 248423183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 24851da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 24861da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 24871da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 24881da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 24891da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 24901da177e4SLinus Torvalds } 24911da177e4SLinus Torvalds 24928dea0d02SFUJITA Tomonori static void pseudo_0_release(struct device *dev) 24938dea0d02SFUJITA Tomonori { 24948dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24958dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n"); 24968dea0d02SFUJITA Tomonori } 24978dea0d02SFUJITA Tomonori 24988dea0d02SFUJITA Tomonori static struct device pseudo_primary = { 24998dea0d02SFUJITA Tomonori .bus_id = "pseudo_0", 25008dea0d02SFUJITA Tomonori .release = pseudo_0_release, 25018dea0d02SFUJITA Tomonori }; 25028dea0d02SFUJITA Tomonori 25031da177e4SLinus Torvalds static int __init scsi_debug_init(void) 25041da177e4SLinus Torvalds { 25055f2578e5SFUJITA Tomonori unsigned long sz; 25061da177e4SLinus Torvalds int host_to_add; 25071da177e4SLinus Torvalds int k; 25086ecaff7fSRandy Dunlap int ret; 25091da177e4SLinus Torvalds 2510597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 2511597136abSMartin K. Petersen case 512: 2512597136abSMartin K. Petersen case 1024: 2513597136abSMartin K. Petersen case 2048: 2514597136abSMartin K. Petersen case 4096: 2515597136abSMartin K. Petersen break; 2516597136abSMartin K. Petersen default: 2517597136abSMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid sector_size %u\n", 2518597136abSMartin K. Petersen scsi_debug_sector_size); 2519597136abSMartin K. Petersen return -EINVAL; 2520597136abSMartin K. Petersen } 2521597136abSMartin K. Petersen 25221da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 25231da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 25245f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 2525597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 252628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 25271da177e4SLinus Torvalds 25281da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 25291da177e4SLinus Torvalds sdebug_heads = 8; 25301da177e4SLinus Torvalds sdebug_sectors_per = 32; 25311da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 25321da177e4SLinus Torvalds sdebug_heads = 32; 25331da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 25341da177e4SLinus Torvalds sdebug_heads = 64; 25351da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 25361da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 25371da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 25381da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 25391da177e4SLinus Torvalds sdebug_heads = 255; 25401da177e4SLinus Torvalds sdebug_sectors_per = 63; 25411da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 25421da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 25431da177e4SLinus Torvalds } 25441da177e4SLinus Torvalds 25451da177e4SLinus Torvalds fake_storep = vmalloc(sz); 25461da177e4SLinus Torvalds if (NULL == fake_storep) { 25471da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 25481da177e4SLinus Torvalds return -ENOMEM; 25491da177e4SLinus Torvalds } 25501da177e4SLinus Torvalds memset(fake_storep, 0, sz); 25511da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 2552f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 25531da177e4SLinus Torvalds 25546ecaff7fSRandy Dunlap ret = device_register(&pseudo_primary); 25556ecaff7fSRandy Dunlap if (ret < 0) { 25566ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: device_register error: %d\n", 25576ecaff7fSRandy Dunlap ret); 25586ecaff7fSRandy Dunlap goto free_vm; 25596ecaff7fSRandy Dunlap } 25606ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 25616ecaff7fSRandy Dunlap if (ret < 0) { 25626ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 25636ecaff7fSRandy Dunlap ret); 25646ecaff7fSRandy Dunlap goto dev_unreg; 25656ecaff7fSRandy Dunlap } 25666ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 25676ecaff7fSRandy Dunlap if (ret < 0) { 25686ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 25696ecaff7fSRandy Dunlap ret); 25706ecaff7fSRandy Dunlap goto bus_unreg; 25716ecaff7fSRandy Dunlap } 25726ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 25736ecaff7fSRandy Dunlap if (ret < 0) { 25746ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 25756ecaff7fSRandy Dunlap ret); 25766ecaff7fSRandy Dunlap goto del_files; 25776ecaff7fSRandy Dunlap } 25781da177e4SLinus Torvalds 25796ecaff7fSRandy Dunlap init_all_queued(); 25801da177e4SLinus Torvalds 25811da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 25821da177e4SLinus Torvalds scsi_debug_add_host = 0; 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 25851da177e4SLinus Torvalds if (sdebug_add_adapter()) { 25861da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 25871da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 25881da177e4SLinus Torvalds break; 25891da177e4SLinus Torvalds } 25901da177e4SLinus Torvalds } 25911da177e4SLinus Torvalds 25921da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 25931da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 25941da177e4SLinus Torvalds scsi_debug_add_host); 25951da177e4SLinus Torvalds } 25961da177e4SLinus Torvalds return 0; 25976ecaff7fSRandy Dunlap 25986ecaff7fSRandy Dunlap del_files: 25996ecaff7fSRandy Dunlap do_remove_driverfs_files(); 26006ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 26016ecaff7fSRandy Dunlap bus_unreg: 26026ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 26036ecaff7fSRandy Dunlap dev_unreg: 26046ecaff7fSRandy Dunlap device_unregister(&pseudo_primary); 26056ecaff7fSRandy Dunlap free_vm: 26066ecaff7fSRandy Dunlap vfree(fake_storep); 26076ecaff7fSRandy Dunlap 26086ecaff7fSRandy Dunlap return ret; 26091da177e4SLinus Torvalds } 26101da177e4SLinus Torvalds 26111da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 26121da177e4SLinus Torvalds { 26131da177e4SLinus Torvalds int k = scsi_debug_add_host; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds stop_all_queued(); 26161da177e4SLinus Torvalds for (; k; k--) 26171da177e4SLinus Torvalds sdebug_remove_adapter(); 26181da177e4SLinus Torvalds do_remove_driverfs_files(); 26191da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 26201da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 26211da177e4SLinus Torvalds device_unregister(&pseudo_primary); 26221da177e4SLinus Torvalds 26231da177e4SLinus Torvalds vfree(fake_storep); 26241da177e4SLinus Torvalds } 26251da177e4SLinus Torvalds 26261da177e4SLinus Torvalds device_initcall(scsi_debug_init); 26271da177e4SLinus Torvalds module_exit(scsi_debug_exit); 26281da177e4SLinus Torvalds 26291da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 26301da177e4SLinus Torvalds { 26311da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 26321da177e4SLinus Torvalds 26331da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 26341da177e4SLinus Torvalds kfree(sdbg_host); 26351da177e4SLinus Torvalds } 26361da177e4SLinus Torvalds 26371da177e4SLinus Torvalds static int sdebug_add_adapter(void) 26381da177e4SLinus Torvalds { 26391da177e4SLinus Torvalds int k, devs_per_host; 26401da177e4SLinus Torvalds int error = 0; 26411da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 26428b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 26431da177e4SLinus Torvalds 264424669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 26451da177e4SLinus Torvalds if (NULL == sdbg_host) { 26461da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 26471da177e4SLinus Torvalds __FUNCTION__, __LINE__); 26481da177e4SLinus Torvalds return -ENOMEM; 26491da177e4SLinus Torvalds } 26501da177e4SLinus Torvalds 26511da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 26521da177e4SLinus Torvalds 26531da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 26541da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 26555cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 26565cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 26571da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 26581da177e4SLinus Torvalds __FUNCTION__, __LINE__); 26591da177e4SLinus Torvalds error = -ENOMEM; 26601da177e4SLinus Torvalds goto clean; 26611da177e4SLinus Torvalds } 26621da177e4SLinus Torvalds } 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 26651da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 26661da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 26671da177e4SLinus Torvalds 26681da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 26691da177e4SLinus Torvalds sdbg_host->dev.parent = &pseudo_primary; 26701da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 26711da177e4SLinus Torvalds sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); 26721da177e4SLinus Torvalds 26731da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 26741da177e4SLinus Torvalds 26751da177e4SLinus Torvalds if (error) 26761da177e4SLinus Torvalds goto clean; 26771da177e4SLinus Torvalds 26781da177e4SLinus Torvalds ++scsi_debug_add_host; 26791da177e4SLinus Torvalds return error; 26801da177e4SLinus Torvalds 26811da177e4SLinus Torvalds clean: 26828b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 26838b40228fSFUJITA Tomonori dev_list) { 26841da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 26851da177e4SLinus Torvalds kfree(sdbg_devinfo); 26861da177e4SLinus Torvalds } 26871da177e4SLinus Torvalds 26881da177e4SLinus Torvalds kfree(sdbg_host); 26891da177e4SLinus Torvalds return error; 26901da177e4SLinus Torvalds } 26911da177e4SLinus Torvalds 26921da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 26931da177e4SLinus Torvalds { 26941da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 26951da177e4SLinus Torvalds 26961da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 26971da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 26981da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 26991da177e4SLinus Torvalds struct sdebug_host_info, host_list); 27001da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 27011da177e4SLinus Torvalds } 27021da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 27031da177e4SLinus Torvalds 27041da177e4SLinus Torvalds if (!sdbg_host) 27051da177e4SLinus Torvalds return; 27061da177e4SLinus Torvalds 27071da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 27081da177e4SLinus Torvalds --scsi_debug_add_host; 27091da177e4SLinus Torvalds } 27101da177e4SLinus Torvalds 2711639db475SFUJITA Tomonori static 2712639db475SFUJITA Tomonori int scsi_debug_queuecommand(struct scsi_cmnd *SCpnt, done_funct_t done) 2713639db475SFUJITA Tomonori { 2714639db475SFUJITA Tomonori unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 2715639db475SFUJITA Tomonori int len, k; 2716639db475SFUJITA Tomonori unsigned int num; 2717639db475SFUJITA Tomonori unsigned long long lba; 2718639db475SFUJITA Tomonori int errsts = 0; 2719639db475SFUJITA Tomonori int target = SCpnt->device->id; 2720639db475SFUJITA Tomonori struct sdebug_dev_info *devip = NULL; 2721639db475SFUJITA Tomonori int inj_recovered = 0; 2722639db475SFUJITA Tomonori int inj_transport = 0; 2723639db475SFUJITA Tomonori int delay_override = 0; 2724639db475SFUJITA Tomonori 2725639db475SFUJITA Tomonori scsi_set_resid(SCpnt, 0); 2726639db475SFUJITA Tomonori if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 2727639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: cmd "); 2728639db475SFUJITA Tomonori for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 2729639db475SFUJITA Tomonori printk("%02x ", (int)cmd[k]); 2730639db475SFUJITA Tomonori printk("\n"); 2731639db475SFUJITA Tomonori } 2732639db475SFUJITA Tomonori 2733639db475SFUJITA Tomonori if (target == SCpnt->device->host->hostt->this_id) { 2734639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: initiator's id used as " 2735639db475SFUJITA Tomonori "target!\n"); 2736639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2737639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2738639db475SFUJITA Tomonori } 2739639db475SFUJITA Tomonori 2740639db475SFUJITA Tomonori if ((SCpnt->device->lun >= scsi_debug_max_luns) && 2741639db475SFUJITA Tomonori (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 2742639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2743639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2744639db475SFUJITA Tomonori devip = devInfoReg(SCpnt->device); 2745639db475SFUJITA Tomonori if (NULL == devip) 2746639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 2747639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 2748639db475SFUJITA Tomonori 2749639db475SFUJITA Tomonori if ((scsi_debug_every_nth != 0) && 2750639db475SFUJITA Tomonori (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 2751639db475SFUJITA Tomonori scsi_debug_cmnd_count = 0; 2752639db475SFUJITA Tomonori if (scsi_debug_every_nth < -1) 2753639db475SFUJITA Tomonori scsi_debug_every_nth = -1; 2754639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 2755639db475SFUJITA Tomonori return 0; /* ignore command causing timeout */ 2756639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 2757639db475SFUJITA Tomonori inj_recovered = 1; /* to reads and writes below */ 2758639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 2759639db475SFUJITA Tomonori inj_transport = 1; /* to reads and writes below */ 2760639db475SFUJITA Tomonori } 2761639db475SFUJITA Tomonori 2762639db475SFUJITA Tomonori if (devip->wlun) { 2763639db475SFUJITA Tomonori switch (*cmd) { 2764639db475SFUJITA Tomonori case INQUIRY: 2765639db475SFUJITA Tomonori case REQUEST_SENSE: 2766639db475SFUJITA Tomonori case TEST_UNIT_READY: 2767639db475SFUJITA Tomonori case REPORT_LUNS: 2768639db475SFUJITA Tomonori break; /* only allowable wlun commands */ 2769639db475SFUJITA Tomonori default: 2770639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2771639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 2772639db475SFUJITA Tomonori "not supported for wlun\n", *cmd); 2773639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2774639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2775639db475SFUJITA Tomonori errsts = check_condition_result; 2776639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 2777639db475SFUJITA Tomonori 0); 2778639db475SFUJITA Tomonori } 2779639db475SFUJITA Tomonori } 2780639db475SFUJITA Tomonori 2781639db475SFUJITA Tomonori switch (*cmd) { 2782639db475SFUJITA Tomonori case INQUIRY: /* mandatory, ignore unit attention */ 2783639db475SFUJITA Tomonori delay_override = 1; 2784639db475SFUJITA Tomonori errsts = resp_inquiry(SCpnt, target, devip); 2785639db475SFUJITA Tomonori break; 2786639db475SFUJITA Tomonori case REQUEST_SENSE: /* mandatory, ignore unit attention */ 2787639db475SFUJITA Tomonori delay_override = 1; 2788639db475SFUJITA Tomonori errsts = resp_requests(SCpnt, devip); 2789639db475SFUJITA Tomonori break; 2790639db475SFUJITA Tomonori case REZERO_UNIT: /* actually this is REWIND for SSC */ 2791639db475SFUJITA Tomonori case START_STOP: 2792639db475SFUJITA Tomonori errsts = resp_start_stop(SCpnt, devip); 2793639db475SFUJITA Tomonori break; 2794639db475SFUJITA Tomonori case ALLOW_MEDIUM_REMOVAL: 2795639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2796639db475SFUJITA Tomonori if (errsts) 2797639db475SFUJITA Tomonori break; 2798639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2799639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Medium removal %s\n", 2800639db475SFUJITA Tomonori cmd[4] ? "inhibited" : "enabled"); 2801639db475SFUJITA Tomonori break; 2802639db475SFUJITA Tomonori case SEND_DIAGNOSTIC: /* mandatory */ 2803639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2804639db475SFUJITA Tomonori break; 2805639db475SFUJITA Tomonori case TEST_UNIT_READY: /* mandatory */ 2806639db475SFUJITA Tomonori delay_override = 1; 2807639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2808639db475SFUJITA Tomonori break; 2809639db475SFUJITA Tomonori case RESERVE: 2810639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2811639db475SFUJITA Tomonori break; 2812639db475SFUJITA Tomonori case RESERVE_10: 2813639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2814639db475SFUJITA Tomonori break; 2815639db475SFUJITA Tomonori case RELEASE: 2816639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2817639db475SFUJITA Tomonori break; 2818639db475SFUJITA Tomonori case RELEASE_10: 2819639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2820639db475SFUJITA Tomonori break; 2821639db475SFUJITA Tomonori case READ_CAPACITY: 2822639db475SFUJITA Tomonori errsts = resp_readcap(SCpnt, devip); 2823639db475SFUJITA Tomonori break; 2824639db475SFUJITA Tomonori case SERVICE_ACTION_IN: 2825639db475SFUJITA Tomonori if (SAI_READ_CAPACITY_16 != cmd[1]) { 2826639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2827639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2828639db475SFUJITA Tomonori errsts = check_condition_result; 2829639db475SFUJITA Tomonori break; 2830639db475SFUJITA Tomonori } 2831639db475SFUJITA Tomonori errsts = resp_readcap16(SCpnt, devip); 2832639db475SFUJITA Tomonori break; 2833639db475SFUJITA Tomonori case MAINTENANCE_IN: 2834639db475SFUJITA Tomonori if (MI_REPORT_TARGET_PGS != cmd[1]) { 2835639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2836639db475SFUJITA Tomonori INVALID_OPCODE, 0); 2837639db475SFUJITA Tomonori errsts = check_condition_result; 2838639db475SFUJITA Tomonori break; 2839639db475SFUJITA Tomonori } 2840639db475SFUJITA Tomonori errsts = resp_report_tgtpgs(SCpnt, devip); 2841639db475SFUJITA Tomonori break; 2842639db475SFUJITA Tomonori case READ_16: 2843639db475SFUJITA Tomonori case READ_12: 2844639db475SFUJITA Tomonori case READ_10: 2845639db475SFUJITA Tomonori case READ_6: 2846639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2847639db475SFUJITA Tomonori if (errsts) 2848639db475SFUJITA Tomonori break; 2849639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2850639db475SFUJITA Tomonori break; 2851639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2852639db475SFUJITA Tomonori errsts = resp_read(SCpnt, lba, num, devip); 2853639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 2854639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 2855639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 2856639db475SFUJITA Tomonori errsts = check_condition_result; 2857639db475SFUJITA Tomonori } else if (inj_transport && (0 == errsts)) { 2858639db475SFUJITA Tomonori mk_sense_buffer(devip, ABORTED_COMMAND, 2859639db475SFUJITA Tomonori TRANSPORT_PROBLEM, ACK_NAK_TO); 2860639db475SFUJITA Tomonori errsts = check_condition_result; 2861639db475SFUJITA Tomonori } 2862639db475SFUJITA Tomonori break; 2863639db475SFUJITA Tomonori case REPORT_LUNS: /* mandatory, ignore unit attention */ 2864639db475SFUJITA Tomonori delay_override = 1; 2865639db475SFUJITA Tomonori errsts = resp_report_luns(SCpnt, devip); 2866639db475SFUJITA Tomonori break; 2867639db475SFUJITA Tomonori case VERIFY: /* 10 byte SBC-2 command */ 2868639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2869639db475SFUJITA Tomonori break; 2870639db475SFUJITA Tomonori case WRITE_16: 2871639db475SFUJITA Tomonori case WRITE_12: 2872639db475SFUJITA Tomonori case WRITE_10: 2873639db475SFUJITA Tomonori case WRITE_6: 2874639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2875639db475SFUJITA Tomonori if (errsts) 2876639db475SFUJITA Tomonori break; 2877639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2878639db475SFUJITA Tomonori break; 2879639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2880639db475SFUJITA Tomonori errsts = resp_write(SCpnt, lba, num, devip); 2881639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 2882639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 2883639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 2884639db475SFUJITA Tomonori errsts = check_condition_result; 2885639db475SFUJITA Tomonori } 2886639db475SFUJITA Tomonori break; 2887639db475SFUJITA Tomonori case MODE_SENSE: 2888639db475SFUJITA Tomonori case MODE_SENSE_10: 2889639db475SFUJITA Tomonori errsts = resp_mode_sense(SCpnt, target, devip); 2890639db475SFUJITA Tomonori break; 2891639db475SFUJITA Tomonori case MODE_SELECT: 2892639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 1, devip); 2893639db475SFUJITA Tomonori break; 2894639db475SFUJITA Tomonori case MODE_SELECT_10: 2895639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 0, devip); 2896639db475SFUJITA Tomonori break; 2897639db475SFUJITA Tomonori case LOG_SENSE: 2898639db475SFUJITA Tomonori errsts = resp_log_sense(SCpnt, devip); 2899639db475SFUJITA Tomonori break; 2900639db475SFUJITA Tomonori case SYNCHRONIZE_CACHE: 2901639db475SFUJITA Tomonori delay_override = 1; 2902639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2903639db475SFUJITA Tomonori break; 2904639db475SFUJITA Tomonori case WRITE_BUFFER: 2905639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2906639db475SFUJITA Tomonori break; 2907639db475SFUJITA Tomonori case XDWRITEREAD_10: 2908639db475SFUJITA Tomonori if (!scsi_bidi_cmnd(SCpnt)) { 2909639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 2910639db475SFUJITA Tomonori INVALID_FIELD_IN_CDB, 0); 2911639db475SFUJITA Tomonori errsts = check_condition_result; 2912639db475SFUJITA Tomonori break; 2913639db475SFUJITA Tomonori } 2914639db475SFUJITA Tomonori 2915639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 2916639db475SFUJITA Tomonori if (errsts) 2917639db475SFUJITA Tomonori break; 2918639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 2919639db475SFUJITA Tomonori break; 2920639db475SFUJITA Tomonori get_data_transfer_info(cmd, &lba, &num); 2921639db475SFUJITA Tomonori errsts = resp_read(SCpnt, lba, num, devip); 2922639db475SFUJITA Tomonori if (errsts) 2923639db475SFUJITA Tomonori break; 2924639db475SFUJITA Tomonori errsts = resp_write(SCpnt, lba, num, devip); 2925639db475SFUJITA Tomonori if (errsts) 2926639db475SFUJITA Tomonori break; 2927639db475SFUJITA Tomonori errsts = resp_xdwriteread(SCpnt, lba, num, devip); 2928639db475SFUJITA Tomonori break; 2929639db475SFUJITA Tomonori default: 2930639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 2931639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 2932639db475SFUJITA Tomonori "supported\n", *cmd); 2933639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 2934639db475SFUJITA Tomonori if (errsts) 2935639db475SFUJITA Tomonori break; /* Unit attention takes precedence */ 2936639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 2937639db475SFUJITA Tomonori errsts = check_condition_result; 2938639db475SFUJITA Tomonori break; 2939639db475SFUJITA Tomonori } 2940639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 2941639db475SFUJITA Tomonori (delay_override ? 0 : scsi_debug_delay)); 2942639db475SFUJITA Tomonori } 2943639db475SFUJITA Tomonori 29449e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 29459e603ca0SFUJITA Tomonori .proc_info = scsi_debug_proc_info, 29469e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 29479e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 29489e603ca0SFUJITA Tomonori .info = scsi_debug_info, 29499e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 29509e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 29519e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 29529e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 29539e603ca0SFUJITA Tomonori .queuecommand = scsi_debug_queuecommand, 29549e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 29559e603ca0SFUJITA Tomonori .eh_bus_reset_handler = scsi_debug_bus_reset, 29569e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 29579e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 29589e603ca0SFUJITA Tomonori .bios_param = scsi_debug_biosparam, 29599e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 29609e603ca0SFUJITA Tomonori .this_id = 7, 29619e603ca0SFUJITA Tomonori .sg_tablesize = 256, 29629e603ca0SFUJITA Tomonori .cmd_per_lun = 16, 29639e603ca0SFUJITA Tomonori .max_sectors = 0xffff, 29649e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 29659e603ca0SFUJITA Tomonori .module = THIS_MODULE, 29669e603ca0SFUJITA Tomonori }; 29679e603ca0SFUJITA Tomonori 29681da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 29691da177e4SLinus Torvalds { 29701da177e4SLinus Torvalds int error = 0; 29711da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 29721da177e4SLinus Torvalds struct Scsi_Host *hpnt; 29731da177e4SLinus Torvalds 29741da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 29751da177e4SLinus Torvalds 29761da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 29771da177e4SLinus Torvalds if (NULL == hpnt) { 29781da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); 29791da177e4SLinus Torvalds error = -ENODEV; 29801da177e4SLinus Torvalds return error; 29811da177e4SLinus Torvalds } 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds sdbg_host->shost = hpnt; 29841da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 29851da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 29861da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 29871da177e4SLinus Torvalds else 29881da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 2989c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 29901da177e4SLinus Torvalds 29911da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 29921da177e4SLinus Torvalds if (error) { 29931da177e4SLinus Torvalds printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); 29941da177e4SLinus Torvalds error = -ENODEV; 29951da177e4SLinus Torvalds scsi_host_put(hpnt); 29961da177e4SLinus Torvalds } else 29971da177e4SLinus Torvalds scsi_scan_host(hpnt); 29981da177e4SLinus Torvalds 29991da177e4SLinus Torvalds 30001da177e4SLinus Torvalds return error; 30011da177e4SLinus Torvalds } 30021da177e4SLinus Torvalds 30031da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 30041da177e4SLinus Torvalds { 30051da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 30068b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 30071da177e4SLinus Torvalds 30081da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 30091da177e4SLinus Torvalds 30101da177e4SLinus Torvalds if (!sdbg_host) { 30111da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 30121da177e4SLinus Torvalds __FUNCTION__); 30131da177e4SLinus Torvalds return -ENODEV; 30141da177e4SLinus Torvalds } 30151da177e4SLinus Torvalds 30161da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 30171da177e4SLinus Torvalds 30188b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 30198b40228fSFUJITA Tomonori dev_list) { 30201da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 30211da177e4SLinus Torvalds kfree(sdbg_devinfo); 30221da177e4SLinus Torvalds } 30231da177e4SLinus Torvalds 30241da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 30251da177e4SLinus Torvalds return 0; 30261da177e4SLinus Torvalds } 30271da177e4SLinus Torvalds 30288dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 30298dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 30301da177e4SLinus Torvalds { 30318dea0d02SFUJITA Tomonori return 1; 30328dea0d02SFUJITA Tomonori } 30331da177e4SLinus Torvalds 30348dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 30358dea0d02SFUJITA Tomonori .name = "pseudo", 30368dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 30378dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 30388dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 30398dea0d02SFUJITA Tomonori }; 3040