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 * 1578d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/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> 335a0e3ad6STejun Heo #include <linux/slab.h> 341da177e4SLinus Torvalds #include <linux/types.h> 351da177e4SLinus Torvalds #include <linux/string.h> 361da177e4SLinus Torvalds #include <linux/genhd.h> 371da177e4SLinus Torvalds #include <linux/fs.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/proc_fs.h> 401da177e4SLinus Torvalds #include <linux/vmalloc.h> 411da177e4SLinus Torvalds #include <linux/moduleparam.h> 42852e034dSJens Axboe #include <linux/scatterlist.h> 431da177e4SLinus Torvalds #include <linux/blkdev.h> 44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 45c6a44287SMartin K. Petersen 46c6a44287SMartin K. Petersen #include <net/checksum.h> 479ff26eefSFUJITA Tomonori 4844d92694SMartin K. Petersen #include <asm/unaligned.h> 4944d92694SMartin K. Petersen 509ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 531da177e4SLinus Torvalds #include <scsi/scsi_host.h> 541da177e4SLinus Torvalds #include <scsi/scsicam.h> 55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 571da177e4SLinus Torvalds 58c6a44287SMartin K. Petersen #include "sd.h" 591da177e4SLinus Torvalds #include "scsi_logging.h" 601da177e4SLinus Torvalds 6178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.82" 6278d4e5a0SDouglas Gilbert static const char * scsi_debug_version_date = "20100324"; 631da177e4SLinus Torvalds 646f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 65c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 66c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 671da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 68c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 691da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 701da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 71395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20 721da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 73c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 741da177e4SLinus Torvalds #define POWERON_RESET 0x29 751da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 766f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 77c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 78c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 791da177e4SLinus Torvalds 806f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 816f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 826f3cbf55SDouglas Gilbert 831da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* Default values for driver parameters */ 861da177e4SLinus Torvalds #define DEF_NUM_HOST 1 871da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 881da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 891da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 901da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 911da177e4SLinus Torvalds */ 921da177e4SLinus Torvalds #define DEF_DELAY 1 931da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 941da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 951da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 961da177e4SLinus Torvalds #define DEF_OPTS 0 971da177e4SLinus Torvalds #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 981da177e4SLinus Torvalds #define DEF_PTYPE 0 991da177e4SLinus Torvalds #define DEF_D_SENSE 0 100c65b1445SDouglas Gilbert #define DEF_NO_LUN_0 0 101c65b1445SDouglas Gilbert #define DEF_VIRTUAL_GB 0 10223183910SDouglas Gilbert #define DEF_FAKE_RW 0 10323183910SDouglas Gilbert #define DEF_VPD_USE_HOSTNO 1 104597136abSMartin K. Petersen #define DEF_SECTOR_SIZE 512 105c6a44287SMartin K. Petersen #define DEF_DIX 0 106c6a44287SMartin K. Petersen #define DEF_DIF 0 107c6a44287SMartin K. Petersen #define DEF_GUARD 0 108c6a44287SMartin K. Petersen #define DEF_ATO 1 109ea61fca5SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 110ea61fca5SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 111e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64 1126014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1136014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1146014759cSMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 11544d92694SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1166014759cSMartin K. Petersen #define DEF_TPWS 0 1176014759cSMartin K. Petersen #define DEF_TPU 0 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1201da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1211da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1221da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1231da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1246f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 125c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR 32 126c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR 64 1271da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1281da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1291da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1301da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1316f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1326f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1331da177e4SLinus Torvalds * 1341da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1351da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1361da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1371da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1386f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1396f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1401da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1411da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1421da177e4SLinus Torvalds */ 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1451da177e4SLinus Torvalds * sector on read commands: */ 1461da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1491da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1501da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 151c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1521da177e4SLinus Torvalds 15378d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that 15478d4e5a0SDouglas Gilbert * that have a non-zero delay are queued. */ 15578d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE 255 15678d4e5a0SDouglas Gilbert 1571da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1581da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1591da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1601da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1611da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 16278d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; 1631da177e4SLinus Torvalds static int scsi_debug_num_parts = DEF_NUM_PARTS; 16478d4e5a0SDouglas Gilbert static int scsi_debug_no_uld = 0; 1651da177e4SLinus Torvalds static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 1661da177e4SLinus Torvalds static int scsi_debug_opts = DEF_OPTS; 1671da177e4SLinus Torvalds static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1681da177e4SLinus Torvalds static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1691da177e4SLinus Torvalds static int scsi_debug_dsense = DEF_D_SENSE; 170c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 171c65b1445SDouglas Gilbert static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 17223183910SDouglas Gilbert static int scsi_debug_fake_rw = DEF_FAKE_RW; 17323183910SDouglas Gilbert static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 174597136abSMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 175c6a44287SMartin K. Petersen static int scsi_debug_dix = DEF_DIX; 176c6a44287SMartin K. Petersen static int scsi_debug_dif = DEF_DIF; 177c6a44287SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD; 178c6a44287SMartin K. Petersen static int scsi_debug_ato = DEF_ATO; 179ea61fca5SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; 180ea61fca5SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; 181e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS; 1826014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 1836014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 1846014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; 1856014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 1866014759cSMartin K. Petersen static unsigned int scsi_debug_tpws = DEF_TPWS; 1876014759cSMartin K. Petersen static unsigned int scsi_debug_tpu = DEF_TPU; 1881da177e4SLinus Torvalds 1891da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 1921da177e4SLinus Torvalds #define DEV_REMOVEABLE(TGT) (0) 1931da177e4SLinus Torvalds 194c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 1951da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 1961da177e4SLinus Torvalds 1971da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 1981da177e4SLinus Torvalds may still need them */ 1991da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 2001da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 2011da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 2021da177e4SLinus Torvalds 2031da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 2041da177e4SLinus Torvalds 2051da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 2061da177e4SLinus Torvalds 207395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32 2089e603ca0SFUJITA Tomonori 2091da177e4SLinus Torvalds struct sdebug_dev_info { 2101da177e4SLinus Torvalds struct list_head dev_list; 2111da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 2121da177e4SLinus Torvalds unsigned int channel; 2131da177e4SLinus Torvalds unsigned int target; 2141da177e4SLinus Torvalds unsigned int lun; 2151da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 216c65b1445SDouglas Gilbert unsigned int wlun; 2171da177e4SLinus Torvalds char reset; 218c65b1445SDouglas Gilbert char stopped; 2191da177e4SLinus Torvalds char used; 2201da177e4SLinus Torvalds }; 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds struct sdebug_host_info { 2231da177e4SLinus Torvalds struct list_head host_list; 2241da177e4SLinus Torvalds struct Scsi_Host *shost; 2251da177e4SLinus Torvalds struct device dev; 2261da177e4SLinus Torvalds struct list_head dev_info_list; 2271da177e4SLinus Torvalds }; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds #define to_sdebug_host(d) \ 2301da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 2331da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds struct sdebug_queued_cmd { 2381da177e4SLinus Torvalds int in_use; 2391da177e4SLinus Torvalds struct timer_list cmnd_timer; 2401da177e4SLinus Torvalds done_funct_t done_funct; 2411da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2421da177e4SLinus Torvalds int scsi_result; 2431da177e4SLinus Torvalds }; 2441da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 247c6a44287SMartin K. Petersen static unsigned char *dif_storep; /* protection info */ 24844d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 2491da177e4SLinus Torvalds 25044d92694SMartin K. Petersen static unsigned long map_size; 2511da177e4SLinus Torvalds static int num_aborts = 0; 2521da177e4SLinus Torvalds static int num_dev_resets = 0; 2531da177e4SLinus Torvalds static int num_bus_resets = 0; 2541da177e4SLinus Torvalds static int num_host_resets = 0; 255c6a44287SMartin K. Petersen static int dix_writes; 256c6a44287SMartin K. Petersen static int dix_reads; 257c6a44287SMartin K. Petersen static int dif_errors; 2581da177e4SLinus Torvalds 2591da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2601da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2651da177e4SLinus Torvalds 266c6a44287SMartin K. Petersen static inline sector_t dif_offset(sector_t sector) 267c6a44287SMartin K. Petersen { 268c6a44287SMartin K. Petersen return sector << 3; 269c6a44287SMartin K. Petersen } 270c6a44287SMartin K. Petersen 2711da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2721da177e4SLinus Torvalds .name = sdebug_proc_name, 2731da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2741da177e4SLinus Torvalds }; 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static const int check_condition_result = 2771da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2781da177e4SLinus Torvalds 279c6a44287SMartin K. Petersen static const int illegal_condition_result = 280c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 281c6a44287SMartin K. Petersen 282c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 283c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 284c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 285c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 286c65b1445SDouglas Gilbert 2871da177e4SLinus Torvalds static int sdebug_add_adapter(void); 2881da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 2891da177e4SLinus Torvalds 2908dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 2918dea0d02SFUJITA Tomonori { 2928dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 2938dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 2948dea0d02SFUJITA Tomonori 2958dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 2968dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 2978dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 2988dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 2998dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 3008dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 3018dea0d02SFUJITA Tomonori else 3028dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 3038dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 3048dea0d02SFUJITA Tomonori hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; 3058dea0d02SFUJITA Tomonori } 3068dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 3078dea0d02SFUJITA Tomonori } 3088dea0d02SFUJITA Tomonori 3098dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, 3108dea0d02SFUJITA Tomonori int asc, int asq) 3118dea0d02SFUJITA Tomonori { 3128dea0d02SFUJITA Tomonori unsigned char *sbuff; 3138dea0d02SFUJITA Tomonori 3148dea0d02SFUJITA Tomonori sbuff = devip->sense_buff; 3158dea0d02SFUJITA Tomonori memset(sbuff, 0, SDEBUG_SENSE_LEN); 3168dea0d02SFUJITA Tomonori 3178dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 3188dea0d02SFUJITA Tomonori 3198dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3208dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 3218dea0d02SFUJITA Tomonori "[0x%x,0x%x,0x%x]\n", key, asc, asq); 3228dea0d02SFUJITA Tomonori } 3231da177e4SLinus Torvalds 3243de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd, 325395cef03SMartin K. Petersen unsigned long long *lba, unsigned int *num, 326395cef03SMartin K. Petersen u32 *ei_lba) 3273de9f944SFUJITA Tomonori { 328395cef03SMartin K. Petersen *ei_lba = 0; 329395cef03SMartin K. Petersen 3303de9f944SFUJITA Tomonori switch (*cmd) { 331395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 332395cef03SMartin K. Petersen *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | 333395cef03SMartin K. Petersen (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | 334395cef03SMartin K. Petersen (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | 335395cef03SMartin K. Petersen (u64)cmd[13] << 48 | (u64)cmd[12] << 56; 336395cef03SMartin K. Petersen 337395cef03SMartin K. Petersen *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | 338395cef03SMartin K. Petersen (u32)cmd[21] << 16 | (u32)cmd[20] << 24; 339395cef03SMartin K. Petersen 340395cef03SMartin K. Petersen *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | 341395cef03SMartin K. Petersen (u32)cmd[28] << 24; 342395cef03SMartin K. Petersen break; 343395cef03SMartin K. Petersen 34444d92694SMartin K. Petersen case WRITE_SAME_16: 3453de9f944SFUJITA Tomonori case WRITE_16: 3463de9f944SFUJITA Tomonori case READ_16: 347d5cdc989SFUJITA Tomonori *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | 348d5cdc989SFUJITA Tomonori (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | 349d5cdc989SFUJITA Tomonori (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | 350d5cdc989SFUJITA Tomonori (u64)cmd[3] << 48 | (u64)cmd[2] << 56; 351d5cdc989SFUJITA Tomonori 352d5cdc989SFUJITA Tomonori *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | 353d5cdc989SFUJITA Tomonori (u32)cmd[10] << 24; 3543de9f944SFUJITA Tomonori break; 3553de9f944SFUJITA Tomonori case WRITE_12: 3563de9f944SFUJITA Tomonori case READ_12: 357d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 358d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 359d5cdc989SFUJITA Tomonori 360d5cdc989SFUJITA Tomonori *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | 361d5cdc989SFUJITA Tomonori (u32)cmd[6] << 24; 3623de9f944SFUJITA Tomonori break; 36344d92694SMartin K. Petersen case WRITE_SAME: 3643de9f944SFUJITA Tomonori case WRITE_10: 3653de9f944SFUJITA Tomonori case READ_10: 366c639d14eSFUJITA Tomonori case XDWRITEREAD_10: 367d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 368d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 369d5cdc989SFUJITA Tomonori 370d5cdc989SFUJITA Tomonori *num = (u32)cmd[8] | (u32)cmd[7] << 8; 3713de9f944SFUJITA Tomonori break; 3723de9f944SFUJITA Tomonori case WRITE_6: 3733de9f944SFUJITA Tomonori case READ_6: 374d5cdc989SFUJITA Tomonori *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 375d5cdc989SFUJITA Tomonori (u32)(cmd[1] & 0x1f) << 16; 3763de9f944SFUJITA Tomonori *num = (0 == cmd[4]) ? 256 : cmd[4]; 3773de9f944SFUJITA Tomonori break; 3783de9f944SFUJITA Tomonori default: 3793de9f944SFUJITA Tomonori break; 3803de9f944SFUJITA Tomonori } 3813de9f944SFUJITA Tomonori } 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 3841da177e4SLinus Torvalds { 3851da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 3861da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds return -EINVAL; 3891da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 3901da177e4SLinus Torvalds } 3911da177e4SLinus Torvalds 392c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 393c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 3941da177e4SLinus Torvalds { 3951da177e4SLinus Torvalds if (devip->reset) { 3961da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3971da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 3981da177e4SLinus Torvalds "attention: power on reset\n"); 3991da177e4SLinus Torvalds devip->reset = 0; 4001da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 4011da177e4SLinus Torvalds return check_condition_result; 4021da177e4SLinus Torvalds } 403c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 404c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 405c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 406c65b1445SDouglas Gilbert "ready: initializing command required\n"); 407c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 408c65b1445SDouglas Gilbert 0x2); 409c65b1445SDouglas Gilbert return check_condition_result; 410c65b1445SDouglas Gilbert } 4111da177e4SLinus Torvalds return 0; 4121da177e4SLinus Torvalds } 4131da177e4SLinus Torvalds 4141da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 4151da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 4161da177e4SLinus Torvalds int arr_len) 4171da177e4SLinus Torvalds { 41821a61829SFUJITA Tomonori int act_len; 419072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 4201da177e4SLinus Torvalds 421072d0bb3SFUJITA Tomonori if (!sdb->length) 4221da177e4SLinus Torvalds return 0; 423072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 4241da177e4SLinus Torvalds return (DID_ERROR << 16); 42521a61829SFUJITA Tomonori 42621a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 42721a61829SFUJITA Tomonori arr, arr_len); 428072d0bb3SFUJITA Tomonori if (sdb->resid) 429072d0bb3SFUJITA Tomonori sdb->resid -= act_len; 430c65b1445SDouglas Gilbert else 43121a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 43221a61829SFUJITA Tomonori 4331da177e4SLinus Torvalds return 0; 4341da177e4SLinus Torvalds } 4351da177e4SLinus Torvalds 4361da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 4371da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 43821a61829SFUJITA Tomonori int arr_len) 4391da177e4SLinus Torvalds { 44021a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 4411da177e4SLinus Torvalds return 0; 442072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 4431da177e4SLinus Torvalds return -1; 44421a61829SFUJITA Tomonori 44521a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 4461da177e4SLinus Torvalds } 4471da177e4SLinus Torvalds 4481da177e4SLinus Torvalds 4491da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 4501da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 4511da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 4521da177e4SLinus Torvalds 4535a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 4545a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 4555a09e398SHannes Reinecke const char * dev_id_str, 456c65b1445SDouglas Gilbert int dev_id_str_len) 4571da177e4SLinus Torvalds { 458c65b1445SDouglas Gilbert int num, port_a; 459c65b1445SDouglas Gilbert char b[32]; 4601da177e4SLinus Torvalds 461c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 4621da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 4631da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 4641da177e4SLinus Torvalds arr[1] = 0x1; 4651da177e4SLinus Torvalds arr[2] = 0x0; 4661da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 4671da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 4681da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 4691da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 4701da177e4SLinus Torvalds arr[3] = num; 4711da177e4SLinus Torvalds num += 4; 472c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 473c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 474c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 475c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 476c65b1445SDouglas Gilbert arr[num++] = 0x0; 477c65b1445SDouglas Gilbert arr[num++] = 0x8; 478c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 479c65b1445SDouglas Gilbert arr[num++] = 0x33; 480c65b1445SDouglas Gilbert arr[num++] = 0x33; 481c65b1445SDouglas Gilbert arr[num++] = 0x30; 482c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 483c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 484c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 485c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 486c65b1445SDouglas Gilbert /* Target relative port number */ 487c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 488c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 489c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 490c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 491c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 492c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 493c65b1445SDouglas Gilbert arr[num++] = 0x0; 494c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 495c65b1445SDouglas Gilbert } 496c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 497c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 498c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 499c65b1445SDouglas Gilbert arr[num++] = 0x0; 500c65b1445SDouglas Gilbert arr[num++] = 0x8; 501c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 502c65b1445SDouglas Gilbert arr[num++] = 0x22; 503c65b1445SDouglas Gilbert arr[num++] = 0x22; 504c65b1445SDouglas Gilbert arr[num++] = 0x20; 505c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 506c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 507c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 508c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 5095a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 5105a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 5115a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 5125a09e398SHannes Reinecke arr[num++] = 0x0; 5135a09e398SHannes Reinecke arr[num++] = 0x4; 5145a09e398SHannes Reinecke arr[num++] = 0; 5155a09e398SHannes Reinecke arr[num++] = 0; 5165a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 5175a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 518c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 519c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 520c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 521c65b1445SDouglas Gilbert arr[num++] = 0x0; 522c65b1445SDouglas Gilbert arr[num++] = 0x8; 523c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 524c65b1445SDouglas Gilbert arr[num++] = 0x22; 525c65b1445SDouglas Gilbert arr[num++] = 0x22; 526c65b1445SDouglas Gilbert arr[num++] = 0x20; 527c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 528c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 529c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 530c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 531c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 532c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 533c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 534c65b1445SDouglas Gilbert arr[num++] = 0x0; 535c65b1445SDouglas Gilbert arr[num++] = 24; 536c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 537c65b1445SDouglas Gilbert num += 12; 538c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 539c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 540c65b1445SDouglas Gilbert num += 8; 541c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 542c65b1445SDouglas Gilbert num += 4; 543c65b1445SDouglas Gilbert return num; 544c65b1445SDouglas Gilbert } 545c65b1445SDouglas Gilbert 546c65b1445SDouglas Gilbert 547c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 548c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 549c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 550c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 551c65b1445SDouglas Gilbert }; 552c65b1445SDouglas Gilbert 553c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 554c65b1445SDouglas Gilbert { 555c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 556c65b1445SDouglas Gilbert return sizeof(vpd84_data); 557c65b1445SDouglas Gilbert } 558c65b1445SDouglas Gilbert 559c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 560c65b1445SDouglas Gilbert { 561c65b1445SDouglas Gilbert int num = 0; 562c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 563c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 564c65b1445SDouglas Gilbert int plen, olen; 565c65b1445SDouglas Gilbert 566c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 567c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 568c65b1445SDouglas Gilbert arr[num++] = 0x0; 569c65b1445SDouglas Gilbert olen = strlen(na1); 570c65b1445SDouglas Gilbert plen = olen + 1; 571c65b1445SDouglas Gilbert if (plen % 4) 572c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 573c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 574c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 575c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 576c65b1445SDouglas Gilbert num += plen; 577c65b1445SDouglas Gilbert 578c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 579c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 580c65b1445SDouglas Gilbert arr[num++] = 0x0; 581c65b1445SDouglas Gilbert olen = strlen(na2); 582c65b1445SDouglas Gilbert plen = olen + 1; 583c65b1445SDouglas Gilbert if (plen % 4) 584c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 585c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 586c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 587c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 588c65b1445SDouglas Gilbert num += plen; 589c65b1445SDouglas Gilbert 590c65b1445SDouglas Gilbert return num; 591c65b1445SDouglas Gilbert } 592c65b1445SDouglas Gilbert 593c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 594c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 595c65b1445SDouglas Gilbert { 596c65b1445SDouglas Gilbert int num = 0; 597c65b1445SDouglas Gilbert int port_a, port_b; 598c65b1445SDouglas Gilbert 599c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 600c65b1445SDouglas Gilbert port_b = port_a + 1; 601c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 602c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 603c65b1445SDouglas Gilbert arr[num++] = 0x0; 604c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 605c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 606c65b1445SDouglas Gilbert num += 6; 607c65b1445SDouglas Gilbert arr[num++] = 0x0; 608c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 609c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 610c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 611c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 612c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 613c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 614c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 615c65b1445SDouglas Gilbert arr[num++] = 0x22; 616c65b1445SDouglas Gilbert arr[num++] = 0x22; 617c65b1445SDouglas Gilbert arr[num++] = 0x20; 618c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 619c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 620c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 621c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 622c65b1445SDouglas Gilbert 623c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 624c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 625c65b1445SDouglas Gilbert arr[num++] = 0x0; 626c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 627c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 628c65b1445SDouglas Gilbert num += 6; 629c65b1445SDouglas Gilbert arr[num++] = 0x0; 630c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 631c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 632c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 633c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 634c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 635c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 636c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 637c65b1445SDouglas Gilbert arr[num++] = 0x22; 638c65b1445SDouglas Gilbert arr[num++] = 0x22; 639c65b1445SDouglas Gilbert arr[num++] = 0x20; 640c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 641c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 642c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 643c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 644c65b1445SDouglas Gilbert 645c65b1445SDouglas Gilbert return num; 646c65b1445SDouglas Gilbert } 647c65b1445SDouglas Gilbert 648c65b1445SDouglas Gilbert 649c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 650c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 651c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 652c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 653c65b1445SDouglas Gilbert '1','2','3','4', 654c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 655c65b1445SDouglas Gilbert 0xec,0,0,0, 656c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 657c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 658c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 659c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 660c65b1445SDouglas Gilbert 0x53,0x41, 661c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 662c65b1445SDouglas Gilbert 0x20,0x20, 663c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 664c65b1445SDouglas Gilbert 0x10,0x80, 665c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 666c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 667c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 668c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 669c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 670c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 671c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 672c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 673c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 674c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 675c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 676c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 677c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 678c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 679c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 680c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 681c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 682c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 683c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 684c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 685c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 686c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 687c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 688c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 689c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 690c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 691c65b1445SDouglas Gilbert }; 692c65b1445SDouglas Gilbert 693c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 694c65b1445SDouglas Gilbert { 695c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 696c65b1445SDouglas Gilbert return sizeof(vpd89_data); 697c65b1445SDouglas Gilbert } 698c65b1445SDouglas Gilbert 699c65b1445SDouglas Gilbert 7001e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 701c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 7021e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 7031e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7041e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7051e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 706c65b1445SDouglas Gilbert }; 707c65b1445SDouglas Gilbert 708c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 709c65b1445SDouglas Gilbert { 710ea61fca5SMartin K. Petersen unsigned int gran; 711ea61fca5SMartin K. Petersen 712c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 713e308b3d1SMartin K. Petersen 714e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 715ea61fca5SMartin K. Petersen gran = 1 << scsi_debug_physblk_exp; 716ea61fca5SMartin K. Petersen arr[2] = (gran >> 8) & 0xff; 717ea61fca5SMartin K. Petersen arr[3] = gran & 0xff; 718e308b3d1SMartin K. Petersen 719e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 720c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 721c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 722c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 723c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 724c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 725c65b1445SDouglas Gilbert } 72644d92694SMartin K. Petersen 727e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 728e308b3d1SMartin K. Petersen put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); 729e308b3d1SMartin K. Petersen 7306014759cSMartin K. Petersen if (scsi_debug_tpu) { 731e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 7326014759cSMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); 733e308b3d1SMartin K. Petersen 734e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 73544d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); 73644d92694SMartin K. Petersen } 73744d92694SMartin K. Petersen 738e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 73944d92694SMartin K. Petersen if (scsi_debug_unmap_alignment) { 74044d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); 74144d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 74244d92694SMartin K. Petersen } 74344d92694SMartin K. Petersen 744e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 74544d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); 7466014759cSMartin K. Petersen 74744d92694SMartin K. Petersen return 0x3c; /* Mandatory page length for thin provisioning */ 74844d92694SMartin K. Petersen 749c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 7501da177e4SLinus Torvalds } 7511da177e4SLinus Torvalds 7521e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 753eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 754eac6e8e4SMatthew Wilcox { 755eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 756eac6e8e4SMatthew Wilcox arr[0] = 0; 7571e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 7581e49f785SDouglas Gilbert arr[2] = 0; 7591e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 760eac6e8e4SMatthew Wilcox 761eac6e8e4SMatthew Wilcox return 0x3c; 762eac6e8e4SMatthew Wilcox } 7631da177e4SLinus Torvalds 7646014759cSMartin K. Petersen /* Thin provisioning VPD page (SBC-3) */ 7656014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 7666014759cSMartin K. Petersen { 7676014759cSMartin K. Petersen memset(arr, 0, 0x8); 7686014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 7696014759cSMartin K. Petersen 7706014759cSMartin K. Petersen if (scsi_debug_tpu) 7716014759cSMartin K. Petersen arr[1] = 1 << 7; 7726014759cSMartin K. Petersen 7736014759cSMartin K. Petersen if (scsi_debug_tpws) 7746014759cSMartin K. Petersen arr[1] |= 1 << 6; 7756014759cSMartin K. Petersen 7766014759cSMartin K. Petersen return 0x8; 7776014759cSMartin K. Petersen } 7786014759cSMartin K. Petersen 7791da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 780c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 7811da177e4SLinus Torvalds 7821da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 7831da177e4SLinus Torvalds struct sdebug_dev_info * devip) 7841da177e4SLinus Torvalds { 7851da177e4SLinus Torvalds unsigned char pq_pdt; 7865a09e398SHannes Reinecke unsigned char * arr; 7871da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 7885a09e398SHannes Reinecke int alloc_len, n, ret; 7891da177e4SLinus Torvalds 7901da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 7916f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 7926f3cbf55SDouglas Gilbert if (! arr) 7936f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 794c65b1445SDouglas Gilbert if (devip->wlun) 795c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 796c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 797c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 798c65b1445SDouglas Gilbert else 7991da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 8001da177e4SLinus Torvalds arr[0] = pq_pdt; 8011da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 8021da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 8031da177e4SLinus Torvalds 0); 8045a09e398SHannes Reinecke kfree(arr); 8051da177e4SLinus Torvalds return check_condition_result; 8061da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 8075a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 808c65b1445SDouglas Gilbert char lu_id_str[6]; 809c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 8101da177e4SLinus Torvalds 8115a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 8125a09e398SHannes Reinecke (devip->channel & 0x7f); 81323183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 81423183910SDouglas Gilbert host_no = 0; 815c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 816c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 817c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 818c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 819c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 8201da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 821c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 822c65b1445SDouglas Gilbert n = 4; 823c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 824c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 825c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 826c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 827c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 828c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 829c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 830c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 831c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 832c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 833eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 8346014759cSMartin K. Petersen arr[n++] = 0xb2; /* Thin provisioning (SBC) */ 835c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 8361da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 837c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8381da177e4SLinus Torvalds arr[3] = len; 839c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 8401da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 841c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8425a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 8435a09e398SHannes Reinecke target_dev_id, lu_id_num, 8445a09e398SHannes Reinecke lu_id_str, len); 845c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 846c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 847c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 848c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 849c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 850c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 851c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 852c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 853c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 854c6a44287SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) 855c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 856c6a44287SMartin K. Petersen else if (scsi_debug_dif) 857c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 858c6a44287SMartin K. Petersen else 859c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 860c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 861c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 862c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 863c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 864c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 865c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 866c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 867c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 868c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 869c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 870c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 871c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 872c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 873c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 874c65b1445SDouglas Gilbert arr[2] = (n >> 8); 875c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 876c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 877c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 878c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 879eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 880eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 881eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 8826014759cSMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Thin provisioning (SBC) */ 8836014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 8846014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 8851da177e4SLinus Torvalds } else { 8861da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 8871da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 8881da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 8895a09e398SHannes Reinecke kfree(arr); 8901da177e4SLinus Torvalds return check_condition_result; 8911da177e4SLinus Torvalds } 892c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 8935a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 894c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 8955a09e398SHannes Reinecke kfree(arr); 8965a09e398SHannes Reinecke return ret; 8971da177e4SLinus Torvalds } 8981da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 8991da177e4SLinus Torvalds arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */ 9001da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 9011da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 9021da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 903c6a44287SMartin K. Petersen arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ 9045a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 9055a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 906c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 9071da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 908c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 9091da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 9101da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 9111da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 9121da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 913c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 914c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 915c65b1445SDouglas Gilbert n = 62; 9161da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 917c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 9181da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 919c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 9201da177e4SLinus Torvalds } 921c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 9225a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 9231da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 9245a09e398SHannes Reinecke kfree(arr); 9255a09e398SHannes Reinecke return ret; 9261da177e4SLinus Torvalds } 9271da177e4SLinus Torvalds 9281da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 9291da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9301da177e4SLinus Torvalds { 9311da177e4SLinus Torvalds unsigned char * sbuff; 9321da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 9331da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 934c65b1445SDouglas Gilbert int want_dsense; 9351da177e4SLinus Torvalds int len = 18; 9361da177e4SLinus Torvalds 937c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9381da177e4SLinus Torvalds if (devip->reset == 1) 939c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 940c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 9411da177e4SLinus Torvalds sbuff = devip->sense_buff; 942c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 943c65b1445SDouglas Gilbert if (want_dsense) { 944c65b1445SDouglas Gilbert arr[0] = 0x72; 945c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 946c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 947c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 948c65b1445SDouglas Gilbert } else { 949c65b1445SDouglas Gilbert arr[0] = 0x70; 950c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 951c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 952c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 953c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 954c65b1445SDouglas Gilbert } 955c65b1445SDouglas Gilbert } else { 956c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 9571da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 9581da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 959c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9601da177e4SLinus Torvalds arr[0] = 0x72; 9611da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 9621da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 9631da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 9641da177e4SLinus Torvalds len = 8; 965c65b1445SDouglas Gilbert } 966c65b1445SDouglas Gilbert } 967c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 9681da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 9691da177e4SLinus Torvalds } 9701da177e4SLinus Torvalds 971c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 972c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 973c65b1445SDouglas Gilbert { 974c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 975c65b1445SDouglas Gilbert int power_cond, errsts, start; 976c65b1445SDouglas Gilbert 977c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 978c65b1445SDouglas Gilbert return errsts; 979c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 980c65b1445SDouglas Gilbert if (power_cond) { 981c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 982c65b1445SDouglas Gilbert 0); 983c65b1445SDouglas Gilbert return check_condition_result; 984c65b1445SDouglas Gilbert } 985c65b1445SDouglas Gilbert start = cmd[4] & 1; 986c65b1445SDouglas Gilbert if (start == devip->stopped) 987c65b1445SDouglas Gilbert devip->stopped = !start; 988c65b1445SDouglas Gilbert return 0; 989c65b1445SDouglas Gilbert } 990c65b1445SDouglas Gilbert 99128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 99228898873SFUJITA Tomonori { 99328898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 9945447ed6cSDouglas Gilbert return (sector_t)scsi_debug_virtual_gb * 9955447ed6cSDouglas Gilbert (1073741824 / scsi_debug_sector_size); 99628898873SFUJITA Tomonori else 99728898873SFUJITA Tomonori return sdebug_store_sectors; 99828898873SFUJITA Tomonori } 99928898873SFUJITA Tomonori 10001da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 10011da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 10021da177e4SLinus Torvalds struct sdebug_dev_info * devip) 10031da177e4SLinus Torvalds { 10041da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1005c65b1445SDouglas Gilbert unsigned int capac; 10061da177e4SLinus Torvalds int errsts; 10071da177e4SLinus Torvalds 1008c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 10091da177e4SLinus Torvalds return errsts; 1010c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 101128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 10121da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1013c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1014c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 10151da177e4SLinus Torvalds arr[0] = (capac >> 24); 10161da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 10171da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 10181da177e4SLinus Torvalds arr[3] = capac & 0xff; 1019c65b1445SDouglas Gilbert } else { 1020c65b1445SDouglas Gilbert arr[0] = 0xff; 1021c65b1445SDouglas Gilbert arr[1] = 0xff; 1022c65b1445SDouglas Gilbert arr[2] = 0xff; 1023c65b1445SDouglas Gilbert arr[3] = 0xff; 1024c65b1445SDouglas Gilbert } 1025597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 1026597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 10271da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 10281da177e4SLinus Torvalds } 10291da177e4SLinus Torvalds 1030c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1031c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1032c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1033c65b1445SDouglas Gilbert { 1034c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1035c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1036c65b1445SDouglas Gilbert unsigned long long capac; 1037c65b1445SDouglas Gilbert int errsts, k, alloc_len; 1038c65b1445SDouglas Gilbert 1039c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1040c65b1445SDouglas Gilbert return errsts; 1041c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1042c65b1445SDouglas Gilbert + cmd[13]); 1043c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 104428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1045c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1046c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1047c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1048c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1049597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 1050597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 1051597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 1052597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 1053ea61fca5SMartin K. Petersen arr[13] = scsi_debug_physblk_exp & 0xf; 1054ea61fca5SMartin K. Petersen arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; 105544d92694SMartin K. Petersen 10566014759cSMartin K. Petersen if (scsi_debug_tpu || scsi_debug_tpws) 105744d92694SMartin K. Petersen arr[14] |= 0x80; /* TPE */ 105844d92694SMartin K. Petersen 1059ea61fca5SMartin K. Petersen arr[15] = scsi_debug_lowest_aligned & 0xff; 1060c6a44287SMartin K. Petersen 1061c6a44287SMartin K. Petersen if (scsi_debug_dif) { 1062c6a44287SMartin K. Petersen arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ 1063c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1064c6a44287SMartin K. Petersen } 1065c6a44287SMartin K. Petersen 1066c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1067c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1068c65b1445SDouglas Gilbert } 1069c65b1445SDouglas Gilbert 10705a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 10715a09e398SHannes Reinecke 10725a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 10735a09e398SHannes Reinecke struct sdebug_dev_info * devip) 10745a09e398SHannes Reinecke { 10755a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 10765a09e398SHannes Reinecke unsigned char * arr; 10775a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 10785a09e398SHannes Reinecke int n, ret, alen, rlen; 10795a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 10805a09e398SHannes Reinecke 10815a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 10825a09e398SHannes Reinecke + cmd[9]); 10835a09e398SHannes Reinecke 10846f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 10856f3cbf55SDouglas Gilbert if (! arr) 10866f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 10875a09e398SHannes Reinecke /* 10885a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 10895a09e398SHannes Reinecke * real and a fake port with no device connected. 10905a09e398SHannes Reinecke * So we create two port groups with one port each 10915a09e398SHannes Reinecke * and set the group with port B to unavailable. 10925a09e398SHannes Reinecke */ 10935a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 10945a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 10955a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 10965a09e398SHannes Reinecke (devip->channel & 0x7f); 10975a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 10985a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 10995a09e398SHannes Reinecke 11005a09e398SHannes Reinecke /* 11015a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 11025a09e398SHannes Reinecke */ 11035a09e398SHannes Reinecke n = 4; 11045a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 11055a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 11065a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 11075a09e398SHannes Reinecke } else { 11085a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 11095a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 11105a09e398SHannes Reinecke } 11115a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 11125a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 11135a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11145a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11155a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11165a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11175a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11185a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11195a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 11205a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 11215a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 11225a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 11235a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 11245a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 11255a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11265a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11275a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11285a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11295a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11305a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11315a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 11325a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 11335a09e398SHannes Reinecke 11345a09e398SHannes Reinecke rlen = n - 4; 11355a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 11365a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 11375a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 11385a09e398SHannes Reinecke arr[3] = rlen & 0xff; 11395a09e398SHannes Reinecke 11405a09e398SHannes Reinecke /* 11415a09e398SHannes Reinecke * Return the smallest value of either 11425a09e398SHannes Reinecke * - The allocated length 11435a09e398SHannes Reinecke * - The constructed command length 11445a09e398SHannes Reinecke * - The maximum array size 11455a09e398SHannes Reinecke */ 11465a09e398SHannes Reinecke rlen = min(alen,n); 11475a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 11485a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 11495a09e398SHannes Reinecke kfree(arr); 11505a09e398SHannes Reinecke return ret; 11515a09e398SHannes Reinecke } 11525a09e398SHannes Reinecke 11531da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 11541da177e4SLinus Torvalds 11551da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 11561da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 11571da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 11581da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 11591da177e4SLinus Torvalds 11601da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 11611da177e4SLinus Torvalds if (1 == pcontrol) 11621da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 11631da177e4SLinus Torvalds return sizeof(err_recov_pg); 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds 11661da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 11671da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 11681da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 11691da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 11701da177e4SLinus Torvalds 11711da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 11721da177e4SLinus Torvalds if (1 == pcontrol) 11731da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 11741da177e4SLinus Torvalds return sizeof(disconnect_pg); 11751da177e4SLinus Torvalds } 11761da177e4SLinus Torvalds 11771da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 11781da177e4SLinus Torvalds { /* Format device page for mode_sense */ 11791da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 11801da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 11811da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 11821da177e4SLinus Torvalds 11831da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 11841da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 11851da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1186597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1187597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 11881da177e4SLinus Torvalds if (DEV_REMOVEABLE(target)) 11891da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 11901da177e4SLinus Torvalds if (1 == pcontrol) 11911da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 11921da177e4SLinus Torvalds return sizeof(format_pg); 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds 11951da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 11961da177e4SLinus Torvalds { /* Caching page for mode_sense */ 11971da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 11981da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 12011da177e4SLinus Torvalds if (1 == pcontrol) 12021da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 12031da177e4SLinus Torvalds return sizeof(caching_pg); 12041da177e4SLinus Torvalds } 12051da177e4SLinus Torvalds 12061da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 12071da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1208c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1209c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1210c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 12111da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds if (scsi_debug_dsense) 12141da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1215c65b1445SDouglas Gilbert else 1216c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1217c6a44287SMartin K. Petersen 1218c6a44287SMartin K. Petersen if (scsi_debug_ato) 1219c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1220c6a44287SMartin K. Petersen 12211da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 12221da177e4SLinus Torvalds if (1 == pcontrol) 1223c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1224c65b1445SDouglas Gilbert else if (2 == pcontrol) 1225c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 12261da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 1229c65b1445SDouglas Gilbert 12301da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 12311da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1232c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 12331da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1234c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1235c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1236c65b1445SDouglas Gilbert 12371da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 12381da177e4SLinus Torvalds if (1 == pcontrol) 1239c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1240c65b1445SDouglas Gilbert else if (2 == pcontrol) 1241c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 12421da177e4SLinus Torvalds return sizeof(iec_m_pg); 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds 1245c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1246c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1247c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1248c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1249c65b1445SDouglas Gilbert 1250c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1251c65b1445SDouglas Gilbert if (1 == pcontrol) 1252c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1253c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1254c65b1445SDouglas Gilbert } 1255c65b1445SDouglas Gilbert 1256c65b1445SDouglas Gilbert 1257c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1258c65b1445SDouglas Gilbert int target_dev_id) 1259c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1260c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1261c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1262c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1263c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1264c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1265c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1266c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1267c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1268c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1269c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1270c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1271c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1272c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1273c65b1445SDouglas Gilbert }; 1274c65b1445SDouglas Gilbert int port_a, port_b; 1275c65b1445SDouglas Gilbert 1276c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1277c65b1445SDouglas Gilbert port_b = port_a + 1; 1278c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1279c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1280c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1281c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1282c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1283c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1284c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1285c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1286c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1287c65b1445SDouglas Gilbert if (1 == pcontrol) 1288c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1289c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1290c65b1445SDouglas Gilbert } 1291c65b1445SDouglas Gilbert 1292c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1293c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1294c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1295c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1296c65b1445SDouglas Gilbert }; 1297c65b1445SDouglas Gilbert 1298c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1299c65b1445SDouglas Gilbert if (1 == pcontrol) 1300c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1301c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1302c65b1445SDouglas Gilbert } 1303c65b1445SDouglas Gilbert 13041da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 13051da177e4SLinus Torvalds 13061da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 13071da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13081da177e4SLinus Torvalds { 130923183910SDouglas Gilbert unsigned char dbd, llbaa; 131023183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 13111da177e4SLinus Torvalds unsigned char dev_spec; 131223183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 13131da177e4SLinus Torvalds unsigned char * ap; 13141da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 13151da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 13161da177e4SLinus Torvalds 1317c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 13181da177e4SLinus Torvalds return errsts; 131923183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 13201da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 13211da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 13221da177e4SLinus Torvalds subpcode = cmd[3]; 13231da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 132423183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 132523183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 132623183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 132723183910SDouglas Gilbert else 132823183910SDouglas Gilbert bd_len = 0; 13291da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 13301da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 13311da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 13321da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 13331da177e4SLinus Torvalds 0); 13341da177e4SLinus Torvalds return check_condition_result; 13351da177e4SLinus Torvalds } 1336c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1337c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 133823183910SDouglas Gilbert /* set DPOFUA bit for disks */ 133923183910SDouglas Gilbert if (0 == scsi_debug_ptype) 134023183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 134123183910SDouglas Gilbert else 134223183910SDouglas Gilbert dev_spec = 0x0; 13431da177e4SLinus Torvalds if (msense_6) { 13441da177e4SLinus Torvalds arr[2] = dev_spec; 134523183910SDouglas Gilbert arr[3] = bd_len; 13461da177e4SLinus Torvalds offset = 4; 13471da177e4SLinus Torvalds } else { 13481da177e4SLinus Torvalds arr[3] = dev_spec; 134923183910SDouglas Gilbert if (16 == bd_len) 135023183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 135123183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 13521da177e4SLinus Torvalds offset = 8; 13531da177e4SLinus Torvalds } 13541da177e4SLinus Torvalds ap = arr + offset; 135528898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 135628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 135728898873SFUJITA Tomonori 135823183910SDouglas Gilbert if (8 == bd_len) { 135923183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 136023183910SDouglas Gilbert ap[0] = 0xff; 136123183910SDouglas Gilbert ap[1] = 0xff; 136223183910SDouglas Gilbert ap[2] = 0xff; 136323183910SDouglas Gilbert ap[3] = 0xff; 136423183910SDouglas Gilbert } else { 136523183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 136623183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 136723183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 136823183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 136923183910SDouglas Gilbert } 1370597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 1371597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 137223183910SDouglas Gilbert offset += bd_len; 137323183910SDouglas Gilbert ap = arr + offset; 137423183910SDouglas Gilbert } else if (16 == bd_len) { 137523183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 137623183910SDouglas Gilbert 137723183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 137823183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 1379597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 1380597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 1381597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 1382597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 138323183910SDouglas Gilbert offset += bd_len; 138423183910SDouglas Gilbert ap = arr + offset; 138523183910SDouglas Gilbert } 13861da177e4SLinus Torvalds 1387c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1388c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 13891da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 13901da177e4SLinus Torvalds 0); 13911da177e4SLinus Torvalds return check_condition_result; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds switch (pcode) { 13941da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 13951da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 13961da177e4SLinus Torvalds offset += len; 13971da177e4SLinus Torvalds break; 13981da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 13991da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 14001da177e4SLinus Torvalds offset += len; 14011da177e4SLinus Torvalds break; 14021da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 14031da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 14041da177e4SLinus Torvalds offset += len; 14051da177e4SLinus Torvalds break; 14061da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 14071da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 14081da177e4SLinus Torvalds offset += len; 14091da177e4SLinus Torvalds break; 14101da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 14111da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 14121da177e4SLinus Torvalds offset += len; 14131da177e4SLinus Torvalds break; 1414c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1415c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1416c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1417c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1418c65b1445SDouglas Gilbert return check_condition_result; 1419c65b1445SDouglas Gilbert } 1420c65b1445SDouglas Gilbert len = 0; 1421c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1422c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1423c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1424c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1425c65b1445SDouglas Gilbert target_dev_id); 1426c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1427c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1428c65b1445SDouglas Gilbert offset += len; 1429c65b1445SDouglas Gilbert break; 14301da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 14311da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 14321da177e4SLinus Torvalds offset += len; 14331da177e4SLinus Torvalds break; 14341da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1435c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 14361da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14371da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 14381da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 14391da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 14401da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1441c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1442c65b1445SDouglas Gilbert if (0xff == subpcode) { 1443c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1444c65b1445SDouglas Gilbert target, target_dev_id); 1445c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1446c65b1445SDouglas Gilbert } 14471da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1448c65b1445SDouglas Gilbert } else { 1449c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1450c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1451c65b1445SDouglas Gilbert return check_condition_result; 1452c65b1445SDouglas Gilbert } 14531da177e4SLinus Torvalds offset += len; 14541da177e4SLinus Torvalds break; 14551da177e4SLinus Torvalds default: 14561da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14571da177e4SLinus Torvalds 0); 14581da177e4SLinus Torvalds return check_condition_result; 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds if (msense_6) 14611da177e4SLinus Torvalds arr[0] = offset - 1; 14621da177e4SLinus Torvalds else { 14631da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 14641da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 14651da177e4SLinus Torvalds } 14661da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 14671da177e4SLinus Torvalds } 14681da177e4SLinus Torvalds 1469c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1470c65b1445SDouglas Gilbert 1471c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1472c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1473c65b1445SDouglas Gilbert { 1474c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1475c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1476c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1477c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1478c65b1445SDouglas Gilbert 1479c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1480c65b1445SDouglas Gilbert return errsts; 1481c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1482c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1483c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1484c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1485c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1486c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1487c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1488c65b1445SDouglas Gilbert return check_condition_result; 1489c65b1445SDouglas Gilbert } 1490c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1491c65b1445SDouglas Gilbert if (-1 == res) 1492c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1493c65b1445SDouglas Gilbert else if ((res < param_len) && 1494c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1495c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1496c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1497c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1498c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 149923183910SDouglas Gilbert if (md_len > 2) { 1500c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1501c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1502c65b1445SDouglas Gilbert return check_condition_result; 1503c65b1445SDouglas Gilbert } 1504c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1505c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1506c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1507c65b1445SDouglas Gilbert if (ps) { 1508c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1509c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1510c65b1445SDouglas Gilbert return check_condition_result; 1511c65b1445SDouglas Gilbert } 1512c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1513c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1514c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1515c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1516c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1517c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1518c65b1445SDouglas Gilbert return check_condition_result; 1519c65b1445SDouglas Gilbert } 1520c65b1445SDouglas Gilbert switch (mpage) { 1521c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1522c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1523c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1524c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1525c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1526c65b1445SDouglas Gilbert return 0; 1527c65b1445SDouglas Gilbert } 1528c65b1445SDouglas Gilbert break; 1529c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1530c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1531c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1532c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1533c65b1445SDouglas Gilbert return 0; 1534c65b1445SDouglas Gilbert } 1535c65b1445SDouglas Gilbert break; 1536c65b1445SDouglas Gilbert default: 1537c65b1445SDouglas Gilbert break; 1538c65b1445SDouglas Gilbert } 1539c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1540c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1541c65b1445SDouglas Gilbert return check_condition_result; 1542c65b1445SDouglas Gilbert } 1543c65b1445SDouglas Gilbert 1544c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1545c65b1445SDouglas Gilbert { 1546c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1547c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1548c65b1445SDouglas Gilbert }; 1549c65b1445SDouglas Gilbert 1550c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1551c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1552c65b1445SDouglas Gilbert } 1553c65b1445SDouglas Gilbert 1554c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1555c65b1445SDouglas Gilbert { 1556c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1557c65b1445SDouglas Gilbert }; 1558c65b1445SDouglas Gilbert 1559c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1560c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1561c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1562c65b1445SDouglas Gilbert arr[5] = 0xff; 1563c65b1445SDouglas Gilbert } 1564c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1565c65b1445SDouglas Gilbert } 1566c65b1445SDouglas Gilbert 1567c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1568c65b1445SDouglas Gilbert 1569c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1570c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1571c65b1445SDouglas Gilbert { 157223183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1573c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1574c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1575c65b1445SDouglas Gilbert 1576c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1577c65b1445SDouglas Gilbert return errsts; 1578c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1579c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1580c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1581c65b1445SDouglas Gilbert if (ppc || sp) { 1582c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1583c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1584c65b1445SDouglas Gilbert return check_condition_result; 1585c65b1445SDouglas Gilbert } 1586c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1587c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 158823183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1589c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1590c65b1445SDouglas Gilbert arr[0] = pcode; 159123183910SDouglas Gilbert if (0 == subpcode) { 1592c65b1445SDouglas Gilbert switch (pcode) { 1593c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1594c65b1445SDouglas Gilbert n = 4; 1595c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1596c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1597c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1598c65b1445SDouglas Gilbert arr[3] = n - 4; 1599c65b1445SDouglas Gilbert break; 1600c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1601c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1602c65b1445SDouglas Gilbert break; 1603c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1604c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1605c65b1445SDouglas Gilbert break; 1606c65b1445SDouglas Gilbert default: 1607c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1608c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1609c65b1445SDouglas Gilbert return check_condition_result; 1610c65b1445SDouglas Gilbert } 161123183910SDouglas Gilbert } else if (0xff == subpcode) { 161223183910SDouglas Gilbert arr[0] |= 0x40; 161323183910SDouglas Gilbert arr[1] = subpcode; 161423183910SDouglas Gilbert switch (pcode) { 161523183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 161623183910SDouglas Gilbert n = 4; 161723183910SDouglas Gilbert arr[n++] = 0x0; 161823183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 161923183910SDouglas Gilbert arr[n++] = 0x0; 162023183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 162123183910SDouglas Gilbert arr[n++] = 0xd; 162223183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 162323183910SDouglas Gilbert arr[n++] = 0x2f; 162423183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 162523183910SDouglas Gilbert arr[3] = n - 4; 162623183910SDouglas Gilbert break; 162723183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 162823183910SDouglas Gilbert n = 4; 162923183910SDouglas Gilbert arr[n++] = 0xd; 163023183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 163123183910SDouglas Gilbert arr[3] = n - 4; 163223183910SDouglas Gilbert break; 163323183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 163423183910SDouglas Gilbert n = 4; 163523183910SDouglas Gilbert arr[n++] = 0x2f; 163623183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 163723183910SDouglas Gilbert arr[3] = n - 4; 163823183910SDouglas Gilbert break; 163923183910SDouglas Gilbert default: 164023183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 164123183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 164223183910SDouglas Gilbert return check_condition_result; 164323183910SDouglas Gilbert } 164423183910SDouglas Gilbert } else { 164523183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 164623183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 164723183910SDouglas Gilbert return check_condition_result; 164823183910SDouglas Gilbert } 1649c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1650c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1651c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1652c65b1445SDouglas Gilbert } 1653c65b1445SDouglas Gilbert 165419789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi, 165519789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 16561da177e4SLinus Torvalds { 1657c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 165819789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); 16591da177e4SLinus Torvalds return check_condition_result; 16601da177e4SLinus Torvalds } 1661c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1662c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 166319789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 1664c65b1445SDouglas Gilbert return check_condition_result; 1665c65b1445SDouglas Gilbert } 166619789100SFUJITA Tomonori return 0; 166719789100SFUJITA Tomonori } 166819789100SFUJITA Tomonori 166919789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd, 167019789100SFUJITA Tomonori struct sdebug_dev_info *devi, 167119789100SFUJITA Tomonori unsigned long long lba, unsigned int num, int write) 167219789100SFUJITA Tomonori { 167319789100SFUJITA Tomonori int ret; 167419789100SFUJITA Tomonori unsigned int block, rest = 0; 167519789100SFUJITA Tomonori int (*func)(struct scsi_cmnd *, unsigned char *, int); 167619789100SFUJITA Tomonori 167719789100SFUJITA Tomonori func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; 167819789100SFUJITA Tomonori 167919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 168019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 168119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 168219789100SFUJITA Tomonori 1683597136abSMartin K. Petersen ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), 1684597136abSMartin K. Petersen (num - rest) * scsi_debug_sector_size); 168519789100SFUJITA Tomonori if (!ret && rest) 1686597136abSMartin K. Petersen ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); 168719789100SFUJITA Tomonori 168819789100SFUJITA Tomonori return ret; 168919789100SFUJITA Tomonori } 169019789100SFUJITA Tomonori 1691c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 1692395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 1693c6a44287SMartin K. Petersen { 1694c6a44287SMartin K. Petersen unsigned int i, resid; 1695c6a44287SMartin K. Petersen struct scatterlist *psgl; 1696c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 1697c6a44287SMartin K. Petersen sector_t sector; 1698c6a44287SMartin K. Petersen sector_t tmp_sec = start_sec; 1699c6a44287SMartin K. Petersen void *paddr; 1700c6a44287SMartin K. Petersen 1701c6a44287SMartin K. Petersen start_sec = do_div(tmp_sec, sdebug_store_sectors); 1702c6a44287SMartin K. Petersen 1703c6a44287SMartin K. Petersen sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); 1704c6a44287SMartin K. Petersen 1705c6a44287SMartin K. Petersen for (i = 0 ; i < sectors ; i++) { 1706c6a44287SMartin K. Petersen u16 csum; 1707c6a44287SMartin K. Petersen 1708c6a44287SMartin K. Petersen if (sdt[i].app_tag == 0xffff) 1709c6a44287SMartin K. Petersen continue; 1710c6a44287SMartin K. Petersen 1711c6a44287SMartin K. Petersen sector = start_sec + i; 1712c6a44287SMartin K. Petersen 1713c6a44287SMartin K. Petersen switch (scsi_debug_guard) { 1714c6a44287SMartin K. Petersen case 1: 1715c6a44287SMartin K. Petersen csum = ip_compute_csum(fake_storep + 1716c6a44287SMartin K. Petersen sector * scsi_debug_sector_size, 1717c6a44287SMartin K. Petersen scsi_debug_sector_size); 1718c6a44287SMartin K. Petersen break; 1719c6a44287SMartin K. Petersen case 0: 1720c6a44287SMartin K. Petersen csum = crc_t10dif(fake_storep + 1721c6a44287SMartin K. Petersen sector * scsi_debug_sector_size, 1722c6a44287SMartin K. Petersen scsi_debug_sector_size); 1723c6a44287SMartin K. Petersen csum = cpu_to_be16(csum); 1724c6a44287SMartin K. Petersen break; 1725c6a44287SMartin K. Petersen default: 1726c6a44287SMartin K. Petersen BUG(); 1727c6a44287SMartin K. Petersen } 1728c6a44287SMartin K. Petersen 1729c6a44287SMartin K. Petersen if (sdt[i].guard_tag != csum) { 1730c6a44287SMartin K. Petersen printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ 1731c6a44287SMartin K. Petersen " rcvd 0x%04x, data 0x%04x\n", __func__, 1732c6a44287SMartin K. Petersen (unsigned long)sector, 1733c6a44287SMartin K. Petersen be16_to_cpu(sdt[i].guard_tag), 1734c6a44287SMartin K. Petersen be16_to_cpu(csum)); 1735c6a44287SMartin K. Petersen dif_errors++; 1736c6a44287SMartin K. Petersen return 0x01; 1737c6a44287SMartin K. Petersen } 1738c6a44287SMartin K. Petersen 1739395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1740c6a44287SMartin K. Petersen be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { 1741c6a44287SMartin K. Petersen printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1742c6a44287SMartin K. Petersen __func__, (unsigned long)sector); 1743c6a44287SMartin K. Petersen dif_errors++; 1744c6a44287SMartin K. Petersen return 0x03; 1745c6a44287SMartin K. Petersen } 1746395cef03SMartin K. Petersen 1747395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1748395cef03SMartin K. Petersen be32_to_cpu(sdt[i].ref_tag) != ei_lba) { 1749395cef03SMartin K. Petersen printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1750395cef03SMartin K. Petersen __func__, (unsigned long)sector); 1751395cef03SMartin K. Petersen dif_errors++; 1752395cef03SMartin K. Petersen return 0x03; 1753395cef03SMartin K. Petersen } 1754395cef03SMartin K. Petersen 1755395cef03SMartin K. Petersen ei_lba++; 1756c6a44287SMartin K. Petersen } 1757c6a44287SMartin K. Petersen 1758c6a44287SMartin K. Petersen resid = sectors * 8; /* Bytes of protection data to copy into sgl */ 1759c6a44287SMartin K. Petersen sector = start_sec; 1760c6a44287SMartin K. Petersen 1761c6a44287SMartin K. Petersen scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { 1762c6a44287SMartin K. Petersen int len = min(psgl->length, resid); 1763c6a44287SMartin K. Petersen 1764c6a44287SMartin K. Petersen paddr = kmap_atomic(sg_page(psgl), KM_IRQ0) + psgl->offset; 1765c6a44287SMartin K. Petersen memcpy(paddr, dif_storep + dif_offset(sector), len); 1766c6a44287SMartin K. Petersen 1767c6a44287SMartin K. Petersen sector += len >> 3; 1768c6a44287SMartin K. Petersen if (sector >= sdebug_store_sectors) { 1769c6a44287SMartin K. Petersen /* Force wrap */ 1770c6a44287SMartin K. Petersen tmp_sec = sector; 1771c6a44287SMartin K. Petersen sector = do_div(tmp_sec, sdebug_store_sectors); 1772c6a44287SMartin K. Petersen } 1773c6a44287SMartin K. Petersen resid -= len; 1774c6a44287SMartin K. Petersen kunmap_atomic(paddr, KM_IRQ0); 1775c6a44287SMartin K. Petersen } 1776c6a44287SMartin K. Petersen 1777c6a44287SMartin K. Petersen dix_reads++; 1778c6a44287SMartin K. Petersen 1779c6a44287SMartin K. Petersen return 0; 1780c6a44287SMartin K. Petersen } 1781c6a44287SMartin K. Petersen 178219789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 1783395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 1784395cef03SMartin K. Petersen u32 ei_lba) 178519789100SFUJITA Tomonori { 178619789100SFUJITA Tomonori unsigned long iflags; 178719789100SFUJITA Tomonori int ret; 178819789100SFUJITA Tomonori 178919789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 179019789100SFUJITA Tomonori if (ret) 179119789100SFUJITA Tomonori return ret; 179219789100SFUJITA Tomonori 17931da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 1794c65b1445SDouglas Gilbert (lba <= OPT_MEDIUM_ERR_ADDR) && 1795c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1796c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 17971da177e4SLinus Torvalds mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 17981da177e4SLinus Torvalds 0); 1799c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1800c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1801c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 1802c65b1445SDouglas Gilbert ret = OPT_MEDIUM_ERR_ADDR; 1803c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1804c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1805c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1806c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1807c65b1445SDouglas Gilbert } 1808a87e3a67SDouglas Gilbert scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 18091da177e4SLinus Torvalds return check_condition_result; 18101da177e4SLinus Torvalds } 1811c6a44287SMartin K. Petersen 1812c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 1813c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 1814395cef03SMartin K. Petersen int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); 1815c6a44287SMartin K. Petersen 1816c6a44287SMartin K. Petersen if (prot_ret) { 1817c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); 1818c6a44287SMartin K. Petersen return illegal_condition_result; 1819c6a44287SMartin K. Petersen } 1820c6a44287SMartin K. Petersen } 1821c6a44287SMartin K. Petersen 18221da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 182319789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 0); 18241da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 18251da177e4SLinus Torvalds return ret; 18261da177e4SLinus Torvalds } 18271da177e4SLinus Torvalds 1828c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len) 1829c6a44287SMartin K. Petersen { 1830c6a44287SMartin K. Petersen int i, j; 1831c6a44287SMartin K. Petersen 1832c6a44287SMartin K. Petersen printk(KERN_ERR ">>> Sector Dump <<<\n"); 1833c6a44287SMartin K. Petersen 1834c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 1835c6a44287SMartin K. Petersen printk(KERN_ERR "%04d: ", i); 1836c6a44287SMartin K. Petersen 1837c6a44287SMartin K. Petersen for (j = 0 ; j < 16 ; j++) { 1838c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 1839c6a44287SMartin K. Petersen if (c >= 0x20 && c < 0x7e) 1840c6a44287SMartin K. Petersen printk(" %c ", buf[i+j]); 1841c6a44287SMartin K. Petersen else 1842c6a44287SMartin K. Petersen printk("%02x ", buf[i+j]); 1843c6a44287SMartin K. Petersen } 1844c6a44287SMartin K. Petersen 1845c6a44287SMartin K. Petersen printk("\n"); 1846c6a44287SMartin K. Petersen } 1847c6a44287SMartin K. Petersen } 1848c6a44287SMartin K. Petersen 1849c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 1850395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 1851c6a44287SMartin K. Petersen { 1852c6a44287SMartin K. Petersen int i, j, ret; 1853c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 1854c6a44287SMartin K. Petersen struct scatterlist *dsgl = scsi_sglist(SCpnt); 1855c6a44287SMartin K. Petersen struct scatterlist *psgl = scsi_prot_sglist(SCpnt); 1856c6a44287SMartin K. Petersen void *daddr, *paddr; 1857c6a44287SMartin K. Petersen sector_t tmp_sec = start_sec; 1858c6a44287SMartin K. Petersen sector_t sector; 1859c6a44287SMartin K. Petersen int ppage_offset; 1860c6a44287SMartin K. Petersen unsigned short csum; 1861c6a44287SMartin K. Petersen 1862c6a44287SMartin K. Petersen sector = do_div(tmp_sec, sdebug_store_sectors); 1863c6a44287SMartin K. Petersen 1864c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 1865c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 1866c6a44287SMartin K. Petersen 1867c6a44287SMartin K. Petersen paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) + psgl->offset; 1868c6a44287SMartin K. Petersen ppage_offset = 0; 1869c6a44287SMartin K. Petersen 1870c6a44287SMartin K. Petersen /* For each data page */ 1871c6a44287SMartin K. Petersen scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { 1872c6a44287SMartin K. Petersen daddr = kmap_atomic(sg_page(dsgl), KM_IRQ0) + dsgl->offset; 1873c6a44287SMartin K. Petersen 1874c6a44287SMartin K. Petersen /* For each sector-sized chunk in data page */ 1875c6a44287SMartin K. Petersen for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { 1876c6a44287SMartin K. Petersen 1877c6a44287SMartin K. Petersen /* If we're at the end of the current 1878c6a44287SMartin K. Petersen * protection page advance to the next one 1879c6a44287SMartin K. Petersen */ 1880c6a44287SMartin K. Petersen if (ppage_offset >= psgl->length) { 1881c6a44287SMartin K. Petersen kunmap_atomic(paddr, KM_IRQ1); 1882c6a44287SMartin K. Petersen psgl = sg_next(psgl); 1883c6a44287SMartin K. Petersen BUG_ON(psgl == NULL); 1884c6a44287SMartin K. Petersen paddr = kmap_atomic(sg_page(psgl), KM_IRQ1) 1885c6a44287SMartin K. Petersen + psgl->offset; 1886c6a44287SMartin K. Petersen ppage_offset = 0; 1887c6a44287SMartin K. Petersen } 1888c6a44287SMartin K. Petersen 1889c6a44287SMartin K. Petersen sdt = paddr + ppage_offset; 1890c6a44287SMartin K. Petersen 1891c6a44287SMartin K. Petersen switch (scsi_debug_guard) { 1892c6a44287SMartin K. Petersen case 1: 1893c6a44287SMartin K. Petersen csum = ip_compute_csum(daddr, 1894c6a44287SMartin K. Petersen scsi_debug_sector_size); 1895c6a44287SMartin K. Petersen break; 1896c6a44287SMartin K. Petersen case 0: 1897c6a44287SMartin K. Petersen csum = cpu_to_be16(crc_t10dif(daddr, 1898c6a44287SMartin K. Petersen scsi_debug_sector_size)); 1899c6a44287SMartin K. Petersen break; 1900c6a44287SMartin K. Petersen default: 1901c6a44287SMartin K. Petersen BUG(); 1902c6a44287SMartin K. Petersen ret = 0; 1903c6a44287SMartin K. Petersen goto out; 1904c6a44287SMartin K. Petersen } 1905c6a44287SMartin K. Petersen 1906c6a44287SMartin K. Petersen if (sdt->guard_tag != csum) { 1907c6a44287SMartin K. Petersen printk(KERN_ERR 1908c6a44287SMartin K. Petersen "%s: GUARD check failed on sector %lu " \ 1909c6a44287SMartin K. Petersen "rcvd 0x%04x, calculated 0x%04x\n", 1910c6a44287SMartin K. Petersen __func__, (unsigned long)sector, 1911c6a44287SMartin K. Petersen be16_to_cpu(sdt->guard_tag), 1912c6a44287SMartin K. Petersen be16_to_cpu(csum)); 1913c6a44287SMartin K. Petersen ret = 0x01; 1914c6a44287SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1915c6a44287SMartin K. Petersen goto out; 1916c6a44287SMartin K. Petersen } 1917c6a44287SMartin K. Petersen 1918395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1919c6a44287SMartin K. Petersen be32_to_cpu(sdt->ref_tag) 1920c6a44287SMartin K. Petersen != (start_sec & 0xffffffff)) { 1921c6a44287SMartin K. Petersen printk(KERN_ERR 1922c6a44287SMartin K. Petersen "%s: REF check failed on sector %lu\n", 1923c6a44287SMartin K. Petersen __func__, (unsigned long)sector); 1924c6a44287SMartin K. Petersen ret = 0x03; 1925c6a44287SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1926c6a44287SMartin K. Petersen goto out; 1927c6a44287SMartin K. Petersen } 1928c6a44287SMartin K. Petersen 1929395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1930395cef03SMartin K. Petersen be32_to_cpu(sdt->ref_tag) != ei_lba) { 1931395cef03SMartin K. Petersen printk(KERN_ERR 1932395cef03SMartin K. Petersen "%s: REF check failed on sector %lu\n", 1933395cef03SMartin K. Petersen __func__, (unsigned long)sector); 1934395cef03SMartin K. Petersen ret = 0x03; 1935395cef03SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1936395cef03SMartin K. Petersen goto out; 1937395cef03SMartin K. Petersen } 1938395cef03SMartin K. Petersen 1939c6a44287SMartin K. Petersen /* Would be great to copy this in bigger 1940c6a44287SMartin K. Petersen * chunks. However, for the sake of 1941c6a44287SMartin K. Petersen * correctness we need to verify each sector 1942c6a44287SMartin K. Petersen * before writing it to "stable" storage 1943c6a44287SMartin K. Petersen */ 1944c6a44287SMartin K. Petersen memcpy(dif_storep + dif_offset(sector), sdt, 8); 1945c6a44287SMartin K. Petersen 1946c6a44287SMartin K. Petersen sector++; 1947c6a44287SMartin K. Petersen 1948c6a44287SMartin K. Petersen if (sector == sdebug_store_sectors) 1949c6a44287SMartin K. Petersen sector = 0; /* Force wrap */ 1950c6a44287SMartin K. Petersen 1951c6a44287SMartin K. Petersen start_sec++; 1952395cef03SMartin K. Petersen ei_lba++; 1953c6a44287SMartin K. Petersen daddr += scsi_debug_sector_size; 1954c6a44287SMartin K. Petersen ppage_offset += sizeof(struct sd_dif_tuple); 1955c6a44287SMartin K. Petersen } 1956c6a44287SMartin K. Petersen 1957c6a44287SMartin K. Petersen kunmap_atomic(daddr, KM_IRQ0); 1958c6a44287SMartin K. Petersen } 1959c6a44287SMartin K. Petersen 1960c6a44287SMartin K. Petersen kunmap_atomic(paddr, KM_IRQ1); 1961c6a44287SMartin K. Petersen 1962c6a44287SMartin K. Petersen dix_writes++; 1963c6a44287SMartin K. Petersen 1964c6a44287SMartin K. Petersen return 0; 1965c6a44287SMartin K. Petersen 1966c6a44287SMartin K. Petersen out: 1967c6a44287SMartin K. Petersen dif_errors++; 1968c6a44287SMartin K. Petersen kunmap_atomic(daddr, KM_IRQ0); 1969c6a44287SMartin K. Petersen kunmap_atomic(paddr, KM_IRQ1); 1970c6a44287SMartin K. Petersen return ret; 1971c6a44287SMartin K. Petersen } 1972c6a44287SMartin K. Petersen 197344d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 197444d92694SMartin K. Petersen { 197544d92694SMartin K. Petersen unsigned int granularity, alignment, mapped; 197644d92694SMartin K. Petersen sector_t block, next, end; 197744d92694SMartin K. Petersen 197844d92694SMartin K. Petersen granularity = scsi_debug_unmap_granularity; 197944d92694SMartin K. Petersen alignment = granularity - scsi_debug_unmap_alignment; 198044d92694SMartin K. Petersen block = lba + alignment; 198144d92694SMartin K. Petersen do_div(block, granularity); 198244d92694SMartin K. Petersen 198344d92694SMartin K. Petersen mapped = test_bit(block, map_storep); 198444d92694SMartin K. Petersen 198544d92694SMartin K. Petersen if (mapped) 198644d92694SMartin K. Petersen next = find_next_zero_bit(map_storep, map_size, block); 198744d92694SMartin K. Petersen else 198844d92694SMartin K. Petersen next = find_next_bit(map_storep, map_size, block); 198944d92694SMartin K. Petersen 199044d92694SMartin K. Petersen end = next * granularity - scsi_debug_unmap_alignment; 199144d92694SMartin K. Petersen *num = end - lba; 199244d92694SMartin K. Petersen 199344d92694SMartin K. Petersen return mapped; 199444d92694SMartin K. Petersen } 199544d92694SMartin K. Petersen 199644d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 199744d92694SMartin K. Petersen { 199844d92694SMartin K. Petersen unsigned int granularity, alignment; 199944d92694SMartin K. Petersen sector_t end = lba + len; 200044d92694SMartin K. Petersen 200144d92694SMartin K. Petersen granularity = scsi_debug_unmap_granularity; 200244d92694SMartin K. Petersen alignment = granularity - scsi_debug_unmap_alignment; 200344d92694SMartin K. Petersen 200444d92694SMartin K. Petersen while (lba < end) { 200544d92694SMartin K. Petersen sector_t block, rem; 200644d92694SMartin K. Petersen 200744d92694SMartin K. Petersen block = lba + alignment; 200844d92694SMartin K. Petersen rem = do_div(block, granularity); 200944d92694SMartin K. Petersen 20109ab98f57SFUJITA Tomonori if (block < map_size) 201144d92694SMartin K. Petersen set_bit(block, map_storep); 201244d92694SMartin K. Petersen 201344d92694SMartin K. Petersen lba += granularity - rem; 201444d92694SMartin K. Petersen } 201544d92694SMartin K. Petersen } 201644d92694SMartin K. Petersen 201744d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 201844d92694SMartin K. Petersen { 201944d92694SMartin K. Petersen unsigned int granularity, alignment; 202044d92694SMartin K. Petersen sector_t end = lba + len; 202144d92694SMartin K. Petersen 202244d92694SMartin K. Petersen granularity = scsi_debug_unmap_granularity; 202344d92694SMartin K. Petersen alignment = granularity - scsi_debug_unmap_alignment; 202444d92694SMartin K. Petersen 202544d92694SMartin K. Petersen while (lba < end) { 202644d92694SMartin K. Petersen sector_t block, rem; 202744d92694SMartin K. Petersen 202844d92694SMartin K. Petersen block = lba + alignment; 202944d92694SMartin K. Petersen rem = do_div(block, granularity); 203044d92694SMartin K. Petersen 20319ab98f57SFUJITA Tomonori if (rem == 0 && lba + granularity <= end && 20329ab98f57SFUJITA Tomonori block < map_size) 203344d92694SMartin K. Petersen clear_bit(block, map_storep); 203444d92694SMartin K. Petersen 203544d92694SMartin K. Petersen lba += granularity - rem; 203644d92694SMartin K. Petersen } 203744d92694SMartin K. Petersen } 203844d92694SMartin K. Petersen 2039c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 2040395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 2041395cef03SMartin K. Petersen u32 ei_lba) 20421da177e4SLinus Torvalds { 20431da177e4SLinus Torvalds unsigned long iflags; 204419789100SFUJITA Tomonori int ret; 20451da177e4SLinus Torvalds 204619789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 204719789100SFUJITA Tomonori if (ret) 204819789100SFUJITA Tomonori return ret; 20491da177e4SLinus Torvalds 2050c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2051c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 2052395cef03SMartin K. Petersen int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); 2053c6a44287SMartin K. Petersen 2054c6a44287SMartin K. Petersen if (prot_ret) { 2055c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); 2056c6a44287SMartin K. Petersen return illegal_condition_result; 2057c6a44287SMartin K. Petersen } 2058c6a44287SMartin K. Petersen } 2059c6a44287SMartin K. Petersen 20601da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 206119789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 1); 206244d92694SMartin K. Petersen if (scsi_debug_unmap_granularity) 206344d92694SMartin K. Petersen map_region(lba, num); 20641da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 206519789100SFUJITA Tomonori if (-1 == ret) 20661da177e4SLinus Torvalds return (DID_ERROR << 16); 2067597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 20681da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2069c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 2070597136abSMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 207144d92694SMartin K. Petersen 20721da177e4SLinus Torvalds return 0; 20731da177e4SLinus Torvalds } 20741da177e4SLinus Torvalds 207544d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba, 207644d92694SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 207744d92694SMartin K. Petersen u32 ei_lba, unsigned int unmap) 207844d92694SMartin K. Petersen { 207944d92694SMartin K. Petersen unsigned long iflags; 208044d92694SMartin K. Petersen unsigned long long i; 208144d92694SMartin K. Petersen int ret; 208244d92694SMartin K. Petersen 208344d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 208444d92694SMartin K. Petersen if (ret) 208544d92694SMartin K. Petersen return ret; 208644d92694SMartin K. Petersen 208744d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 208844d92694SMartin K. Petersen 208944d92694SMartin K. Petersen if (unmap && scsi_debug_unmap_granularity) { 209044d92694SMartin K. Petersen unmap_region(lba, num); 209144d92694SMartin K. Petersen goto out; 209244d92694SMartin K. Petersen } 209344d92694SMartin K. Petersen 209444d92694SMartin K. Petersen /* Else fetch one logical block */ 209544d92694SMartin K. Petersen ret = fetch_to_dev_buffer(scmd, 209644d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 209744d92694SMartin K. Petersen scsi_debug_sector_size); 209844d92694SMartin K. Petersen 209944d92694SMartin K. Petersen if (-1 == ret) { 210044d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 210144d92694SMartin K. Petersen return (DID_ERROR << 16); 210244d92694SMartin K. Petersen } else if ((ret < (num * scsi_debug_sector_size)) && 210344d92694SMartin K. Petersen (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 210444d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, " 210544d92694SMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 210644d92694SMartin K. Petersen 210744d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 210844d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 210944d92694SMartin K. Petersen memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), 211044d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 211144d92694SMartin K. Petersen scsi_debug_sector_size); 211244d92694SMartin K. Petersen 211344d92694SMartin K. Petersen if (scsi_debug_unmap_granularity) 211444d92694SMartin K. Petersen map_region(lba, num); 211544d92694SMartin K. Petersen out: 211644d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 211744d92694SMartin K. Petersen 211844d92694SMartin K. Petersen return 0; 211944d92694SMartin K. Petersen } 212044d92694SMartin K. Petersen 212144d92694SMartin K. Petersen struct unmap_block_desc { 212244d92694SMartin K. Petersen __be64 lba; 212344d92694SMartin K. Petersen __be32 blocks; 212444d92694SMartin K. Petersen __be32 __reserved; 212544d92694SMartin K. Petersen }; 212644d92694SMartin K. Petersen 212744d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip) 212844d92694SMartin K. Petersen { 212944d92694SMartin K. Petersen unsigned char *buf; 213044d92694SMartin K. Petersen struct unmap_block_desc *desc; 213144d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 213244d92694SMartin K. Petersen int ret; 213344d92694SMartin K. Petersen 213444d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 213544d92694SMartin K. Petersen if (ret) 213644d92694SMartin K. Petersen return ret; 213744d92694SMartin K. Petersen 213844d92694SMartin K. Petersen payload_len = get_unaligned_be16(&scmd->cmnd[7]); 213944d92694SMartin K. Petersen BUG_ON(scsi_bufflen(scmd) != payload_len); 214044d92694SMartin K. Petersen 214144d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 214244d92694SMartin K. Petersen 214344d92694SMartin K. Petersen buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC); 214444d92694SMartin K. Petersen if (!buf) 214544d92694SMartin K. Petersen return check_condition_result; 214644d92694SMartin K. Petersen 214744d92694SMartin K. Petersen scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); 214844d92694SMartin K. Petersen 214944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 215044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 215144d92694SMartin K. Petersen 215244d92694SMartin K. Petersen desc = (void *)&buf[8]; 215344d92694SMartin K. Petersen 215444d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 215544d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 215644d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 215744d92694SMartin K. Petersen 215844d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 215944d92694SMartin K. Petersen if (ret) 216044d92694SMartin K. Petersen goto out; 216144d92694SMartin K. Petersen 216244d92694SMartin K. Petersen unmap_region(lba, num); 216344d92694SMartin K. Petersen } 216444d92694SMartin K. Petersen 216544d92694SMartin K. Petersen ret = 0; 216644d92694SMartin K. Petersen 216744d92694SMartin K. Petersen out: 216844d92694SMartin K. Petersen kfree(buf); 216944d92694SMartin K. Petersen 217044d92694SMartin K. Petersen return ret; 217144d92694SMartin K. Petersen } 217244d92694SMartin K. Petersen 217344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 217444d92694SMartin K. Petersen 217544d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd, 217644d92694SMartin K. Petersen struct sdebug_dev_info * devip) 217744d92694SMartin K. Petersen { 217844d92694SMartin K. Petersen unsigned long long lba; 217944d92694SMartin K. Petersen unsigned int alloc_len, mapped, num; 218044d92694SMartin K. Petersen unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN]; 218144d92694SMartin K. Petersen int ret; 218244d92694SMartin K. Petersen 218344d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 218444d92694SMartin K. Petersen if (ret) 218544d92694SMartin K. Petersen return ret; 218644d92694SMartin K. Petersen 218744d92694SMartin K. Petersen lba = get_unaligned_be64(&scmd->cmnd[2]); 218844d92694SMartin K. Petersen alloc_len = get_unaligned_be32(&scmd->cmnd[10]); 218944d92694SMartin K. Petersen 219044d92694SMartin K. Petersen if (alloc_len < 24) 219144d92694SMartin K. Petersen return 0; 219244d92694SMartin K. Petersen 219344d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, 1); 219444d92694SMartin K. Petersen if (ret) 219544d92694SMartin K. Petersen return ret; 219644d92694SMartin K. Petersen 219744d92694SMartin K. Petersen mapped = map_state(lba, &num); 219844d92694SMartin K. Petersen 219944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 220044d92694SMartin K. Petersen put_unaligned_be32(16, &arr[0]); /* Parameter Data Length */ 220144d92694SMartin K. Petersen put_unaligned_be64(lba, &arr[8]); /* LBA */ 220244d92694SMartin K. Petersen put_unaligned_be32(num, &arr[16]); /* Number of blocks */ 220344d92694SMartin K. Petersen arr[20] = !mapped; /* mapped = 0, unmapped = 1 */ 220444d92694SMartin K. Petersen 220544d92694SMartin K. Petersen return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN); 220644d92694SMartin K. Petersen } 220744d92694SMartin K. Petersen 2208c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 22091da177e4SLinus Torvalds 22101da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 22111da177e4SLinus Torvalds struct sdebug_dev_info * devip) 22121da177e4SLinus Torvalds { 22131da177e4SLinus Torvalds unsigned int alloc_len; 2214c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 22151da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 22161da177e4SLinus Torvalds int select_report = (int)cmd[2]; 22171da177e4SLinus Torvalds struct scsi_lun *one_lun; 22181da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 2219c65b1445SDouglas Gilbert unsigned char * max_addr; 22201da177e4SLinus Torvalds 22211da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 2222c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 22231da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 22241da177e4SLinus Torvalds 0); 22251da177e4SLinus Torvalds return check_condition_result; 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 22281da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 22291da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 2230c65b1445SDouglas Gilbert if (1 == select_report) 2231c65b1445SDouglas Gilbert lun_cnt = 0; 2232c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 2233c65b1445SDouglas Gilbert --lun_cnt; 2234c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 2235c65b1445SDouglas Gilbert num = lun_cnt + wlun; 2236c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 2237c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 2238c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 2239c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 2240c65b1445SDouglas Gilbert if (n < num) { 2241c65b1445SDouglas Gilbert wlun = 0; 2242c65b1445SDouglas Gilbert lun_cnt = n; 2243c65b1445SDouglas Gilbert } 22441da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 2245c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 2246c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 2247c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 2248c65b1445SDouglas Gilbert i++, lun++) { 2249c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 22501da177e4SLinus Torvalds if (upper) 22511da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 22521da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 2253c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 22541da177e4SLinus Torvalds } 2255c65b1445SDouglas Gilbert if (wlun) { 2256c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 2257c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 2258c65b1445SDouglas Gilbert i++; 2259c65b1445SDouglas Gilbert } 2260c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 22611da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 22621da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds 2265c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 2266c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 2267c639d14eSFUJITA Tomonori { 2268c639d14eSFUJITA Tomonori int i, j, ret = -1; 2269c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 2270c639d14eSFUJITA Tomonori unsigned int offset; 2271c639d14eSFUJITA Tomonori struct scatterlist *sg; 2272c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 2273c639d14eSFUJITA Tomonori 2274c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 2275c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 2276c639d14eSFUJITA Tomonori if (!buf) 2277c639d14eSFUJITA Tomonori return ret; 2278c639d14eSFUJITA Tomonori 227921a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 2280c639d14eSFUJITA Tomonori 2281c639d14eSFUJITA Tomonori offset = 0; 2282c639d14eSFUJITA Tomonori for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { 2283c639d14eSFUJITA Tomonori kaddr = (unsigned char *)kmap_atomic(sg_page(sg), KM_USER0); 2284c639d14eSFUJITA Tomonori if (!kaddr) 2285c639d14eSFUJITA Tomonori goto out; 2286c639d14eSFUJITA Tomonori 2287c639d14eSFUJITA Tomonori for (j = 0; j < sg->length; j++) 2288c639d14eSFUJITA Tomonori *(kaddr + sg->offset + j) ^= *(buf + offset + j); 2289c639d14eSFUJITA Tomonori 2290c639d14eSFUJITA Tomonori offset += sg->length; 2291c639d14eSFUJITA Tomonori kunmap_atomic(kaddr, KM_USER0); 2292c639d14eSFUJITA Tomonori } 2293c639d14eSFUJITA Tomonori ret = 0; 2294c639d14eSFUJITA Tomonori out: 2295c639d14eSFUJITA Tomonori kfree(buf); 2296c639d14eSFUJITA Tomonori 2297c639d14eSFUJITA Tomonori return ret; 2298c639d14eSFUJITA Tomonori } 2299c639d14eSFUJITA Tomonori 23001da177e4SLinus Torvalds /* When timer goes off this function is called. */ 23011da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 23021da177e4SLinus Torvalds { 23031da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 23041da177e4SLinus Torvalds unsigned long iflags; 23051da177e4SLinus Torvalds 230678d4e5a0SDouglas Gilbert if (indx >= scsi_debug_max_queue) { 23071da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 23081da177e4SLinus Torvalds "large\n"); 23091da177e4SLinus Torvalds return; 23101da177e4SLinus Torvalds } 23111da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 23121da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 23131da177e4SLinus Torvalds if (! sqcp->in_use) { 23141da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 23151da177e4SLinus Torvalds "interrupt\n"); 23161da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23171da177e4SLinus Torvalds return; 23181da177e4SLinus Torvalds } 23191da177e4SLinus Torvalds sqcp->in_use = 0; 23201da177e4SLinus Torvalds if (sqcp->done_funct) { 23211da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 23221da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 23231da177e4SLinus Torvalds } 23241da177e4SLinus Torvalds sqcp->done_funct = NULL; 23251da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23261da177e4SLinus Torvalds } 23271da177e4SLinus Torvalds 23281da177e4SLinus Torvalds 23298dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 23308dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 23315cb2fc06SFUJITA Tomonori { 23325cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 23335cb2fc06SFUJITA Tomonori 23345cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 23355cb2fc06SFUJITA Tomonori if (devip) { 23365cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 23375cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 23385cb2fc06SFUJITA Tomonori } 23395cb2fc06SFUJITA Tomonori return devip; 23405cb2fc06SFUJITA Tomonori } 23415cb2fc06SFUJITA Tomonori 23421da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 23431da177e4SLinus Torvalds { 23441da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 23451da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 23461da177e4SLinus Torvalds struct sdebug_dev_info * devip = 23471da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 23481da177e4SLinus Torvalds 23491da177e4SLinus Torvalds if (devip) 23501da177e4SLinus Torvalds return devip; 2351d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 23521da177e4SLinus Torvalds if (!sdbg_host) { 23531da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 23541da177e4SLinus Torvalds return NULL; 23551da177e4SLinus Torvalds } 23561da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 23571da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 23581da177e4SLinus Torvalds (devip->target == sdev->id) && 23591da177e4SLinus Torvalds (devip->lun == sdev->lun)) 23601da177e4SLinus Torvalds return devip; 23611da177e4SLinus Torvalds else { 23621da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 23631da177e4SLinus Torvalds open_devip = devip; 23641da177e4SLinus Torvalds } 23651da177e4SLinus Torvalds } 23665cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 23675cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 23685cb2fc06SFUJITA Tomonori if (!open_devip) { 23691da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 2370cadbd4a5SHarvey Harrison __func__, __LINE__); 23711da177e4SLinus Torvalds return NULL; 23721da177e4SLinus Torvalds } 23731da177e4SLinus Torvalds } 2374a75869d1SFUJITA Tomonori 23751da177e4SLinus Torvalds open_devip->channel = sdev->channel; 23761da177e4SLinus Torvalds open_devip->target = sdev->id; 23771da177e4SLinus Torvalds open_devip->lun = sdev->lun; 23781da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 23791da177e4SLinus Torvalds open_devip->reset = 1; 23801da177e4SLinus Torvalds open_devip->used = 1; 23811da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 23821da177e4SLinus Torvalds if (scsi_debug_dsense) 23831da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 23841da177e4SLinus Torvalds else { 23851da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 23861da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 23871da177e4SLinus Torvalds } 2388c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 2389c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 2390a75869d1SFUJITA Tomonori 23911da177e4SLinus Torvalds return open_devip; 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds 23948dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 23951da177e4SLinus Torvalds { 23968dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 23978dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 23988dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 239975ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 24008dea0d02SFUJITA Tomonori return 0; 24018dea0d02SFUJITA Tomonori } 24021da177e4SLinus Torvalds 24038dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 24048dea0d02SFUJITA Tomonori { 24058dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 2406a34c4e98SFUJITA Tomonori 24071da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24088dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 24098dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24108dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 24118dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 24128dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 24138dea0d02SFUJITA Tomonori if (NULL == devip) 24148dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 24158dea0d02SFUJITA Tomonori sdp->hostdata = devip; 24168dea0d02SFUJITA Tomonori if (sdp->host->cmd_per_lun) 24178dea0d02SFUJITA Tomonori scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 24188dea0d02SFUJITA Tomonori sdp->host->cmd_per_lun); 24198dea0d02SFUJITA Tomonori blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 242078d4e5a0SDouglas Gilbert if (scsi_debug_no_uld) 242178d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 24228dea0d02SFUJITA Tomonori return 0; 24238dea0d02SFUJITA Tomonori } 24248dea0d02SFUJITA Tomonori 24258dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 24268dea0d02SFUJITA Tomonori { 24278dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 24288dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 24298dea0d02SFUJITA Tomonori 24308dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24318dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 24328dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24338dea0d02SFUJITA Tomonori if (devip) { 24348dea0d02SFUJITA Tomonori /* make this slot avaliable for re-use */ 24358dea0d02SFUJITA Tomonori devip->used = 0; 24368dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 24378dea0d02SFUJITA Tomonori } 24388dea0d02SFUJITA Tomonori } 24398dea0d02SFUJITA Tomonori 24408dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 24418dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 24428dea0d02SFUJITA Tomonori { 24438dea0d02SFUJITA Tomonori unsigned long iflags; 24448dea0d02SFUJITA Tomonori int k; 24458dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 24468dea0d02SFUJITA Tomonori 24478dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 244878d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 24498dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 24508dea0d02SFUJITA Tomonori if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 24518dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 24528dea0d02SFUJITA Tomonori sqcp->in_use = 0; 24538dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 24548dea0d02SFUJITA Tomonori break; 24558dea0d02SFUJITA Tomonori } 24568dea0d02SFUJITA Tomonori } 24578dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 245878d4e5a0SDouglas Gilbert return (k < scsi_debug_max_queue) ? 1 : 0; 24598dea0d02SFUJITA Tomonori } 24608dea0d02SFUJITA Tomonori 24618dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */ 24628dea0d02SFUJITA Tomonori static void stop_all_queued(void) 24638dea0d02SFUJITA Tomonori { 24648dea0d02SFUJITA Tomonori unsigned long iflags; 24658dea0d02SFUJITA Tomonori int k; 24668dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 24678dea0d02SFUJITA Tomonori 24688dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 246978d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 24708dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 24718dea0d02SFUJITA Tomonori if (sqcp->in_use && sqcp->a_cmnd) { 24728dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 24738dea0d02SFUJITA Tomonori sqcp->in_use = 0; 24748dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 24758dea0d02SFUJITA Tomonori } 24768dea0d02SFUJITA Tomonori } 24778dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 24781da177e4SLinus Torvalds } 24791da177e4SLinus Torvalds 24801da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 24811da177e4SLinus Torvalds { 24821da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24831da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 24841da177e4SLinus Torvalds ++num_aborts; 24851da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 24861da177e4SLinus Torvalds return SUCCESS; 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 24891da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 24901da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 24911da177e4SLinus Torvalds { 24921da177e4SLinus Torvalds int res; 24931da177e4SLinus Torvalds unsigned char *buf; 24941da177e4SLinus Torvalds 24951da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24961da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 24971da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 24981da177e4SLinus Torvalds if (buf) { 24991da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 25001da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 25011da177e4SLinus Torvalds kfree(buf); 25021da177e4SLinus Torvalds if (! res) 25031da177e4SLinus Torvalds return res; 25041da177e4SLinus Torvalds } 25051da177e4SLinus Torvalds info[0] = sdebug_heads; 25061da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 25071da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 25081da177e4SLinus Torvalds return 0; 25091da177e4SLinus Torvalds } 25101da177e4SLinus Torvalds 25111da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 25121da177e4SLinus Torvalds { 25131da177e4SLinus Torvalds struct sdebug_dev_info * devip; 25141da177e4SLinus Torvalds 25151da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25161da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 25171da177e4SLinus Torvalds ++num_dev_resets; 25181da177e4SLinus Torvalds if (SCpnt) { 25191da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 25201da177e4SLinus Torvalds if (devip) 25211da177e4SLinus Torvalds devip->reset = 1; 25221da177e4SLinus Torvalds } 25231da177e4SLinus Torvalds return SUCCESS; 25241da177e4SLinus Torvalds } 25251da177e4SLinus Torvalds 25261da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 25271da177e4SLinus Torvalds { 25281da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 25291da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 25301da177e4SLinus Torvalds struct scsi_device * sdp; 25311da177e4SLinus Torvalds struct Scsi_Host * hp; 25321da177e4SLinus Torvalds 25331da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25341da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 25351da177e4SLinus Torvalds ++num_bus_resets; 25361da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 2537d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 25381da177e4SLinus Torvalds if (sdbg_host) { 25391da177e4SLinus Torvalds list_for_each_entry(dev_info, 25401da177e4SLinus Torvalds &sdbg_host->dev_info_list, 25411da177e4SLinus Torvalds dev_list) 25421da177e4SLinus Torvalds dev_info->reset = 1; 25431da177e4SLinus Torvalds } 25441da177e4SLinus Torvalds } 25451da177e4SLinus Torvalds return SUCCESS; 25461da177e4SLinus Torvalds } 25471da177e4SLinus Torvalds 25481da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 25491da177e4SLinus Torvalds { 25501da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 25511da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 25521da177e4SLinus Torvalds 25531da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25541da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 25551da177e4SLinus Torvalds ++num_host_resets; 25561da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 25571da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 25581da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 25591da177e4SLinus Torvalds dev_list) 25601da177e4SLinus Torvalds dev_info->reset = 1; 25611da177e4SLinus Torvalds } 25621da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 25631da177e4SLinus Torvalds stop_all_queued(); 25641da177e4SLinus Torvalds return SUCCESS; 25651da177e4SLinus Torvalds } 25661da177e4SLinus Torvalds 25671da177e4SLinus Torvalds /* Initializes timers in queued array */ 25681da177e4SLinus Torvalds static void __init init_all_queued(void) 25691da177e4SLinus Torvalds { 25701da177e4SLinus Torvalds unsigned long iflags; 25711da177e4SLinus Torvalds int k; 25721da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 25731da177e4SLinus Torvalds 25741da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 257578d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 25761da177e4SLinus Torvalds sqcp = &queued_arr[k]; 25771da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 25781da177e4SLinus Torvalds sqcp->in_use = 0; 25791da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 25801da177e4SLinus Torvalds } 25811da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 25821da177e4SLinus Torvalds } 25831da177e4SLinus Torvalds 2584f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 25855f2578e5SFUJITA Tomonori unsigned long store_size) 25861da177e4SLinus Torvalds { 25871da177e4SLinus Torvalds struct partition * pp; 25881da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 25891da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 25901da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 25911da177e4SLinus Torvalds 25921da177e4SLinus Torvalds /* assume partition table already zeroed */ 2593f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 25941da177e4SLinus Torvalds return; 25951da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 25961da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 25971da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 25981da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 25991da177e4SLinus Torvalds } 2600c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 26011da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 26021da177e4SLinus Torvalds / scsi_debug_num_parts; 26031da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 26041da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 26051da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 26061da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 26071da177e4SLinus Torvalds * heads_by_sects; 26081da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 26091da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 26101da177e4SLinus Torvalds 26111da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 26121da177e4SLinus Torvalds ramp[511] = 0xAA; 26131da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 26141da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 26151da177e4SLinus Torvalds start_sec = starts[k]; 26161da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 26171da177e4SLinus Torvalds pp->boot_ind = 0; 26181da177e4SLinus Torvalds 26191da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 26201da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 26211da177e4SLinus Torvalds / sdebug_sectors_per; 26221da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 26231da177e4SLinus Torvalds 26241da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 26251da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 26261da177e4SLinus Torvalds / sdebug_sectors_per; 26271da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 26281da177e4SLinus Torvalds 26291da177e4SLinus Torvalds pp->start_sect = start_sec; 26301da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 26311da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 26321da177e4SLinus Torvalds } 26331da177e4SLinus Torvalds } 26341da177e4SLinus Torvalds 26351da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 26361da177e4SLinus Torvalds struct sdebug_dev_info * devip, 26371da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 26381da177e4SLinus Torvalds { 26391da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 26401da177e4SLinus Torvalds if (scsi_result) { 26411da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 26421da177e4SLinus Torvalds 2643c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2644c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2645c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 26461da177e4SLinus Torvalds } 26471da177e4SLinus Torvalds } 26481da177e4SLinus Torvalds if (cmnd && devip) { 26491da177e4SLinus Torvalds /* simulate autosense by this driver */ 26501da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 26511da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 26521da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 26531da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 26541da177e4SLinus Torvalds } 26551da177e4SLinus Torvalds if (delta_jiff <= 0) { 26561da177e4SLinus Torvalds if (cmnd) 26571da177e4SLinus Torvalds cmnd->result = scsi_result; 26581da177e4SLinus Torvalds if (done) 26591da177e4SLinus Torvalds done(cmnd); 26601da177e4SLinus Torvalds return 0; 26611da177e4SLinus Torvalds } else { 26621da177e4SLinus Torvalds unsigned long iflags; 26631da177e4SLinus Torvalds int k; 26641da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 26651da177e4SLinus Torvalds 26661da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 266778d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 26681da177e4SLinus Torvalds sqcp = &queued_arr[k]; 26691da177e4SLinus Torvalds if (! sqcp->in_use) 26701da177e4SLinus Torvalds break; 26711da177e4SLinus Torvalds } 267278d4e5a0SDouglas Gilbert if (k >= scsi_debug_max_queue) { 26731da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 26741da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 26751da177e4SLinus Torvalds return 1; /* report busy to mid level */ 26761da177e4SLinus Torvalds } 26771da177e4SLinus Torvalds sqcp->in_use = 1; 26781da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 26791da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 26801da177e4SLinus Torvalds sqcp->done_funct = done; 26811da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 26821da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 26831da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 26841da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 26851da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 26861da177e4SLinus Torvalds if (cmnd) 26871da177e4SLinus Torvalds cmnd->result = 0; 26881da177e4SLinus Torvalds return 0; 26891da177e4SLinus Torvalds } 26901da177e4SLinus Torvalds } 269123183910SDouglas Gilbert /* Note: The following macros create attribute files in the 269223183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 269323183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 269423183910SDouglas Gilbert as it can when the corresponding attribute in the 269523183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 269623183910SDouglas Gilbert */ 2697c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 2698c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2699c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 2700c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2701c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 270223183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 2703c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 270478d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); 2705c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 270678d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); 2707c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2708c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 2709c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 2710c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2711c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 2712c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 271323183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 271423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 2715597136abSMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 2716c6a44287SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO); 2717c6a44287SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO); 2718c6a44287SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO); 2719c6a44287SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO); 2720ea61fca5SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); 2721e308b3d1SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); 2722ea61fca5SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); 272344d92694SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); 272444d92694SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); 272544d92694SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); 272644d92694SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); 27276014759cSMartin K. Petersen module_param_named(tpu, scsi_debug_tpu, int, S_IRUGO); 27286014759cSMartin K. Petersen module_param_named(tpws, scsi_debug_tpws, int, S_IRUGO); 27291da177e4SLinus Torvalds 27301da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 27311da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 27321da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 27331da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 27341da177e4SLinus Torvalds 27351da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 27361da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2737c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 2738c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2739beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 274023183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 2741c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 274278d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))"); 2743c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 274478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 27451da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2746c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 27476f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 27481da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 27491da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2750c65b1445SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 275123183910SDouglas Gilbert MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 2752ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 2753ea61fca5SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 2754e308b3d1SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); 2755ea61fca5SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 2756c6a44287SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 2757c6a44287SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 2758c6a44287SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 2759c6a44287SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 27606014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 27616014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 27626014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 276344d92694SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 27646014759cSMartin K. Petersen MODULE_PARM_DESC(tpu, "enable TP, support UNMAP command (def=0)"); 27656014759cSMartin K. Petersen MODULE_PARM_DESC(tpws, "enable TP, support WRITE SAME(16) with UNMAP bit (def=0)"); 27661da177e4SLinus Torvalds 27671da177e4SLinus Torvalds static char sdebug_info[256]; 27681da177e4SLinus Torvalds 27691da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 27701da177e4SLinus Torvalds { 27711da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 27721da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 27731da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 27741da177e4SLinus Torvalds scsi_debug_opts); 27751da177e4SLinus Torvalds return sdebug_info; 27761da177e4SLinus Torvalds } 27771da177e4SLinus Torvalds 27781da177e4SLinus Torvalds /* scsi_debug_proc_info 27791da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 27801da177e4SLinus Torvalds */ 27811da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 27821da177e4SLinus Torvalds int length, int inout) 27831da177e4SLinus Torvalds { 27841da177e4SLinus Torvalds int len, pos, begin; 27851da177e4SLinus Torvalds int orig_length; 27861da177e4SLinus Torvalds 27871da177e4SLinus Torvalds orig_length = length; 27881da177e4SLinus Torvalds 27891da177e4SLinus Torvalds if (inout == 1) { 27901da177e4SLinus Torvalds char arr[16]; 27911da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 27921da177e4SLinus Torvalds 27931da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 27941da177e4SLinus Torvalds return -EACCES; 27951da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 27961da177e4SLinus Torvalds arr[minLen] = '\0'; 27971da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 27981da177e4SLinus Torvalds return -EINVAL; 27991da177e4SLinus Torvalds scsi_debug_opts = pos; 28001da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 28011da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 28021da177e4SLinus Torvalds return length; 28031da177e4SLinus Torvalds } 28041da177e4SLinus Torvalds begin = 0; 28051da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 28061da177e4SLinus Torvalds "%s [%s]\n" 28071da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 28081da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 28091da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 28101da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 28111da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 2812c6a44287SMartin K. Petersen "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", 28131da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 28141da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 28151da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 28161da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 2817597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 2818597136abSMartin K. Petersen sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, 2819c6a44287SMartin K. Petersen num_host_resets, dix_reads, dix_writes, dif_errors); 28201da177e4SLinus Torvalds if (pos < offset) { 28211da177e4SLinus Torvalds len = 0; 28221da177e4SLinus Torvalds begin = pos; 28231da177e4SLinus Torvalds } 28241da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 28251da177e4SLinus Torvalds len -= (offset - begin); 28261da177e4SLinus Torvalds if (len > length) 28271da177e4SLinus Torvalds len = length; 28281da177e4SLinus Torvalds return len; 28291da177e4SLinus Torvalds } 28301da177e4SLinus Torvalds 28311da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 28321da177e4SLinus Torvalds { 28331da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 28341da177e4SLinus Torvalds } 28351da177e4SLinus Torvalds 28361da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 28371da177e4SLinus Torvalds const char * buf, size_t count) 28381da177e4SLinus Torvalds { 28391da177e4SLinus Torvalds int delay; 28401da177e4SLinus Torvalds char work[20]; 28411da177e4SLinus Torvalds 28421da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 28431da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 28441da177e4SLinus Torvalds scsi_debug_delay = delay; 28451da177e4SLinus Torvalds return count; 28461da177e4SLinus Torvalds } 28471da177e4SLinus Torvalds } 28481da177e4SLinus Torvalds return -EINVAL; 28491da177e4SLinus Torvalds } 28501da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 28511da177e4SLinus Torvalds sdebug_delay_store); 28521da177e4SLinus Torvalds 28531da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 28541da177e4SLinus Torvalds { 28551da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 28561da177e4SLinus Torvalds } 28571da177e4SLinus Torvalds 28581da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 28591da177e4SLinus Torvalds const char * buf, size_t count) 28601da177e4SLinus Torvalds { 28611da177e4SLinus Torvalds int opts; 28621da177e4SLinus Torvalds char work[20]; 28631da177e4SLinus Torvalds 28641da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 28651da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 28661da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 28671da177e4SLinus Torvalds goto opts_done; 28681da177e4SLinus Torvalds } else { 28691da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 28701da177e4SLinus Torvalds goto opts_done; 28711da177e4SLinus Torvalds } 28721da177e4SLinus Torvalds } 28731da177e4SLinus Torvalds return -EINVAL; 28741da177e4SLinus Torvalds opts_done: 28751da177e4SLinus Torvalds scsi_debug_opts = opts; 28761da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 28771da177e4SLinus Torvalds return count; 28781da177e4SLinus Torvalds } 28791da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 28801da177e4SLinus Torvalds sdebug_opts_store); 28811da177e4SLinus Torvalds 28821da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 28831da177e4SLinus Torvalds { 28841da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 28851da177e4SLinus Torvalds } 28861da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 28871da177e4SLinus Torvalds const char * buf, size_t count) 28881da177e4SLinus Torvalds { 28891da177e4SLinus Torvalds int n; 28901da177e4SLinus Torvalds 28911da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 28921da177e4SLinus Torvalds scsi_debug_ptype = n; 28931da177e4SLinus Torvalds return count; 28941da177e4SLinus Torvalds } 28951da177e4SLinus Torvalds return -EINVAL; 28961da177e4SLinus Torvalds } 28971da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 28981da177e4SLinus Torvalds 28991da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 29001da177e4SLinus Torvalds { 29011da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 29021da177e4SLinus Torvalds } 29031da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 29041da177e4SLinus Torvalds const char * buf, size_t count) 29051da177e4SLinus Torvalds { 29061da177e4SLinus Torvalds int n; 29071da177e4SLinus Torvalds 29081da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29091da177e4SLinus Torvalds scsi_debug_dsense = n; 29101da177e4SLinus Torvalds return count; 29111da177e4SLinus Torvalds } 29121da177e4SLinus Torvalds return -EINVAL; 29131da177e4SLinus Torvalds } 29141da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 29151da177e4SLinus Torvalds sdebug_dsense_store); 29161da177e4SLinus Torvalds 291723183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 291823183910SDouglas Gilbert { 291923183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 292023183910SDouglas Gilbert } 292123183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 292223183910SDouglas Gilbert const char * buf, size_t count) 292323183910SDouglas Gilbert { 292423183910SDouglas Gilbert int n; 292523183910SDouglas Gilbert 292623183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 292723183910SDouglas Gilbert scsi_debug_fake_rw = n; 292823183910SDouglas Gilbert return count; 292923183910SDouglas Gilbert } 293023183910SDouglas Gilbert return -EINVAL; 293123183910SDouglas Gilbert } 293223183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 293323183910SDouglas Gilbert sdebug_fake_rw_store); 293423183910SDouglas Gilbert 2935c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2936c65b1445SDouglas Gilbert { 2937c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2938c65b1445SDouglas Gilbert } 2939c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2940c65b1445SDouglas Gilbert const char * buf, size_t count) 2941c65b1445SDouglas Gilbert { 2942c65b1445SDouglas Gilbert int n; 2943c65b1445SDouglas Gilbert 2944c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2945c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2946c65b1445SDouglas Gilbert return count; 2947c65b1445SDouglas Gilbert } 2948c65b1445SDouglas Gilbert return -EINVAL; 2949c65b1445SDouglas Gilbert } 2950c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 2951c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 2952c65b1445SDouglas Gilbert 29531da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf) 29541da177e4SLinus Torvalds { 29551da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 29561da177e4SLinus Torvalds } 29571da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 29581da177e4SLinus Torvalds const char * buf, size_t count) 29591da177e4SLinus Torvalds { 29601da177e4SLinus Torvalds int n; 29611da177e4SLinus Torvalds 29621da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29631da177e4SLinus Torvalds scsi_debug_num_tgts = n; 29641da177e4SLinus Torvalds sdebug_max_tgts_luns(); 29651da177e4SLinus Torvalds return count; 29661da177e4SLinus Torvalds } 29671da177e4SLinus Torvalds return -EINVAL; 29681da177e4SLinus Torvalds } 29691da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 29701da177e4SLinus Torvalds sdebug_num_tgts_store); 29711da177e4SLinus Torvalds 29721da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 29731da177e4SLinus Torvalds { 29741da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 29751da177e4SLinus Torvalds } 29761da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 29771da177e4SLinus Torvalds 29781da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 29791da177e4SLinus Torvalds { 29801da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 29811da177e4SLinus Torvalds } 29821da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 29831da177e4SLinus Torvalds 29841da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 29851da177e4SLinus Torvalds { 29861da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 29891da177e4SLinus Torvalds const char * buf, size_t count) 29901da177e4SLinus Torvalds { 29911da177e4SLinus Torvalds int nth; 29921da177e4SLinus Torvalds 29931da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 29941da177e4SLinus Torvalds scsi_debug_every_nth = nth; 29951da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 29961da177e4SLinus Torvalds return count; 29971da177e4SLinus Torvalds } 29981da177e4SLinus Torvalds return -EINVAL; 29991da177e4SLinus Torvalds } 30001da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 30011da177e4SLinus Torvalds sdebug_every_nth_store); 30021da177e4SLinus Torvalds 30031da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 30041da177e4SLinus Torvalds { 30051da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 30061da177e4SLinus Torvalds } 30071da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 30081da177e4SLinus Torvalds const char * buf, size_t count) 30091da177e4SLinus Torvalds { 30101da177e4SLinus Torvalds int n; 30111da177e4SLinus Torvalds 30121da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 30131da177e4SLinus Torvalds scsi_debug_max_luns = n; 30141da177e4SLinus Torvalds sdebug_max_tgts_luns(); 30151da177e4SLinus Torvalds return count; 30161da177e4SLinus Torvalds } 30171da177e4SLinus Torvalds return -EINVAL; 30181da177e4SLinus Torvalds } 30191da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 30201da177e4SLinus Torvalds sdebug_max_luns_store); 30211da177e4SLinus Torvalds 302278d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf) 302378d4e5a0SDouglas Gilbert { 302478d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); 302578d4e5a0SDouglas Gilbert } 302678d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp, 302778d4e5a0SDouglas Gilbert const char * buf, size_t count) 302878d4e5a0SDouglas Gilbert { 302978d4e5a0SDouglas Gilbert int n; 303078d4e5a0SDouglas Gilbert 303178d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 303278d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 303378d4e5a0SDouglas Gilbert scsi_debug_max_queue = n; 303478d4e5a0SDouglas Gilbert return count; 303578d4e5a0SDouglas Gilbert } 303678d4e5a0SDouglas Gilbert return -EINVAL; 303778d4e5a0SDouglas Gilbert } 303878d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show, 303978d4e5a0SDouglas Gilbert sdebug_max_queue_store); 304078d4e5a0SDouglas Gilbert 304178d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf) 304278d4e5a0SDouglas Gilbert { 304378d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); 304478d4e5a0SDouglas Gilbert } 304578d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL); 304678d4e5a0SDouglas Gilbert 30471da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 30481da177e4SLinus Torvalds { 30491da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 30501da177e4SLinus Torvalds } 30511da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 30521da177e4SLinus Torvalds 3053c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 3054c65b1445SDouglas Gilbert { 3055c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 3056c65b1445SDouglas Gilbert } 3057c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 3058c65b1445SDouglas Gilbert const char * buf, size_t count) 3059c65b1445SDouglas Gilbert { 3060c65b1445SDouglas Gilbert int n; 3061c65b1445SDouglas Gilbert 3062c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 3063c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 306428898873SFUJITA Tomonori 306528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 306628898873SFUJITA Tomonori 3067c65b1445SDouglas Gilbert return count; 3068c65b1445SDouglas Gilbert } 3069c65b1445SDouglas Gilbert return -EINVAL; 3070c65b1445SDouglas Gilbert } 3071c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 3072c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 3073c65b1445SDouglas Gilbert 30741da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 30751da177e4SLinus Torvalds { 30761da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 30771da177e4SLinus Torvalds } 30781da177e4SLinus Torvalds 30791da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 30801da177e4SLinus Torvalds const char * buf, size_t count) 30811da177e4SLinus Torvalds { 30821da177e4SLinus Torvalds int delta_hosts; 30831da177e4SLinus Torvalds 3084f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 30851da177e4SLinus Torvalds return -EINVAL; 30861da177e4SLinus Torvalds if (delta_hosts > 0) { 30871da177e4SLinus Torvalds do { 30881da177e4SLinus Torvalds sdebug_add_adapter(); 30891da177e4SLinus Torvalds } while (--delta_hosts); 30901da177e4SLinus Torvalds } else if (delta_hosts < 0) { 30911da177e4SLinus Torvalds do { 30921da177e4SLinus Torvalds sdebug_remove_adapter(); 30931da177e4SLinus Torvalds } while (++delta_hosts); 30941da177e4SLinus Torvalds } 30951da177e4SLinus Torvalds return count; 30961da177e4SLinus Torvalds } 30971da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 30981da177e4SLinus Torvalds sdebug_add_host_store); 30991da177e4SLinus Torvalds 310023183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 310123183910SDouglas Gilbert char * buf) 310223183910SDouglas Gilbert { 310323183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 310423183910SDouglas Gilbert } 310523183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 310623183910SDouglas Gilbert const char * buf, size_t count) 310723183910SDouglas Gilbert { 310823183910SDouglas Gilbert int n; 310923183910SDouglas Gilbert 311023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 311123183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 311223183910SDouglas Gilbert return count; 311323183910SDouglas Gilbert } 311423183910SDouglas Gilbert return -EINVAL; 311523183910SDouglas Gilbert } 311623183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 311723183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 311823183910SDouglas Gilbert 3119597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) 3120597136abSMartin K. Petersen { 3121597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 3122597136abSMartin K. Petersen } 3123597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); 3124597136abSMartin K. Petersen 3125c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) 3126c6a44287SMartin K. Petersen { 3127c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); 3128c6a44287SMartin K. Petersen } 3129c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); 3130c6a44287SMartin K. Petersen 3131c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) 3132c6a44287SMartin K. Petersen { 3133c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); 3134c6a44287SMartin K. Petersen } 3135c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); 3136c6a44287SMartin K. Petersen 3137c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) 3138c6a44287SMartin K. Petersen { 3139c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); 3140c6a44287SMartin K. Petersen } 3141c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); 3142c6a44287SMartin K. Petersen 3143c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) 3144c6a44287SMartin K. Petersen { 3145c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); 3146c6a44287SMartin K. Petersen } 3147c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); 3148c6a44287SMartin K. Petersen 314944d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) 315044d92694SMartin K. Petersen { 315144d92694SMartin K. Petersen ssize_t count; 315244d92694SMartin K. Petersen 31536014759cSMartin K. Petersen if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) 315444d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 315544d92694SMartin K. Petersen sdebug_store_sectors); 315644d92694SMartin K. Petersen 315744d92694SMartin K. Petersen count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); 315844d92694SMartin K. Petersen 315944d92694SMartin K. Petersen buf[count++] = '\n'; 316044d92694SMartin K. Petersen buf[count++] = 0; 316144d92694SMartin K. Petersen 316244d92694SMartin K. Petersen return count; 316344d92694SMartin K. Petersen } 316444d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL); 316544d92694SMartin K. Petersen 3166c6a44287SMartin K. Petersen 316723183910SDouglas Gilbert /* Note: The following function creates attribute files in the 316823183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 316923183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 317023183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 317123183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 317223183910SDouglas Gilbert */ 31736ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 31741da177e4SLinus Torvalds { 31756ecaff7fSRandy Dunlap int ret; 31766ecaff7fSRandy Dunlap 31776ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 31786ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 31796ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 31806ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 31816ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 318223183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 31836ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 318478d4e5a0SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue); 318523183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 318678d4e5a0SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld); 31876ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 318823183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 31896ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 31906ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 31916ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 319223183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 319323183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 3194597136abSMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 3195c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); 3196c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); 3197c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); 3198c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); 319944d92694SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map); 32006ecaff7fSRandy Dunlap return ret; 32011da177e4SLinus Torvalds } 32021da177e4SLinus Torvalds 32031da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 32041da177e4SLinus Torvalds { 320544d92694SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map); 3206c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); 3207c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); 3208c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); 3209c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); 3210597136abSMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 321123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 321223183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 32131da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 32141da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 32151da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 32161da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 321723183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 321878d4e5a0SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld); 321923183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 322078d4e5a0SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue); 32211da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 322223183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 32231da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 32241da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 32251da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 32261da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 32271da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 32281da177e4SLinus Torvalds } 32291da177e4SLinus Torvalds 32309b906779SNicholas Bellinger struct device *pseudo_primary; 32318dea0d02SFUJITA Tomonori 32321da177e4SLinus Torvalds static int __init scsi_debug_init(void) 32331da177e4SLinus Torvalds { 32345f2578e5SFUJITA Tomonori unsigned long sz; 32351da177e4SLinus Torvalds int host_to_add; 32361da177e4SLinus Torvalds int k; 32376ecaff7fSRandy Dunlap int ret; 32381da177e4SLinus Torvalds 3239597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 3240597136abSMartin K. Petersen case 512: 3241597136abSMartin K. Petersen case 1024: 3242597136abSMartin K. Petersen case 2048: 3243597136abSMartin K. Petersen case 4096: 3244597136abSMartin K. Petersen break; 3245597136abSMartin K. Petersen default: 3246c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", 3247597136abSMartin K. Petersen scsi_debug_sector_size); 3248597136abSMartin K. Petersen return -EINVAL; 3249597136abSMartin K. Petersen } 3250597136abSMartin K. Petersen 3251c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 3252c6a44287SMartin K. Petersen 3253c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 3254c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 3255395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 3256c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 3257c6a44287SMartin K. Petersen break; 3258c6a44287SMartin K. Petersen 3259c6a44287SMartin K. Petersen default: 3260395cef03SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); 3261c6a44287SMartin K. Petersen return -EINVAL; 3262c6a44287SMartin K. Petersen } 3263c6a44287SMartin K. Petersen 3264c6a44287SMartin K. Petersen if (scsi_debug_guard > 1) { 3265c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); 3266c6a44287SMartin K. Petersen return -EINVAL; 3267c6a44287SMartin K. Petersen } 3268c6a44287SMartin K. Petersen 3269c6a44287SMartin K. Petersen if (scsi_debug_ato > 1) { 3270c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); 3271c6a44287SMartin K. Petersen return -EINVAL; 3272c6a44287SMartin K. Petersen } 3273c6a44287SMartin K. Petersen 3274ea61fca5SMartin K. Petersen if (scsi_debug_physblk_exp > 15) { 3275ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n", 3276ea61fca5SMartin K. Petersen scsi_debug_physblk_exp); 3277ea61fca5SMartin K. Petersen return -EINVAL; 3278ea61fca5SMartin K. Petersen } 3279ea61fca5SMartin K. Petersen 3280ea61fca5SMartin K. Petersen if (scsi_debug_lowest_aligned > 0x3fff) { 3281ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n", 3282ea61fca5SMartin K. Petersen scsi_debug_lowest_aligned); 3283ea61fca5SMartin K. Petersen return -EINVAL; 3284ea61fca5SMartin K. Petersen } 3285ea61fca5SMartin K. Petersen 32861da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 32871da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 32885f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 3289597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 329028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 32911da177e4SLinus Torvalds 32921da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 32931da177e4SLinus Torvalds sdebug_heads = 8; 32941da177e4SLinus Torvalds sdebug_sectors_per = 32; 32951da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 32961da177e4SLinus Torvalds sdebug_heads = 32; 32971da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 32981da177e4SLinus Torvalds sdebug_heads = 64; 32991da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33001da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33011da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 33021da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 33031da177e4SLinus Torvalds sdebug_heads = 255; 33041da177e4SLinus Torvalds sdebug_sectors_per = 63; 33051da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33061da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33071da177e4SLinus Torvalds } 33081da177e4SLinus Torvalds 33091da177e4SLinus Torvalds fake_storep = vmalloc(sz); 33101da177e4SLinus Torvalds if (NULL == fake_storep) { 33111da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 33121da177e4SLinus Torvalds return -ENOMEM; 33131da177e4SLinus Torvalds } 33141da177e4SLinus Torvalds memset(fake_storep, 0, sz); 33151da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 3316f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 33171da177e4SLinus Torvalds 3318c6a44287SMartin K. Petersen if (scsi_debug_dif) { 3319c6a44287SMartin K. Petersen int dif_size; 3320c6a44287SMartin K. Petersen 3321c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 3322c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 3323c6a44287SMartin K. Petersen 3324c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", 3325c6a44287SMartin K. Petersen dif_size, dif_storep); 3326c6a44287SMartin K. Petersen 3327c6a44287SMartin K. Petersen if (dif_storep == NULL) { 3328c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); 3329c6a44287SMartin K. Petersen ret = -ENOMEM; 3330c6a44287SMartin K. Petersen goto free_vm; 3331c6a44287SMartin K. Petersen } 3332c6a44287SMartin K. Petersen 3333c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 3334c6a44287SMartin K. Petersen } 3335c6a44287SMartin K. Petersen 33366014759cSMartin K. Petersen /* Thin Provisioning */ 33376014759cSMartin K. Petersen if (scsi_debug_tpu || scsi_debug_tpws) { 333844d92694SMartin K. Petersen unsigned int map_bytes; 333944d92694SMartin K. Petersen 33406014759cSMartin K. Petersen scsi_debug_unmap_max_blocks = 33416014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); 33426014759cSMartin K. Petersen 33436014759cSMartin K. Petersen scsi_debug_unmap_max_desc = 33446014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_desc, 0U, 256U); 33456014759cSMartin K. Petersen 33466014759cSMartin K. Petersen scsi_debug_unmap_granularity = 33476014759cSMartin K. Petersen clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); 33486014759cSMartin K. Petersen 33496014759cSMartin K. Petersen if (scsi_debug_unmap_alignment && 33506014759cSMartin K. Petersen scsi_debug_unmap_granularity < scsi_debug_unmap_alignment) { 335144d92694SMartin K. Petersen printk(KERN_ERR 335244d92694SMartin K. Petersen "%s: ERR: unmap_granularity < unmap_alignment\n", 335344d92694SMartin K. Petersen __func__); 335444d92694SMartin K. Petersen return -EINVAL; 335544d92694SMartin K. Petersen } 335644d92694SMartin K. Petersen 335744d92694SMartin K. Petersen map_size = (sdebug_store_sectors / scsi_debug_unmap_granularity); 335844d92694SMartin K. Petersen map_bytes = map_size >> 3; 335944d92694SMartin K. Petersen map_storep = vmalloc(map_bytes); 336044d92694SMartin K. Petersen 336144d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", 336244d92694SMartin K. Petersen map_size); 336344d92694SMartin K. Petersen 336444d92694SMartin K. Petersen if (map_storep == NULL) { 336544d92694SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n"); 336644d92694SMartin K. Petersen ret = -ENOMEM; 336744d92694SMartin K. Petersen goto free_vm; 336844d92694SMartin K. Petersen } 336944d92694SMartin K. Petersen 337044d92694SMartin K. Petersen memset(map_storep, 0x0, map_bytes); 337144d92694SMartin K. Petersen 337244d92694SMartin K. Petersen /* Map first 1KB for partition table */ 337344d92694SMartin K. Petersen if (scsi_debug_num_parts) 337444d92694SMartin K. Petersen map_region(0, 2); 337544d92694SMartin K. Petersen } 337644d92694SMartin K. Petersen 33779b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 33789b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 33799b906779SNicholas Bellinger printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); 33809b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 33816ecaff7fSRandy Dunlap goto free_vm; 33826ecaff7fSRandy Dunlap } 33836ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 33846ecaff7fSRandy Dunlap if (ret < 0) { 33856ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 33866ecaff7fSRandy Dunlap ret); 33876ecaff7fSRandy Dunlap goto dev_unreg; 33886ecaff7fSRandy Dunlap } 33896ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 33906ecaff7fSRandy Dunlap if (ret < 0) { 33916ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 33926ecaff7fSRandy Dunlap ret); 33936ecaff7fSRandy Dunlap goto bus_unreg; 33946ecaff7fSRandy Dunlap } 33956ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 33966ecaff7fSRandy Dunlap if (ret < 0) { 33976ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 33986ecaff7fSRandy Dunlap ret); 33996ecaff7fSRandy Dunlap goto del_files; 34006ecaff7fSRandy Dunlap } 34011da177e4SLinus Torvalds 34026ecaff7fSRandy Dunlap init_all_queued(); 34031da177e4SLinus Torvalds 34041da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 34051da177e4SLinus Torvalds scsi_debug_add_host = 0; 34061da177e4SLinus Torvalds 34071da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 34081da177e4SLinus Torvalds if (sdebug_add_adapter()) { 34091da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 34101da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 34111da177e4SLinus Torvalds break; 34121da177e4SLinus Torvalds } 34131da177e4SLinus Torvalds } 34141da177e4SLinus Torvalds 34151da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 34161da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 34171da177e4SLinus Torvalds scsi_debug_add_host); 34181da177e4SLinus Torvalds } 34191da177e4SLinus Torvalds return 0; 34206ecaff7fSRandy Dunlap 34216ecaff7fSRandy Dunlap del_files: 34226ecaff7fSRandy Dunlap do_remove_driverfs_files(); 34236ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 34246ecaff7fSRandy Dunlap bus_unreg: 34256ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 34266ecaff7fSRandy Dunlap dev_unreg: 34279b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 34286ecaff7fSRandy Dunlap free_vm: 342944d92694SMartin K. Petersen if (map_storep) 343044d92694SMartin K. Petersen vfree(map_storep); 3431c6a44287SMartin K. Petersen if (dif_storep) 3432c6a44287SMartin K. Petersen vfree(dif_storep); 34336ecaff7fSRandy Dunlap vfree(fake_storep); 34346ecaff7fSRandy Dunlap 34356ecaff7fSRandy Dunlap return ret; 34361da177e4SLinus Torvalds } 34371da177e4SLinus Torvalds 34381da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 34391da177e4SLinus Torvalds { 34401da177e4SLinus Torvalds int k = scsi_debug_add_host; 34411da177e4SLinus Torvalds 34421da177e4SLinus Torvalds stop_all_queued(); 34431da177e4SLinus Torvalds for (; k; k--) 34441da177e4SLinus Torvalds sdebug_remove_adapter(); 34451da177e4SLinus Torvalds do_remove_driverfs_files(); 34461da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 34471da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 34489b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 34491da177e4SLinus Torvalds 3450c6a44287SMartin K. Petersen if (dif_storep) 3451c6a44287SMartin K. Petersen vfree(dif_storep); 3452c6a44287SMartin K. Petersen 34531da177e4SLinus Torvalds vfree(fake_storep); 34541da177e4SLinus Torvalds } 34551da177e4SLinus Torvalds 34561da177e4SLinus Torvalds device_initcall(scsi_debug_init); 34571da177e4SLinus Torvalds module_exit(scsi_debug_exit); 34581da177e4SLinus Torvalds 34591da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 34601da177e4SLinus Torvalds { 34611da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 34621da177e4SLinus Torvalds 34631da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 34641da177e4SLinus Torvalds kfree(sdbg_host); 34651da177e4SLinus Torvalds } 34661da177e4SLinus Torvalds 34671da177e4SLinus Torvalds static int sdebug_add_adapter(void) 34681da177e4SLinus Torvalds { 34691da177e4SLinus Torvalds int k, devs_per_host; 34701da177e4SLinus Torvalds int error = 0; 34711da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 34728b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 34731da177e4SLinus Torvalds 347424669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 34751da177e4SLinus Torvalds if (NULL == sdbg_host) { 34761da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3477cadbd4a5SHarvey Harrison __func__, __LINE__); 34781da177e4SLinus Torvalds return -ENOMEM; 34791da177e4SLinus Torvalds } 34801da177e4SLinus Torvalds 34811da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 34821da177e4SLinus Torvalds 34831da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 34841da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 34855cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 34865cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 34871da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3488cadbd4a5SHarvey Harrison __func__, __LINE__); 34891da177e4SLinus Torvalds error = -ENOMEM; 34901da177e4SLinus Torvalds goto clean; 34911da177e4SLinus Torvalds } 34921da177e4SLinus Torvalds } 34931da177e4SLinus Torvalds 34941da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 34951da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 34961da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 34971da177e4SLinus Torvalds 34981da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 34999b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 35001da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 350171610f55SKay Sievers dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); 35021da177e4SLinus Torvalds 35031da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 35041da177e4SLinus Torvalds 35051da177e4SLinus Torvalds if (error) 35061da177e4SLinus Torvalds goto clean; 35071da177e4SLinus Torvalds 35081da177e4SLinus Torvalds ++scsi_debug_add_host; 35091da177e4SLinus Torvalds return error; 35101da177e4SLinus Torvalds 35111da177e4SLinus Torvalds clean: 35128b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 35138b40228fSFUJITA Tomonori dev_list) { 35141da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 35151da177e4SLinus Torvalds kfree(sdbg_devinfo); 35161da177e4SLinus Torvalds } 35171da177e4SLinus Torvalds 35181da177e4SLinus Torvalds kfree(sdbg_host); 35191da177e4SLinus Torvalds return error; 35201da177e4SLinus Torvalds } 35211da177e4SLinus Torvalds 35221da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 35231da177e4SLinus Torvalds { 35241da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 35251da177e4SLinus Torvalds 35261da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 35271da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 35281da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 35291da177e4SLinus Torvalds struct sdebug_host_info, host_list); 35301da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 35311da177e4SLinus Torvalds } 35321da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 35331da177e4SLinus Torvalds 35341da177e4SLinus Torvalds if (!sdbg_host) 35351da177e4SLinus Torvalds return; 35361da177e4SLinus Torvalds 35371da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 35381da177e4SLinus Torvalds --scsi_debug_add_host; 35391da177e4SLinus Torvalds } 35401da177e4SLinus Torvalds 3541639db475SFUJITA Tomonori static 3542f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) 3543639db475SFUJITA Tomonori { 3544639db475SFUJITA Tomonori unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 3545639db475SFUJITA Tomonori int len, k; 3546639db475SFUJITA Tomonori unsigned int num; 3547639db475SFUJITA Tomonori unsigned long long lba; 3548395cef03SMartin K. Petersen u32 ei_lba; 3549639db475SFUJITA Tomonori int errsts = 0; 3550639db475SFUJITA Tomonori int target = SCpnt->device->id; 3551639db475SFUJITA Tomonori struct sdebug_dev_info *devip = NULL; 3552639db475SFUJITA Tomonori int inj_recovered = 0; 3553639db475SFUJITA Tomonori int inj_transport = 0; 3554c6a44287SMartin K. Petersen int inj_dif = 0; 3555c6a44287SMartin K. Petersen int inj_dix = 0; 3556639db475SFUJITA Tomonori int delay_override = 0; 355744d92694SMartin K. Petersen int unmap = 0; 3558639db475SFUJITA Tomonori 3559639db475SFUJITA Tomonori scsi_set_resid(SCpnt, 0); 3560639db475SFUJITA Tomonori if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 3561639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: cmd "); 3562639db475SFUJITA Tomonori for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 3563639db475SFUJITA Tomonori printk("%02x ", (int)cmd[k]); 3564639db475SFUJITA Tomonori printk("\n"); 3565639db475SFUJITA Tomonori } 3566639db475SFUJITA Tomonori 3567639db475SFUJITA Tomonori if (target == SCpnt->device->host->hostt->this_id) { 3568639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: initiator's id used as " 3569639db475SFUJITA Tomonori "target!\n"); 3570639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3571639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3572639db475SFUJITA Tomonori } 3573639db475SFUJITA Tomonori 3574639db475SFUJITA Tomonori if ((SCpnt->device->lun >= scsi_debug_max_luns) && 3575639db475SFUJITA Tomonori (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 3576639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3577639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3578639db475SFUJITA Tomonori devip = devInfoReg(SCpnt->device); 3579639db475SFUJITA Tomonori if (NULL == devip) 3580639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3581639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3582639db475SFUJITA Tomonori 3583639db475SFUJITA Tomonori if ((scsi_debug_every_nth != 0) && 3584639db475SFUJITA Tomonori (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3585639db475SFUJITA Tomonori scsi_debug_cmnd_count = 0; 3586639db475SFUJITA Tomonori if (scsi_debug_every_nth < -1) 3587639db475SFUJITA Tomonori scsi_debug_every_nth = -1; 3588639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3589639db475SFUJITA Tomonori return 0; /* ignore command causing timeout */ 3590639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3591639db475SFUJITA Tomonori inj_recovered = 1; /* to reads and writes below */ 3592639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 3593639db475SFUJITA Tomonori inj_transport = 1; /* to reads and writes below */ 3594c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) 3595c6a44287SMartin K. Petersen inj_dif = 1; /* to reads and writes below */ 3596c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) 3597c6a44287SMartin K. Petersen inj_dix = 1; /* to reads and writes below */ 3598639db475SFUJITA Tomonori } 3599639db475SFUJITA Tomonori 3600639db475SFUJITA Tomonori if (devip->wlun) { 3601639db475SFUJITA Tomonori switch (*cmd) { 3602639db475SFUJITA Tomonori case INQUIRY: 3603639db475SFUJITA Tomonori case REQUEST_SENSE: 3604639db475SFUJITA Tomonori case TEST_UNIT_READY: 3605639db475SFUJITA Tomonori case REPORT_LUNS: 3606639db475SFUJITA Tomonori break; /* only allowable wlun commands */ 3607639db475SFUJITA Tomonori default: 3608639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3609639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 3610639db475SFUJITA Tomonori "not supported for wlun\n", *cmd); 3611639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3612639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3613639db475SFUJITA Tomonori errsts = check_condition_result; 3614639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3615639db475SFUJITA Tomonori 0); 3616639db475SFUJITA Tomonori } 3617639db475SFUJITA Tomonori } 3618639db475SFUJITA Tomonori 3619639db475SFUJITA Tomonori switch (*cmd) { 3620639db475SFUJITA Tomonori case INQUIRY: /* mandatory, ignore unit attention */ 3621639db475SFUJITA Tomonori delay_override = 1; 3622639db475SFUJITA Tomonori errsts = resp_inquiry(SCpnt, target, devip); 3623639db475SFUJITA Tomonori break; 3624639db475SFUJITA Tomonori case REQUEST_SENSE: /* mandatory, ignore unit attention */ 3625639db475SFUJITA Tomonori delay_override = 1; 3626639db475SFUJITA Tomonori errsts = resp_requests(SCpnt, devip); 3627639db475SFUJITA Tomonori break; 3628639db475SFUJITA Tomonori case REZERO_UNIT: /* actually this is REWIND for SSC */ 3629639db475SFUJITA Tomonori case START_STOP: 3630639db475SFUJITA Tomonori errsts = resp_start_stop(SCpnt, devip); 3631639db475SFUJITA Tomonori break; 3632639db475SFUJITA Tomonori case ALLOW_MEDIUM_REMOVAL: 3633639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3634639db475SFUJITA Tomonori if (errsts) 3635639db475SFUJITA Tomonori break; 3636639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3637639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Medium removal %s\n", 3638639db475SFUJITA Tomonori cmd[4] ? "inhibited" : "enabled"); 3639639db475SFUJITA Tomonori break; 3640639db475SFUJITA Tomonori case SEND_DIAGNOSTIC: /* mandatory */ 3641639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3642639db475SFUJITA Tomonori break; 3643639db475SFUJITA Tomonori case TEST_UNIT_READY: /* mandatory */ 3644639db475SFUJITA Tomonori delay_override = 1; 3645639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3646639db475SFUJITA Tomonori break; 3647639db475SFUJITA Tomonori case RESERVE: 3648639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3649639db475SFUJITA Tomonori break; 3650639db475SFUJITA Tomonori case RESERVE_10: 3651639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3652639db475SFUJITA Tomonori break; 3653639db475SFUJITA Tomonori case RELEASE: 3654639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3655639db475SFUJITA Tomonori break; 3656639db475SFUJITA Tomonori case RELEASE_10: 3657639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3658639db475SFUJITA Tomonori break; 3659639db475SFUJITA Tomonori case READ_CAPACITY: 3660639db475SFUJITA Tomonori errsts = resp_readcap(SCpnt, devip); 3661639db475SFUJITA Tomonori break; 3662639db475SFUJITA Tomonori case SERVICE_ACTION_IN: 366344d92694SMartin K. Petersen if (cmd[1] == SAI_READ_CAPACITY_16) 366444d92694SMartin K. Petersen errsts = resp_readcap16(SCpnt, devip); 366544d92694SMartin K. Petersen else if (cmd[1] == SAI_GET_LBA_STATUS) { 366644d92694SMartin K. Petersen 36676014759cSMartin K. Petersen if (scsi_debug_tpu == 0 && scsi_debug_tpws == 0) { 366844d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 366944d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 367044d92694SMartin K. Petersen errsts = check_condition_result; 367144d92694SMartin K. Petersen } else 367244d92694SMartin K. Petersen errsts = resp_get_lba_status(SCpnt, devip); 367344d92694SMartin K. Petersen } else { 3674639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3675639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3676639db475SFUJITA Tomonori errsts = check_condition_result; 3677639db475SFUJITA Tomonori } 3678639db475SFUJITA Tomonori break; 3679639db475SFUJITA Tomonori case MAINTENANCE_IN: 3680639db475SFUJITA Tomonori if (MI_REPORT_TARGET_PGS != cmd[1]) { 3681639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3682639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3683639db475SFUJITA Tomonori errsts = check_condition_result; 3684639db475SFUJITA Tomonori break; 3685639db475SFUJITA Tomonori } 3686639db475SFUJITA Tomonori errsts = resp_report_tgtpgs(SCpnt, devip); 3687639db475SFUJITA Tomonori break; 3688639db475SFUJITA Tomonori case READ_16: 3689639db475SFUJITA Tomonori case READ_12: 3690639db475SFUJITA Tomonori case READ_10: 3691395cef03SMartin K. Petersen /* READ{10,12,16} and DIF Type 2 are natural enemies */ 3692395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3693395cef03SMartin K. Petersen cmd[1] & 0xe0) { 3694395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3695395cef03SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 3696395cef03SMartin K. Petersen errsts = check_condition_result; 3697395cef03SMartin K. Petersen break; 3698395cef03SMartin K. Petersen } 3699395cef03SMartin K. Petersen 3700395cef03SMartin K. Petersen if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3701395cef03SMartin K. Petersen scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3702395cef03SMartin K. Petersen (cmd[1] & 0xe0) == 0) 3703395cef03SMartin K. Petersen printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3704395cef03SMartin K. Petersen 3705395cef03SMartin K. Petersen /* fall through */ 3706639db475SFUJITA Tomonori case READ_6: 3707395cef03SMartin K. Petersen read: 3708639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3709639db475SFUJITA Tomonori if (errsts) 3710639db475SFUJITA Tomonori break; 3711639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3712639db475SFUJITA Tomonori break; 3713395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3714395cef03SMartin K. Petersen errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3715639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 3716639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 3717639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 3718639db475SFUJITA Tomonori errsts = check_condition_result; 3719639db475SFUJITA Tomonori } else if (inj_transport && (0 == errsts)) { 3720639db475SFUJITA Tomonori mk_sense_buffer(devip, ABORTED_COMMAND, 3721639db475SFUJITA Tomonori TRANSPORT_PROBLEM, ACK_NAK_TO); 3722639db475SFUJITA Tomonori errsts = check_condition_result; 3723c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3724c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3725c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3726c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3727c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3728c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3729639db475SFUJITA Tomonori } 3730639db475SFUJITA Tomonori break; 3731639db475SFUJITA Tomonori case REPORT_LUNS: /* mandatory, ignore unit attention */ 3732639db475SFUJITA Tomonori delay_override = 1; 3733639db475SFUJITA Tomonori errsts = resp_report_luns(SCpnt, devip); 3734639db475SFUJITA Tomonori break; 3735639db475SFUJITA Tomonori case VERIFY: /* 10 byte SBC-2 command */ 3736639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3737639db475SFUJITA Tomonori break; 3738639db475SFUJITA Tomonori case WRITE_16: 3739639db475SFUJITA Tomonori case WRITE_12: 3740639db475SFUJITA Tomonori case WRITE_10: 3741395cef03SMartin K. Petersen /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ 3742395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3743395cef03SMartin K. Petersen cmd[1] & 0xe0) { 3744395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3745395cef03SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 3746395cef03SMartin K. Petersen errsts = check_condition_result; 3747395cef03SMartin K. Petersen break; 3748395cef03SMartin K. Petersen } 3749395cef03SMartin K. Petersen 3750395cef03SMartin K. Petersen if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3751395cef03SMartin K. Petersen scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3752395cef03SMartin K. Petersen (cmd[1] & 0xe0) == 0) 3753395cef03SMartin K. Petersen printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3754395cef03SMartin K. Petersen 3755395cef03SMartin K. Petersen /* fall through */ 3756639db475SFUJITA Tomonori case WRITE_6: 3757395cef03SMartin K. Petersen write: 3758639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3759639db475SFUJITA Tomonori if (errsts) 3760639db475SFUJITA Tomonori break; 3761639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3762639db475SFUJITA Tomonori break; 3763395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3764395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3765639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 3766639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 3767639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 3768639db475SFUJITA Tomonori errsts = check_condition_result; 3769c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3770c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3771c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3772c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3773c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3774c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3775639db475SFUJITA Tomonori } 3776639db475SFUJITA Tomonori break; 377744d92694SMartin K. Petersen case WRITE_SAME_16: 37786014759cSMartin K. Petersen if (cmd[1] & 0x8) { 37796014759cSMartin K. Petersen if (scsi_debug_tpws == 0) { 37806014759cSMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 37816014759cSMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 37826014759cSMartin K. Petersen errsts = check_condition_result; 37836014759cSMartin K. Petersen } else 378444d92694SMartin K. Petersen unmap = 1; 37856014759cSMartin K. Petersen } 37866014759cSMartin K. Petersen if (errsts) 37876014759cSMartin K. Petersen break; 378844d92694SMartin K. Petersen /* fall through */ 378944d92694SMartin K. Petersen case WRITE_SAME: 379044d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 379144d92694SMartin K. Petersen if (errsts) 379244d92694SMartin K. Petersen break; 379344d92694SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 379444d92694SMartin K. Petersen errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap); 379544d92694SMartin K. Petersen break; 379644d92694SMartin K. Petersen case UNMAP: 379744d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 379844d92694SMartin K. Petersen if (errsts) 379944d92694SMartin K. Petersen break; 380044d92694SMartin K. Petersen 38016014759cSMartin K. Petersen if (scsi_debug_unmap_max_desc == 0 || scsi_debug_tpu == 0) { 380244d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 380344d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 380444d92694SMartin K. Petersen errsts = check_condition_result; 380544d92694SMartin K. Petersen } else 380644d92694SMartin K. Petersen errsts = resp_unmap(SCpnt, devip); 380744d92694SMartin K. Petersen break; 3808639db475SFUJITA Tomonori case MODE_SENSE: 3809639db475SFUJITA Tomonori case MODE_SENSE_10: 3810639db475SFUJITA Tomonori errsts = resp_mode_sense(SCpnt, target, devip); 3811639db475SFUJITA Tomonori break; 3812639db475SFUJITA Tomonori case MODE_SELECT: 3813639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 1, devip); 3814639db475SFUJITA Tomonori break; 3815639db475SFUJITA Tomonori case MODE_SELECT_10: 3816639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 0, devip); 3817639db475SFUJITA Tomonori break; 3818639db475SFUJITA Tomonori case LOG_SENSE: 3819639db475SFUJITA Tomonori errsts = resp_log_sense(SCpnt, devip); 3820639db475SFUJITA Tomonori break; 3821639db475SFUJITA Tomonori case SYNCHRONIZE_CACHE: 3822639db475SFUJITA Tomonori delay_override = 1; 3823639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3824639db475SFUJITA Tomonori break; 3825639db475SFUJITA Tomonori case WRITE_BUFFER: 3826639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3827639db475SFUJITA Tomonori break; 3828639db475SFUJITA Tomonori case XDWRITEREAD_10: 3829639db475SFUJITA Tomonori if (!scsi_bidi_cmnd(SCpnt)) { 3830639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3831639db475SFUJITA Tomonori INVALID_FIELD_IN_CDB, 0); 3832639db475SFUJITA Tomonori errsts = check_condition_result; 3833639db475SFUJITA Tomonori break; 3834639db475SFUJITA Tomonori } 3835639db475SFUJITA Tomonori 3836639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3837639db475SFUJITA Tomonori if (errsts) 3838639db475SFUJITA Tomonori break; 3839639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3840639db475SFUJITA Tomonori break; 3841395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3842395cef03SMartin K. Petersen errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3843639db475SFUJITA Tomonori if (errsts) 3844639db475SFUJITA Tomonori break; 3845395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3846639db475SFUJITA Tomonori if (errsts) 3847639db475SFUJITA Tomonori break; 3848639db475SFUJITA Tomonori errsts = resp_xdwriteread(SCpnt, lba, num, devip); 3849639db475SFUJITA Tomonori break; 3850395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 3851395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { 3852395cef03SMartin K. Petersen 3853395cef03SMartin K. Petersen if ((cmd[10] & 0xe0) == 0) 3854395cef03SMartin K. Petersen printk(KERN_ERR 3855395cef03SMartin K. Petersen "Unprotected RD/WR to DIF device\n"); 3856395cef03SMartin K. Petersen 3857395cef03SMartin K. Petersen if (cmd[9] == READ_32) { 3858395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3859395cef03SMartin K. Petersen goto read; 3860395cef03SMartin K. Petersen } 3861395cef03SMartin K. Petersen 3862395cef03SMartin K. Petersen if (cmd[9] == WRITE_32) { 3863395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3864395cef03SMartin K. Petersen goto write; 3865395cef03SMartin K. Petersen } 3866395cef03SMartin K. Petersen } 3867395cef03SMartin K. Petersen 3868395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3869395cef03SMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 3870395cef03SMartin K. Petersen errsts = check_condition_result; 3871395cef03SMartin K. Petersen break; 3872395cef03SMartin K. Petersen 3873639db475SFUJITA Tomonori default: 3874639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3875639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 3876639db475SFUJITA Tomonori "supported\n", *cmd); 3877639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3878639db475SFUJITA Tomonori if (errsts) 3879639db475SFUJITA Tomonori break; /* Unit attention takes precedence */ 3880639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 3881639db475SFUJITA Tomonori errsts = check_condition_result; 3882639db475SFUJITA Tomonori break; 3883639db475SFUJITA Tomonori } 3884639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3885639db475SFUJITA Tomonori (delay_override ? 0 : scsi_debug_delay)); 3886639db475SFUJITA Tomonori } 3887639db475SFUJITA Tomonori 3888f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand) 3889f281233dSJeff Garzik 38909e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 38919e603ca0SFUJITA Tomonori .proc_info = scsi_debug_proc_info, 38929e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 38939e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 38949e603ca0SFUJITA Tomonori .info = scsi_debug_info, 38959e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 38969e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 38979e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 38989e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 38999e603ca0SFUJITA Tomonori .queuecommand = scsi_debug_queuecommand, 39009e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 39019e603ca0SFUJITA Tomonori .eh_bus_reset_handler = scsi_debug_bus_reset, 39029e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 39039e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 39049e603ca0SFUJITA Tomonori .bios_param = scsi_debug_biosparam, 39059e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 39069e603ca0SFUJITA Tomonori .this_id = 7, 39079e603ca0SFUJITA Tomonori .sg_tablesize = 256, 39089e603ca0SFUJITA Tomonori .cmd_per_lun = 16, 39099e603ca0SFUJITA Tomonori .max_sectors = 0xffff, 39109e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 39119e603ca0SFUJITA Tomonori .module = THIS_MODULE, 39129e603ca0SFUJITA Tomonori }; 39139e603ca0SFUJITA Tomonori 39141da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 39151da177e4SLinus Torvalds { 39161da177e4SLinus Torvalds int error = 0; 39171da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 39181da177e4SLinus Torvalds struct Scsi_Host *hpnt; 3919c6a44287SMartin K. Petersen int host_prot; 39201da177e4SLinus Torvalds 39211da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 39221da177e4SLinus Torvalds 392378d4e5a0SDouglas Gilbert sdebug_driver_template.can_queue = scsi_debug_max_queue; 39241da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 39251da177e4SLinus Torvalds if (NULL == hpnt) { 3926cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_register failed\n", __func__); 39271da177e4SLinus Torvalds error = -ENODEV; 39281da177e4SLinus Torvalds return error; 39291da177e4SLinus Torvalds } 39301da177e4SLinus Torvalds 39311da177e4SLinus Torvalds sdbg_host->shost = hpnt; 39321da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 39331da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 39341da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 39351da177e4SLinus Torvalds else 39361da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 3937c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 39381da177e4SLinus Torvalds 3939c6a44287SMartin K. Petersen host_prot = 0; 3940c6a44287SMartin K. Petersen 3941c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 3942c6a44287SMartin K. Petersen 3943c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 3944c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE1_PROTECTION; 3945c6a44287SMartin K. Petersen if (scsi_debug_dix) 3946c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE1_PROTECTION; 3947c6a44287SMartin K. Petersen break; 3948c6a44287SMartin K. Petersen 3949c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 3950c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE2_PROTECTION; 3951c6a44287SMartin K. Petersen if (scsi_debug_dix) 3952c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE2_PROTECTION; 3953c6a44287SMartin K. Petersen break; 3954c6a44287SMartin K. Petersen 3955c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 3956c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE3_PROTECTION; 3957c6a44287SMartin K. Petersen if (scsi_debug_dix) 3958c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE3_PROTECTION; 3959c6a44287SMartin K. Petersen break; 3960c6a44287SMartin K. Petersen 3961c6a44287SMartin K. Petersen default: 3962c6a44287SMartin K. Petersen if (scsi_debug_dix) 3963c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE0_PROTECTION; 3964c6a44287SMartin K. Petersen break; 3965c6a44287SMartin K. Petersen } 3966c6a44287SMartin K. Petersen 3967c6a44287SMartin K. Petersen scsi_host_set_prot(hpnt, host_prot); 3968c6a44287SMartin K. Petersen 3969c6a44287SMartin K. Petersen printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", 3970c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 3971c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 3972c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 3973c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 3974c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 3975c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 3976c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 3977c6a44287SMartin K. Petersen 3978c6a44287SMartin K. Petersen if (scsi_debug_guard == 1) 3979c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 3980c6a44287SMartin K. Petersen else 3981c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 3982c6a44287SMartin K. Petersen 39831da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 39841da177e4SLinus Torvalds if (error) { 3985cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); 39861da177e4SLinus Torvalds error = -ENODEV; 39871da177e4SLinus Torvalds scsi_host_put(hpnt); 39881da177e4SLinus Torvalds } else 39891da177e4SLinus Torvalds scsi_scan_host(hpnt); 39901da177e4SLinus Torvalds 39911da177e4SLinus Torvalds 39921da177e4SLinus Torvalds return error; 39931da177e4SLinus Torvalds } 39941da177e4SLinus Torvalds 39951da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 39961da177e4SLinus Torvalds { 39971da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 39988b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 39991da177e4SLinus Torvalds 40001da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 40011da177e4SLinus Torvalds 40021da177e4SLinus Torvalds if (!sdbg_host) { 40031da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 4004cadbd4a5SHarvey Harrison __func__); 40051da177e4SLinus Torvalds return -ENODEV; 40061da177e4SLinus Torvalds } 40071da177e4SLinus Torvalds 40081da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 40091da177e4SLinus Torvalds 40108b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 40118b40228fSFUJITA Tomonori dev_list) { 40121da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 40131da177e4SLinus Torvalds kfree(sdbg_devinfo); 40141da177e4SLinus Torvalds } 40151da177e4SLinus Torvalds 40161da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 40171da177e4SLinus Torvalds return 0; 40181da177e4SLinus Torvalds } 40191da177e4SLinus Torvalds 40208dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 40218dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 40221da177e4SLinus Torvalds { 40238dea0d02SFUJITA Tomonori return 1; 40248dea0d02SFUJITA Tomonori } 40251da177e4SLinus Torvalds 40268dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 40278dea0d02SFUJITA Tomonori .name = "pseudo", 40288dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 40298dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 40308dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 40318dea0d02SFUJITA Tomonori }; 4032