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 67c5af0db9SAkinobu Mita #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 681da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 69c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 701da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 711da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 72395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20 731da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 74c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 751da177e4SLinus Torvalds #define POWERON_RESET 0x29 761da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 776f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 78c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 79c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 801da177e4SLinus Torvalds 816f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 826f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 836f3cbf55SDouglas Gilbert 841da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 851da177e4SLinus Torvalds 861da177e4SLinus Torvalds /* Default values for driver parameters */ 871da177e4SLinus Torvalds #define DEF_NUM_HOST 1 881da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 891da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 901da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 911da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 921da177e4SLinus Torvalds */ 935b94e232SMartin K. Petersen #define DEF_ATO 1 941da177e4SLinus Torvalds #define DEF_DELAY 1 951da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 965b94e232SMartin K. Petersen #define DEF_DIF 0 975b94e232SMartin K. Petersen #define DEF_DIX 0 985b94e232SMartin K. Petersen #define DEF_D_SENSE 0 991da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1005b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1015b94e232SMartin K. Petersen #define DEF_GUARD 0 1025b94e232SMartin K. Petersen #define DEF_LBPU 0 1035b94e232SMartin K. Petersen #define DEF_LBPWS 0 1045b94e232SMartin K. Petersen #define DEF_LBPWS10 0 105be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1065b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 1075b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1081da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1091da177e4SLinus Torvalds #define DEF_OPTS 0 110e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64 1115b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 1125b94e232SMartin K. Petersen #define DEF_PTYPE 0 113d986788bSMartin Pitt #define DEF_REMOVABLE false 1145b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 1155b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1165b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1175b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1196014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1205b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1215b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1225b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1281da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1296f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR 32 131c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR 64 13218a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT 128 1331da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1341da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1351da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1361da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1376f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1386f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1391da177e4SLinus Torvalds * 1401da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1411da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1421da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1431da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1446f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1456f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1461da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1471da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1481da177e4SLinus Torvalds */ 1491da177e4SLinus Torvalds 1501da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1511da177e4SLinus Torvalds * sector on read commands: */ 1521da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 15332f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1561da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1571da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 158c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1591da177e4SLinus Torvalds 16078d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that 16178d4e5a0SDouglas Gilbert * that have a non-zero delay are queued. */ 16278d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE 255 16378d4e5a0SDouglas Gilbert 1641da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1655b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO; 1661da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1671da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1685b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF; 1695b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX; 1705b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE; 1711da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1725b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW; 17368aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD; 1745b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; 1751da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 17678d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; 177c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 1785b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0; 1795b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS; 1805b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 181e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS; 1825b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS; 1835b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; 1845b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1855b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1865b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 1875b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 1885b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 1895b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU; 1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS; 1915b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; 192be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ; 1936014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 1945b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; 1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 1965b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 1975b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; 198d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE; 1991da177e4SLinus Torvalds 2001da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 2011da177e4SLinus Torvalds 2021da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 2031da177e4SLinus Torvalds 204c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 2051da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 2081da177e4SLinus Torvalds may still need them */ 2091da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 2101da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 2111da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 2141da177e4SLinus Torvalds 2151da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 2161da177e4SLinus Torvalds 217395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32 2189e603ca0SFUJITA Tomonori 2195b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void) 2205b94e232SMartin K. Petersen { 2215b94e232SMartin K. Petersen return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10; 2225b94e232SMartin K. Petersen } 2235b94e232SMartin K. Petersen 2241da177e4SLinus Torvalds struct sdebug_dev_info { 2251da177e4SLinus Torvalds struct list_head dev_list; 2261da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 2271da177e4SLinus Torvalds unsigned int channel; 2281da177e4SLinus Torvalds unsigned int target; 2291da177e4SLinus Torvalds unsigned int lun; 2301da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 231c65b1445SDouglas Gilbert unsigned int wlun; 2321da177e4SLinus Torvalds char reset; 233c65b1445SDouglas Gilbert char stopped; 2341da177e4SLinus Torvalds char used; 2351da177e4SLinus Torvalds }; 2361da177e4SLinus Torvalds 2371da177e4SLinus Torvalds struct sdebug_host_info { 2381da177e4SLinus Torvalds struct list_head host_list; 2391da177e4SLinus Torvalds struct Scsi_Host *shost; 2401da177e4SLinus Torvalds struct device dev; 2411da177e4SLinus Torvalds struct list_head dev_info_list; 2421da177e4SLinus Torvalds }; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds #define to_sdebug_host(d) \ 2451da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 2481da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 2511da177e4SLinus Torvalds 2521da177e4SLinus Torvalds struct sdebug_queued_cmd { 2531da177e4SLinus Torvalds int in_use; 2541da177e4SLinus Torvalds struct timer_list cmnd_timer; 2551da177e4SLinus Torvalds done_funct_t done_funct; 2561da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2571da177e4SLinus Torvalds int scsi_result; 2581da177e4SLinus Torvalds }; 2591da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2601da177e4SLinus Torvalds 2611da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 262e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep; /* protection info */ 26344d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 2641da177e4SLinus Torvalds 26544d92694SMartin K. Petersen static unsigned long map_size; 2661da177e4SLinus Torvalds static int num_aborts = 0; 2671da177e4SLinus Torvalds static int num_dev_resets = 0; 2681da177e4SLinus Torvalds static int num_bus_resets = 0; 2691da177e4SLinus Torvalds static int num_host_resets = 0; 270c6a44287SMartin K. Petersen static int dix_writes; 271c6a44287SMartin K. Petersen static int dix_reads; 272c6a44287SMartin K. Petersen static int dif_errors; 2731da177e4SLinus Torvalds 2741da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2751da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2761da177e4SLinus Torvalds 2771da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2781da177e4SLinus Torvalds 2791da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2821da177e4SLinus Torvalds .name = sdebug_proc_name, 2831da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2841da177e4SLinus Torvalds }; 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds static const int check_condition_result = 2871da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2881da177e4SLinus Torvalds 289c6a44287SMartin K. Petersen static const int illegal_condition_result = 290c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 291c6a44287SMartin K. Petersen 292c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 293c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 294c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 295c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 296c65b1445SDouglas Gilbert 29714faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 29814faa944SAkinobu Mita { 29914faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 30014faa944SAkinobu Mita 30114faa944SAkinobu Mita return fake_storep + lba * scsi_debug_sector_size; 30214faa944SAkinobu Mita } 30314faa944SAkinobu Mita 30414faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector) 30514faa944SAkinobu Mita { 30614faa944SAkinobu Mita sector = do_div(sector, sdebug_store_sectors); 30714faa944SAkinobu Mita 30814faa944SAkinobu Mita return dif_storep + sector; 30914faa944SAkinobu Mita } 31014faa944SAkinobu Mita 3111da177e4SLinus Torvalds static int sdebug_add_adapter(void); 3121da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 3131da177e4SLinus Torvalds 3148dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 3158dea0d02SFUJITA Tomonori { 3168dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 3178dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 3188dea0d02SFUJITA Tomonori 3198dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 3208dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3218dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 3228dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 3238dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 3248dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 3258dea0d02SFUJITA Tomonori else 3268dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 3278dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 3288dea0d02SFUJITA Tomonori hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; 3298dea0d02SFUJITA Tomonori } 3308dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 3318dea0d02SFUJITA Tomonori } 3328dea0d02SFUJITA Tomonori 3338dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, 3348dea0d02SFUJITA Tomonori int asc, int asq) 3358dea0d02SFUJITA Tomonori { 3368dea0d02SFUJITA Tomonori unsigned char *sbuff; 3378dea0d02SFUJITA Tomonori 3388dea0d02SFUJITA Tomonori sbuff = devip->sense_buff; 3398dea0d02SFUJITA Tomonori memset(sbuff, 0, SDEBUG_SENSE_LEN); 3408dea0d02SFUJITA Tomonori 3418dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 3428dea0d02SFUJITA Tomonori 3438dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3448dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 3458dea0d02SFUJITA Tomonori "[0x%x,0x%x,0x%x]\n", key, asc, asq); 3468dea0d02SFUJITA Tomonori } 3471da177e4SLinus Torvalds 3483de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd, 349395cef03SMartin K. Petersen unsigned long long *lba, unsigned int *num, 350395cef03SMartin K. Petersen u32 *ei_lba) 3513de9f944SFUJITA Tomonori { 352395cef03SMartin K. Petersen *ei_lba = 0; 353395cef03SMartin K. Petersen 3543de9f944SFUJITA Tomonori switch (*cmd) { 355395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 356395cef03SMartin K. Petersen *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | 357395cef03SMartin K. Petersen (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | 358395cef03SMartin K. Petersen (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | 359395cef03SMartin K. Petersen (u64)cmd[13] << 48 | (u64)cmd[12] << 56; 360395cef03SMartin K. Petersen 361395cef03SMartin K. Petersen *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | 362395cef03SMartin K. Petersen (u32)cmd[21] << 16 | (u32)cmd[20] << 24; 363395cef03SMartin K. Petersen 364395cef03SMartin K. Petersen *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | 365395cef03SMartin K. Petersen (u32)cmd[28] << 24; 366395cef03SMartin K. Petersen break; 367395cef03SMartin K. Petersen 36844d92694SMartin K. Petersen case WRITE_SAME_16: 3693de9f944SFUJITA Tomonori case WRITE_16: 3703de9f944SFUJITA Tomonori case READ_16: 371d5cdc989SFUJITA Tomonori *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | 372d5cdc989SFUJITA Tomonori (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | 373d5cdc989SFUJITA Tomonori (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | 374d5cdc989SFUJITA Tomonori (u64)cmd[3] << 48 | (u64)cmd[2] << 56; 375d5cdc989SFUJITA Tomonori 376d5cdc989SFUJITA Tomonori *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | 377d5cdc989SFUJITA Tomonori (u32)cmd[10] << 24; 3783de9f944SFUJITA Tomonori break; 3793de9f944SFUJITA Tomonori case WRITE_12: 3803de9f944SFUJITA Tomonori case READ_12: 381d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 382d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 383d5cdc989SFUJITA Tomonori 384d5cdc989SFUJITA Tomonori *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | 385d5cdc989SFUJITA Tomonori (u32)cmd[6] << 24; 3863de9f944SFUJITA Tomonori break; 38744d92694SMartin K. Petersen case WRITE_SAME: 3883de9f944SFUJITA Tomonori case WRITE_10: 3893de9f944SFUJITA Tomonori case READ_10: 390c639d14eSFUJITA Tomonori case XDWRITEREAD_10: 391d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 392d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 393d5cdc989SFUJITA Tomonori 394d5cdc989SFUJITA Tomonori *num = (u32)cmd[8] | (u32)cmd[7] << 8; 3953de9f944SFUJITA Tomonori break; 3963de9f944SFUJITA Tomonori case WRITE_6: 3973de9f944SFUJITA Tomonori case READ_6: 398d5cdc989SFUJITA Tomonori *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 399d5cdc989SFUJITA Tomonori (u32)(cmd[1] & 0x1f) << 16; 4003de9f944SFUJITA Tomonori *num = (0 == cmd[4]) ? 256 : cmd[4]; 4013de9f944SFUJITA Tomonori break; 4023de9f944SFUJITA Tomonori default: 4033de9f944SFUJITA Tomonori break; 4043de9f944SFUJITA Tomonori } 4053de9f944SFUJITA Tomonori } 4061da177e4SLinus Torvalds 4071da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 4101da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds return -EINVAL; 4131da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 4141da177e4SLinus Torvalds } 4151da177e4SLinus Torvalds 416c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 417c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 4181da177e4SLinus Torvalds { 4191da177e4SLinus Torvalds if (devip->reset) { 4201da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4211da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 4221da177e4SLinus Torvalds "attention: power on reset\n"); 4231da177e4SLinus Torvalds devip->reset = 0; 4241da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 4251da177e4SLinus Torvalds return check_condition_result; 4261da177e4SLinus Torvalds } 427c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 428c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 429c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 430c65b1445SDouglas Gilbert "ready: initializing command required\n"); 431c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 432c65b1445SDouglas Gilbert 0x2); 433c65b1445SDouglas Gilbert return check_condition_result; 434c65b1445SDouglas Gilbert } 4351da177e4SLinus Torvalds return 0; 4361da177e4SLinus Torvalds } 4371da177e4SLinus Torvalds 4381da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 4391da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 4401da177e4SLinus Torvalds int arr_len) 4411da177e4SLinus Torvalds { 44221a61829SFUJITA Tomonori int act_len; 443072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 4441da177e4SLinus Torvalds 445072d0bb3SFUJITA Tomonori if (!sdb->length) 4461da177e4SLinus Torvalds return 0; 447072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 4481da177e4SLinus Torvalds return (DID_ERROR << 16); 44921a61829SFUJITA Tomonori 45021a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 45121a61829SFUJITA Tomonori arr, arr_len); 45221a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 45321a61829SFUJITA Tomonori 4541da177e4SLinus Torvalds return 0; 4551da177e4SLinus Torvalds } 4561da177e4SLinus Torvalds 4571da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 4581da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 45921a61829SFUJITA Tomonori int arr_len) 4601da177e4SLinus Torvalds { 46121a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 4621da177e4SLinus Torvalds return 0; 463072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 4641da177e4SLinus Torvalds return -1; 46521a61829SFUJITA Tomonori 46621a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 4671da177e4SLinus Torvalds } 4681da177e4SLinus Torvalds 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 4711da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 4721da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 4731da177e4SLinus Torvalds 4745a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 4755a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 4765a09e398SHannes Reinecke const char * dev_id_str, 477c65b1445SDouglas Gilbert int dev_id_str_len) 4781da177e4SLinus Torvalds { 479c65b1445SDouglas Gilbert int num, port_a; 480c65b1445SDouglas Gilbert char b[32]; 4811da177e4SLinus Torvalds 482c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 4831da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 4841da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 4851da177e4SLinus Torvalds arr[1] = 0x1; 4861da177e4SLinus Torvalds arr[2] = 0x0; 4871da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 4881da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 4891da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 4901da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 4911da177e4SLinus Torvalds arr[3] = num; 4921da177e4SLinus Torvalds num += 4; 493c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 494c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 495c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 496c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 497c65b1445SDouglas Gilbert arr[num++] = 0x0; 498c65b1445SDouglas Gilbert arr[num++] = 0x8; 499c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 500c65b1445SDouglas Gilbert arr[num++] = 0x33; 501c65b1445SDouglas Gilbert arr[num++] = 0x33; 502c65b1445SDouglas Gilbert arr[num++] = 0x30; 503c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 504c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 505c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 506c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 507c65b1445SDouglas Gilbert /* Target relative port number */ 508c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 509c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 510c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 511c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 512c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 513c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 514c65b1445SDouglas Gilbert arr[num++] = 0x0; 515c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 516c65b1445SDouglas Gilbert } 517c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 518c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 519c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 520c65b1445SDouglas Gilbert arr[num++] = 0x0; 521c65b1445SDouglas Gilbert arr[num++] = 0x8; 522c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 523c65b1445SDouglas Gilbert arr[num++] = 0x22; 524c65b1445SDouglas Gilbert arr[num++] = 0x22; 525c65b1445SDouglas Gilbert arr[num++] = 0x20; 526c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 527c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 528c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 529c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 5305a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 5315a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 5325a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 5335a09e398SHannes Reinecke arr[num++] = 0x0; 5345a09e398SHannes Reinecke arr[num++] = 0x4; 5355a09e398SHannes Reinecke arr[num++] = 0; 5365a09e398SHannes Reinecke arr[num++] = 0; 5375a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 5385a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 539c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 540c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 541c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 542c65b1445SDouglas Gilbert arr[num++] = 0x0; 543c65b1445SDouglas Gilbert arr[num++] = 0x8; 544c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 545c65b1445SDouglas Gilbert arr[num++] = 0x22; 546c65b1445SDouglas Gilbert arr[num++] = 0x22; 547c65b1445SDouglas Gilbert arr[num++] = 0x20; 548c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 549c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 550c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 551c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 552c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 553c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 554c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 555c65b1445SDouglas Gilbert arr[num++] = 0x0; 556c65b1445SDouglas Gilbert arr[num++] = 24; 557c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 558c65b1445SDouglas Gilbert num += 12; 559c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 560c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 561c65b1445SDouglas Gilbert num += 8; 562c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 563c65b1445SDouglas Gilbert num += 4; 564c65b1445SDouglas Gilbert return num; 565c65b1445SDouglas Gilbert } 566c65b1445SDouglas Gilbert 567c65b1445SDouglas Gilbert 568c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 569c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 570c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 571c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 572c65b1445SDouglas Gilbert }; 573c65b1445SDouglas Gilbert 574c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 575c65b1445SDouglas Gilbert { 576c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 577c65b1445SDouglas Gilbert return sizeof(vpd84_data); 578c65b1445SDouglas Gilbert } 579c65b1445SDouglas Gilbert 580c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 581c65b1445SDouglas Gilbert { 582c65b1445SDouglas Gilbert int num = 0; 583c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 584c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 585c65b1445SDouglas Gilbert int plen, olen; 586c65b1445SDouglas Gilbert 587c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 588c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 589c65b1445SDouglas Gilbert arr[num++] = 0x0; 590c65b1445SDouglas Gilbert olen = strlen(na1); 591c65b1445SDouglas Gilbert plen = olen + 1; 592c65b1445SDouglas Gilbert if (plen % 4) 593c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 594c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 595c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 596c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 597c65b1445SDouglas Gilbert num += plen; 598c65b1445SDouglas Gilbert 599c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 600c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 601c65b1445SDouglas Gilbert arr[num++] = 0x0; 602c65b1445SDouglas Gilbert olen = strlen(na2); 603c65b1445SDouglas Gilbert plen = olen + 1; 604c65b1445SDouglas Gilbert if (plen % 4) 605c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 606c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 607c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 608c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 609c65b1445SDouglas Gilbert num += plen; 610c65b1445SDouglas Gilbert 611c65b1445SDouglas Gilbert return num; 612c65b1445SDouglas Gilbert } 613c65b1445SDouglas Gilbert 614c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 615c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 616c65b1445SDouglas Gilbert { 617c65b1445SDouglas Gilbert int num = 0; 618c65b1445SDouglas Gilbert int port_a, port_b; 619c65b1445SDouglas Gilbert 620c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 621c65b1445SDouglas Gilbert port_b = port_a + 1; 622c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 623c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 624c65b1445SDouglas Gilbert arr[num++] = 0x0; 625c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 626c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 627c65b1445SDouglas Gilbert num += 6; 628c65b1445SDouglas Gilbert arr[num++] = 0x0; 629c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 630c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 631c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 632c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 633c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 634c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 635c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 636c65b1445SDouglas Gilbert arr[num++] = 0x22; 637c65b1445SDouglas Gilbert arr[num++] = 0x22; 638c65b1445SDouglas Gilbert arr[num++] = 0x20; 639c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 640c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 641c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 642c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 643c65b1445SDouglas Gilbert 644c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 645c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 646c65b1445SDouglas Gilbert arr[num++] = 0x0; 647c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 648c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 649c65b1445SDouglas Gilbert num += 6; 650c65b1445SDouglas Gilbert arr[num++] = 0x0; 651c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 652c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 653c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 654c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 655c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 656c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 657c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 658c65b1445SDouglas Gilbert arr[num++] = 0x22; 659c65b1445SDouglas Gilbert arr[num++] = 0x22; 660c65b1445SDouglas Gilbert arr[num++] = 0x20; 661c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 662c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 663c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 664c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 665c65b1445SDouglas Gilbert 666c65b1445SDouglas Gilbert return num; 667c65b1445SDouglas Gilbert } 668c65b1445SDouglas Gilbert 669c65b1445SDouglas Gilbert 670c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 671c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 672c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 673c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 674c65b1445SDouglas Gilbert '1','2','3','4', 675c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 676c65b1445SDouglas Gilbert 0xec,0,0,0, 677c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 678c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 679c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 680c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 681c65b1445SDouglas Gilbert 0x53,0x41, 682c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 683c65b1445SDouglas Gilbert 0x20,0x20, 684c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 685c65b1445SDouglas Gilbert 0x10,0x80, 686c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 687c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 688c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 689c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 690c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 691c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 692c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 693c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 694c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 695c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 696c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 697c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 698c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 699c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 700c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 701c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 702c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 703c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 704c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 705c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 706c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 707c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 708c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 709c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 710c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 711c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 712c65b1445SDouglas Gilbert }; 713c65b1445SDouglas Gilbert 714c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 715c65b1445SDouglas Gilbert { 716c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 717c65b1445SDouglas Gilbert return sizeof(vpd89_data); 718c65b1445SDouglas Gilbert } 719c65b1445SDouglas Gilbert 720c65b1445SDouglas Gilbert 7211e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 722c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 7231e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 7241e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7251e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7261e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 727c65b1445SDouglas Gilbert }; 728c65b1445SDouglas Gilbert 729c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 730c65b1445SDouglas Gilbert { 731ea61fca5SMartin K. Petersen unsigned int gran; 732ea61fca5SMartin K. Petersen 733c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 734e308b3d1SMartin K. Petersen 735e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 736ea61fca5SMartin K. Petersen gran = 1 << scsi_debug_physblk_exp; 737ea61fca5SMartin K. Petersen arr[2] = (gran >> 8) & 0xff; 738ea61fca5SMartin K. Petersen arr[3] = gran & 0xff; 739e308b3d1SMartin K. Petersen 740e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 741c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 742c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 743c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 744c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 745c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 746c65b1445SDouglas Gilbert } 74744d92694SMartin K. Petersen 748e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 749e308b3d1SMartin K. Petersen put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); 750e308b3d1SMartin K. Petersen 7515b94e232SMartin K. Petersen if (scsi_debug_lbpu) { 752e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 7536014759cSMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); 754e308b3d1SMartin K. Petersen 755e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 75644d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); 75744d92694SMartin K. Petersen } 75844d92694SMartin K. Petersen 759e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 76044d92694SMartin K. Petersen if (scsi_debug_unmap_alignment) { 76144d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); 76244d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 76344d92694SMartin K. Petersen } 76444d92694SMartin K. Petersen 765e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 76644d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); 7676014759cSMartin K. Petersen 7685b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 7695b94e232SMartin K. Petersen put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); 7705b94e232SMartin K. Petersen 7715b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 77244d92694SMartin K. Petersen 773c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds 7761e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 777eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 778eac6e8e4SMatthew Wilcox { 779eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 780eac6e8e4SMatthew Wilcox arr[0] = 0; 7811e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 7821e49f785SDouglas Gilbert arr[2] = 0; 7831e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 784eac6e8e4SMatthew Wilcox 785eac6e8e4SMatthew Wilcox return 0x3c; 786eac6e8e4SMatthew Wilcox } 7871da177e4SLinus Torvalds 788be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */ 7896014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 7906014759cSMartin K. Petersen { 7913f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 7926014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 7936014759cSMartin K. Petersen 7945b94e232SMartin K. Petersen if (scsi_debug_lbpu) 7956014759cSMartin K. Petersen arr[1] = 1 << 7; 7966014759cSMartin K. Petersen 7975b94e232SMartin K. Petersen if (scsi_debug_lbpws) 7986014759cSMartin K. Petersen arr[1] |= 1 << 6; 7996014759cSMartin K. Petersen 8005b94e232SMartin K. Petersen if (scsi_debug_lbpws10) 8015b94e232SMartin K. Petersen arr[1] |= 1 << 5; 8025b94e232SMartin K. Petersen 803be1dd78dSEric Sandeen if (scsi_debug_lbprz) 804be1dd78dSEric Sandeen arr[1] |= 1 << 2; 805be1dd78dSEric Sandeen 8063f0bc3b3SMartin K. Petersen return 0x4; 8076014759cSMartin K. Petersen } 8086014759cSMartin K. Petersen 8091da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 810c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 8131da177e4SLinus Torvalds struct sdebug_dev_info * devip) 8141da177e4SLinus Torvalds { 8151da177e4SLinus Torvalds unsigned char pq_pdt; 8165a09e398SHannes Reinecke unsigned char * arr; 8171da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 8185a09e398SHannes Reinecke int alloc_len, n, ret; 8191da177e4SLinus Torvalds 8201da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 8216f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 8226f3cbf55SDouglas Gilbert if (! arr) 8236f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 824c65b1445SDouglas Gilbert if (devip->wlun) 825c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 826c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 827c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 828c65b1445SDouglas Gilbert else 8291da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 8301da177e4SLinus Torvalds arr[0] = pq_pdt; 8311da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 8321da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 8331da177e4SLinus Torvalds 0); 8345a09e398SHannes Reinecke kfree(arr); 8351da177e4SLinus Torvalds return check_condition_result; 8361da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 8375a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 838c65b1445SDouglas Gilbert char lu_id_str[6]; 839c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 8401da177e4SLinus Torvalds 8415a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 8425a09e398SHannes Reinecke (devip->channel & 0x7f); 84323183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 84423183910SDouglas Gilbert host_no = 0; 845c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 846c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 847c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 848c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 849c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 8501da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 851c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 852c65b1445SDouglas Gilbert n = 4; 853c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 854c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 855c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 856c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 857c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 858c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 859c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 860c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 861c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 862c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 863eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 8645b94e232SMartin K. Petersen if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ 8655b94e232SMartin K. Petersen arr[n++] = 0xb2; 866c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 8671da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 868c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8691da177e4SLinus Torvalds arr[3] = len; 870c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 8711da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 872c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8735a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 8745a09e398SHannes Reinecke target_dev_id, lu_id_num, 8755a09e398SHannes Reinecke lu_id_str, len); 876c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 877c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 878c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 879c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 880c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 881c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 882c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 883c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 884c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 885c6a44287SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) 886c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 887c6a44287SMartin K. Petersen else if (scsi_debug_dif) 888c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 889c6a44287SMartin K. Petersen else 890c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 891c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 892c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 893c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 894c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 895c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 896c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 897c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 898c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 899c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 900c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 901c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 902c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 903c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 904c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 905c65b1445SDouglas Gilbert arr[2] = (n >> 8); 906c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 907c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 908c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 909c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 910eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 911eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 912eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 9135b94e232SMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ 9146014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 9156014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 9161da177e4SLinus Torvalds } else { 9171da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 9181da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 9191da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 9205a09e398SHannes Reinecke kfree(arr); 9211da177e4SLinus Torvalds return check_condition_result; 9221da177e4SLinus Torvalds } 923c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 9245a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 925c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 9265a09e398SHannes Reinecke kfree(arr); 9275a09e398SHannes Reinecke return ret; 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 930d986788bSMartin Pitt arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */ 9311da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 9321da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 9331da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 934c6a44287SMartin K. Petersen arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ 9355a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 9365a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 937c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 9381da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 939c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 9401da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 9411da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 9421da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 9431da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 944c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 945c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 946c65b1445SDouglas Gilbert n = 62; 9471da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 948c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 9491da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 950c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 9511da177e4SLinus Torvalds } 952c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 9535a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 9541da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 9555a09e398SHannes Reinecke kfree(arr); 9565a09e398SHannes Reinecke return ret; 9571da177e4SLinus Torvalds } 9581da177e4SLinus Torvalds 9591da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 9601da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9611da177e4SLinus Torvalds { 9621da177e4SLinus Torvalds unsigned char * sbuff; 9631da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 9641da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 965c65b1445SDouglas Gilbert int want_dsense; 9661da177e4SLinus Torvalds int len = 18; 9671da177e4SLinus Torvalds 968c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9691da177e4SLinus Torvalds if (devip->reset == 1) 970c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 971c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 9721da177e4SLinus Torvalds sbuff = devip->sense_buff; 973c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 974c65b1445SDouglas Gilbert if (want_dsense) { 975c65b1445SDouglas Gilbert arr[0] = 0x72; 976c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 977c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 978c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 979c65b1445SDouglas Gilbert } else { 980c65b1445SDouglas Gilbert arr[0] = 0x70; 981c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 982c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 983c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 984c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 985c65b1445SDouglas Gilbert } 986c65b1445SDouglas Gilbert } else { 987c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 9881da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 9891da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 990c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9911da177e4SLinus Torvalds arr[0] = 0x72; 9921da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 9931da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 9941da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 9951da177e4SLinus Torvalds len = 8; 996c65b1445SDouglas Gilbert } 997c65b1445SDouglas Gilbert } 998c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 9991da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds 1002c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1003c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1004c65b1445SDouglas Gilbert { 1005c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1006c65b1445SDouglas Gilbert int power_cond, errsts, start; 1007c65b1445SDouglas Gilbert 1008c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1009c65b1445SDouglas Gilbert return errsts; 1010c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1011c65b1445SDouglas Gilbert if (power_cond) { 1012c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1013c65b1445SDouglas Gilbert 0); 1014c65b1445SDouglas Gilbert return check_condition_result; 1015c65b1445SDouglas Gilbert } 1016c65b1445SDouglas Gilbert start = cmd[4] & 1; 1017c65b1445SDouglas Gilbert if (start == devip->stopped) 1018c65b1445SDouglas Gilbert devip->stopped = !start; 1019c65b1445SDouglas Gilbert return 0; 1020c65b1445SDouglas Gilbert } 1021c65b1445SDouglas Gilbert 102228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 102328898873SFUJITA Tomonori { 102428898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 10255447ed6cSDouglas Gilbert return (sector_t)scsi_debug_virtual_gb * 10265447ed6cSDouglas Gilbert (1073741824 / scsi_debug_sector_size); 102728898873SFUJITA Tomonori else 102828898873SFUJITA Tomonori return sdebug_store_sectors; 102928898873SFUJITA Tomonori } 103028898873SFUJITA Tomonori 10311da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 10321da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 10331da177e4SLinus Torvalds struct sdebug_dev_info * devip) 10341da177e4SLinus Torvalds { 10351da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1036c65b1445SDouglas Gilbert unsigned int capac; 10371da177e4SLinus Torvalds int errsts; 10381da177e4SLinus Torvalds 1039c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 10401da177e4SLinus Torvalds return errsts; 1041c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 104228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 10431da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1044c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1045c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 10461da177e4SLinus Torvalds arr[0] = (capac >> 24); 10471da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 10481da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 10491da177e4SLinus Torvalds arr[3] = capac & 0xff; 1050c65b1445SDouglas Gilbert } else { 1051c65b1445SDouglas Gilbert arr[0] = 0xff; 1052c65b1445SDouglas Gilbert arr[1] = 0xff; 1053c65b1445SDouglas Gilbert arr[2] = 0xff; 1054c65b1445SDouglas Gilbert arr[3] = 0xff; 1055c65b1445SDouglas Gilbert } 1056597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 1057597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 10581da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds 1061c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1062c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1063c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1064c65b1445SDouglas Gilbert { 1065c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1066c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1067c65b1445SDouglas Gilbert unsigned long long capac; 1068c65b1445SDouglas Gilbert int errsts, k, alloc_len; 1069c65b1445SDouglas Gilbert 1070c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1071c65b1445SDouglas Gilbert return errsts; 1072c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1073c65b1445SDouglas Gilbert + cmd[13]); 1074c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 107528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1076c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1077c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1078c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1079c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1080597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 1081597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 1082597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 1083597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 1084ea61fca5SMartin K. Petersen arr[13] = scsi_debug_physblk_exp & 0xf; 1085ea61fca5SMartin K. Petersen arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; 108644d92694SMartin K. Petersen 1087be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 10885b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1089be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1090be1dd78dSEric Sandeen arr[14] |= 0x40; /* LBPRZ */ 1091be1dd78dSEric Sandeen } 109244d92694SMartin K. Petersen 1093ea61fca5SMartin K. Petersen arr[15] = scsi_debug_lowest_aligned & 0xff; 1094c6a44287SMartin K. Petersen 1095c6a44287SMartin K. Petersen if (scsi_debug_dif) { 1096c6a44287SMartin K. Petersen arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ 1097c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1098c6a44287SMartin K. Petersen } 1099c6a44287SMartin K. Petersen 1100c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1101c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1102c65b1445SDouglas Gilbert } 1103c65b1445SDouglas Gilbert 11045a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 11055a09e398SHannes Reinecke 11065a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 11075a09e398SHannes Reinecke struct sdebug_dev_info * devip) 11085a09e398SHannes Reinecke { 11095a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 11105a09e398SHannes Reinecke unsigned char * arr; 11115a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 11125a09e398SHannes Reinecke int n, ret, alen, rlen; 11135a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 11145a09e398SHannes Reinecke 11155a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 11165a09e398SHannes Reinecke + cmd[9]); 11175a09e398SHannes Reinecke 11186f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 11196f3cbf55SDouglas Gilbert if (! arr) 11206f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 11215a09e398SHannes Reinecke /* 11225a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 11235a09e398SHannes Reinecke * real and a fake port with no device connected. 11245a09e398SHannes Reinecke * So we create two port groups with one port each 11255a09e398SHannes Reinecke * and set the group with port B to unavailable. 11265a09e398SHannes Reinecke */ 11275a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 11285a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 11295a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 11305a09e398SHannes Reinecke (devip->channel & 0x7f); 11315a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 11325a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 11335a09e398SHannes Reinecke 11345a09e398SHannes Reinecke /* 11355a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 11365a09e398SHannes Reinecke */ 11375a09e398SHannes Reinecke n = 4; 11385a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 11395a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 11405a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 11415a09e398SHannes Reinecke } else { 11425a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 11435a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 11445a09e398SHannes Reinecke } 11455a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 11465a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 11475a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11485a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11495a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11505a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11515a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11525a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11535a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 11545a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 11555a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 11565a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 11575a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 11585a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 11595a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11605a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11615a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11625a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11635a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11645a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11655a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 11665a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 11675a09e398SHannes Reinecke 11685a09e398SHannes Reinecke rlen = n - 4; 11695a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 11705a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 11715a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 11725a09e398SHannes Reinecke arr[3] = rlen & 0xff; 11735a09e398SHannes Reinecke 11745a09e398SHannes Reinecke /* 11755a09e398SHannes Reinecke * Return the smallest value of either 11765a09e398SHannes Reinecke * - The allocated length 11775a09e398SHannes Reinecke * - The constructed command length 11785a09e398SHannes Reinecke * - The maximum array size 11795a09e398SHannes Reinecke */ 11805a09e398SHannes Reinecke rlen = min(alen,n); 11815a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 11825a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 11835a09e398SHannes Reinecke kfree(arr); 11845a09e398SHannes Reinecke return ret; 11855a09e398SHannes Reinecke } 11865a09e398SHannes Reinecke 11871da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 11881da177e4SLinus Torvalds 11891da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 11901da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 11911da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 11921da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 11951da177e4SLinus Torvalds if (1 == pcontrol) 11961da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 11971da177e4SLinus Torvalds return sizeof(err_recov_pg); 11981da177e4SLinus Torvalds } 11991da177e4SLinus Torvalds 12001da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 12011da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 12021da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 12031da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 12061da177e4SLinus Torvalds if (1 == pcontrol) 12071da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 12081da177e4SLinus Torvalds return sizeof(disconnect_pg); 12091da177e4SLinus Torvalds } 12101da177e4SLinus Torvalds 12111da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 12121da177e4SLinus Torvalds { /* Format device page for mode_sense */ 12131da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 12141da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 12151da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 12181da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 12191da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1220597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1221597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 1222d986788bSMartin Pitt if (scsi_debug_removable) 12231da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 12241da177e4SLinus Torvalds if (1 == pcontrol) 12251da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 12261da177e4SLinus Torvalds return sizeof(format_pg); 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 12301da177e4SLinus Torvalds { /* Caching page for mode_sense */ 12311da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 12321da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 12331da177e4SLinus Torvalds 12341da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 12351da177e4SLinus Torvalds if (1 == pcontrol) 12361da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 12371da177e4SLinus Torvalds return sizeof(caching_pg); 12381da177e4SLinus Torvalds } 12391da177e4SLinus Torvalds 12401da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 12411da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1242c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1243c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1244c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 12451da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 12461da177e4SLinus Torvalds 12471da177e4SLinus Torvalds if (scsi_debug_dsense) 12481da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1249c65b1445SDouglas Gilbert else 1250c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1251c6a44287SMartin K. Petersen 1252c6a44287SMartin K. Petersen if (scsi_debug_ato) 1253c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1254c6a44287SMartin K. Petersen 12551da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 12561da177e4SLinus Torvalds if (1 == pcontrol) 1257c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1258c65b1445SDouglas Gilbert else if (2 == pcontrol) 1259c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 12601da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 12611da177e4SLinus Torvalds } 12621da177e4SLinus Torvalds 1263c65b1445SDouglas Gilbert 12641da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 12651da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1266c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 12671da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1268c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1269c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1270c65b1445SDouglas Gilbert 12711da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 12721da177e4SLinus Torvalds if (1 == pcontrol) 1273c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1274c65b1445SDouglas Gilbert else if (2 == pcontrol) 1275c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 12761da177e4SLinus Torvalds return sizeof(iec_m_pg); 12771da177e4SLinus Torvalds } 12781da177e4SLinus Torvalds 1279c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1280c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1281c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1282c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1283c65b1445SDouglas Gilbert 1284c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1285c65b1445SDouglas Gilbert if (1 == pcontrol) 1286c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1287c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1288c65b1445SDouglas Gilbert } 1289c65b1445SDouglas Gilbert 1290c65b1445SDouglas Gilbert 1291c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1292c65b1445SDouglas Gilbert int target_dev_id) 1293c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1294c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1295c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1296c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1297c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1298c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1299c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1300c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1301c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1302c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1303c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1304c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1305c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1306c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1307c65b1445SDouglas Gilbert }; 1308c65b1445SDouglas Gilbert int port_a, port_b; 1309c65b1445SDouglas Gilbert 1310c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1311c65b1445SDouglas Gilbert port_b = port_a + 1; 1312c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1313c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1314c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1315c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1316c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1317c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1318c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1319c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1320c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1321c65b1445SDouglas Gilbert if (1 == pcontrol) 1322c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1323c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1324c65b1445SDouglas Gilbert } 1325c65b1445SDouglas Gilbert 1326c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1327c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1328c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1329c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1330c65b1445SDouglas Gilbert }; 1331c65b1445SDouglas Gilbert 1332c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1333c65b1445SDouglas Gilbert if (1 == pcontrol) 1334c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1335c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1336c65b1445SDouglas Gilbert } 1337c65b1445SDouglas Gilbert 13381da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 13391da177e4SLinus Torvalds 13401da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 13411da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13421da177e4SLinus Torvalds { 134323183910SDouglas Gilbert unsigned char dbd, llbaa; 134423183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 13451da177e4SLinus Torvalds unsigned char dev_spec; 134623183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 13471da177e4SLinus Torvalds unsigned char * ap; 13481da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 13491da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 13501da177e4SLinus Torvalds 1351c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 13521da177e4SLinus Torvalds return errsts; 135323183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 13541da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 13551da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 13561da177e4SLinus Torvalds subpcode = cmd[3]; 13571da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 135823183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 135923183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 136023183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 136123183910SDouglas Gilbert else 136223183910SDouglas Gilbert bd_len = 0; 13631da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 13641da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 13651da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 13661da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 13671da177e4SLinus Torvalds 0); 13681da177e4SLinus Torvalds return check_condition_result; 13691da177e4SLinus Torvalds } 1370c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1371c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 137223183910SDouglas Gilbert /* set DPOFUA bit for disks */ 137323183910SDouglas Gilbert if (0 == scsi_debug_ptype) 137423183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 137523183910SDouglas Gilbert else 137623183910SDouglas Gilbert dev_spec = 0x0; 13771da177e4SLinus Torvalds if (msense_6) { 13781da177e4SLinus Torvalds arr[2] = dev_spec; 137923183910SDouglas Gilbert arr[3] = bd_len; 13801da177e4SLinus Torvalds offset = 4; 13811da177e4SLinus Torvalds } else { 13821da177e4SLinus Torvalds arr[3] = dev_spec; 138323183910SDouglas Gilbert if (16 == bd_len) 138423183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 138523183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 13861da177e4SLinus Torvalds offset = 8; 13871da177e4SLinus Torvalds } 13881da177e4SLinus Torvalds ap = arr + offset; 138928898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 139028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 139128898873SFUJITA Tomonori 139223183910SDouglas Gilbert if (8 == bd_len) { 139323183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 139423183910SDouglas Gilbert ap[0] = 0xff; 139523183910SDouglas Gilbert ap[1] = 0xff; 139623183910SDouglas Gilbert ap[2] = 0xff; 139723183910SDouglas Gilbert ap[3] = 0xff; 139823183910SDouglas Gilbert } else { 139923183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 140023183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 140123183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 140223183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 140323183910SDouglas Gilbert } 1404597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 1405597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 140623183910SDouglas Gilbert offset += bd_len; 140723183910SDouglas Gilbert ap = arr + offset; 140823183910SDouglas Gilbert } else if (16 == bd_len) { 140923183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 141023183910SDouglas Gilbert 141123183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 141223183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 1413597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 1414597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 1415597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 1416597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 141723183910SDouglas Gilbert offset += bd_len; 141823183910SDouglas Gilbert ap = arr + offset; 141923183910SDouglas Gilbert } 14201da177e4SLinus Torvalds 1421c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1422c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 14231da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14241da177e4SLinus Torvalds 0); 14251da177e4SLinus Torvalds return check_condition_result; 14261da177e4SLinus Torvalds } 14271da177e4SLinus Torvalds switch (pcode) { 14281da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 14291da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14301da177e4SLinus Torvalds offset += len; 14311da177e4SLinus Torvalds break; 14321da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 14331da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 14341da177e4SLinus Torvalds offset += len; 14351da177e4SLinus Torvalds break; 14361da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 14371da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 14381da177e4SLinus Torvalds offset += len; 14391da177e4SLinus Torvalds break; 14401da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 14411da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 14421da177e4SLinus Torvalds offset += len; 14431da177e4SLinus Torvalds break; 14441da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 14451da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 14461da177e4SLinus Torvalds offset += len; 14471da177e4SLinus Torvalds break; 1448c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1449c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1450c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1451c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1452c65b1445SDouglas Gilbert return check_condition_result; 1453c65b1445SDouglas Gilbert } 1454c65b1445SDouglas Gilbert len = 0; 1455c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1456c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1457c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1458c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1459c65b1445SDouglas Gilbert target_dev_id); 1460c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1461c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1462c65b1445SDouglas Gilbert offset += len; 1463c65b1445SDouglas Gilbert break; 14641da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 14651da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 14661da177e4SLinus Torvalds offset += len; 14671da177e4SLinus Torvalds break; 14681da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1469c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 14701da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14711da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 14721da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 14731da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 14741da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1475c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1476c65b1445SDouglas Gilbert if (0xff == subpcode) { 1477c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1478c65b1445SDouglas Gilbert target, target_dev_id); 1479c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1480c65b1445SDouglas Gilbert } 14811da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1482c65b1445SDouglas Gilbert } else { 1483c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1484c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1485c65b1445SDouglas Gilbert return check_condition_result; 1486c65b1445SDouglas Gilbert } 14871da177e4SLinus Torvalds offset += len; 14881da177e4SLinus Torvalds break; 14891da177e4SLinus Torvalds default: 14901da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14911da177e4SLinus Torvalds 0); 14921da177e4SLinus Torvalds return check_condition_result; 14931da177e4SLinus Torvalds } 14941da177e4SLinus Torvalds if (msense_6) 14951da177e4SLinus Torvalds arr[0] = offset - 1; 14961da177e4SLinus Torvalds else { 14971da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 14981da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 14991da177e4SLinus Torvalds } 15001da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 15011da177e4SLinus Torvalds } 15021da177e4SLinus Torvalds 1503c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1504c65b1445SDouglas Gilbert 1505c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1506c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1507c65b1445SDouglas Gilbert { 1508c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1509c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1510c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1511c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1512c65b1445SDouglas Gilbert 1513c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1514c65b1445SDouglas Gilbert return errsts; 1515c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1516c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1517c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1518c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1519c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1520c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1521c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1522c65b1445SDouglas Gilbert return check_condition_result; 1523c65b1445SDouglas Gilbert } 1524c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1525c65b1445SDouglas Gilbert if (-1 == res) 1526c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1527c65b1445SDouglas Gilbert else if ((res < param_len) && 1528c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1529c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1530c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1531c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1532c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 153323183910SDouglas Gilbert if (md_len > 2) { 1534c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1535c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1536c65b1445SDouglas Gilbert return check_condition_result; 1537c65b1445SDouglas Gilbert } 1538c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1539c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1540c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1541c65b1445SDouglas Gilbert if (ps) { 1542c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1543c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1544c65b1445SDouglas Gilbert return check_condition_result; 1545c65b1445SDouglas Gilbert } 1546c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1547c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1548c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1549c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1550c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1551c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1552c65b1445SDouglas Gilbert return check_condition_result; 1553c65b1445SDouglas Gilbert } 1554c65b1445SDouglas Gilbert switch (mpage) { 1555c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1556c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1557c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1558c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1559c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1560c65b1445SDouglas Gilbert return 0; 1561c65b1445SDouglas Gilbert } 1562c65b1445SDouglas Gilbert break; 1563c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1564c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1565c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1566c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1567c65b1445SDouglas Gilbert return 0; 1568c65b1445SDouglas Gilbert } 1569c65b1445SDouglas Gilbert break; 1570c65b1445SDouglas Gilbert default: 1571c65b1445SDouglas Gilbert break; 1572c65b1445SDouglas Gilbert } 1573c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1574c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1575c65b1445SDouglas Gilbert return check_condition_result; 1576c65b1445SDouglas Gilbert } 1577c65b1445SDouglas Gilbert 1578c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1579c65b1445SDouglas Gilbert { 1580c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1581c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1582c65b1445SDouglas Gilbert }; 1583c65b1445SDouglas Gilbert 1584c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1585c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1586c65b1445SDouglas Gilbert } 1587c65b1445SDouglas Gilbert 1588c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1589c65b1445SDouglas Gilbert { 1590c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1591c65b1445SDouglas Gilbert }; 1592c65b1445SDouglas Gilbert 1593c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1594c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1595c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1596c65b1445SDouglas Gilbert arr[5] = 0xff; 1597c65b1445SDouglas Gilbert } 1598c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1599c65b1445SDouglas Gilbert } 1600c65b1445SDouglas Gilbert 1601c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1602c65b1445SDouglas Gilbert 1603c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1604c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1605c65b1445SDouglas Gilbert { 160623183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1607c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1608c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1609c65b1445SDouglas Gilbert 1610c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1611c65b1445SDouglas Gilbert return errsts; 1612c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1613c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1614c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1615c65b1445SDouglas Gilbert if (ppc || sp) { 1616c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1617c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1618c65b1445SDouglas Gilbert return check_condition_result; 1619c65b1445SDouglas Gilbert } 1620c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1621c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 162223183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1623c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1624c65b1445SDouglas Gilbert arr[0] = pcode; 162523183910SDouglas Gilbert if (0 == subpcode) { 1626c65b1445SDouglas Gilbert switch (pcode) { 1627c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1628c65b1445SDouglas Gilbert n = 4; 1629c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1630c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1631c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1632c65b1445SDouglas Gilbert arr[3] = n - 4; 1633c65b1445SDouglas Gilbert break; 1634c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1635c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1636c65b1445SDouglas Gilbert break; 1637c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1638c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1639c65b1445SDouglas Gilbert break; 1640c65b1445SDouglas Gilbert default: 1641c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1642c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1643c65b1445SDouglas Gilbert return check_condition_result; 1644c65b1445SDouglas Gilbert } 164523183910SDouglas Gilbert } else if (0xff == subpcode) { 164623183910SDouglas Gilbert arr[0] |= 0x40; 164723183910SDouglas Gilbert arr[1] = subpcode; 164823183910SDouglas Gilbert switch (pcode) { 164923183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 165023183910SDouglas Gilbert n = 4; 165123183910SDouglas Gilbert arr[n++] = 0x0; 165223183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 165323183910SDouglas Gilbert arr[n++] = 0x0; 165423183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 165523183910SDouglas Gilbert arr[n++] = 0xd; 165623183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 165723183910SDouglas Gilbert arr[n++] = 0x2f; 165823183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 165923183910SDouglas Gilbert arr[3] = n - 4; 166023183910SDouglas Gilbert break; 166123183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 166223183910SDouglas Gilbert n = 4; 166323183910SDouglas Gilbert arr[n++] = 0xd; 166423183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 166523183910SDouglas Gilbert arr[3] = n - 4; 166623183910SDouglas Gilbert break; 166723183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 166823183910SDouglas Gilbert n = 4; 166923183910SDouglas Gilbert arr[n++] = 0x2f; 167023183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 167123183910SDouglas Gilbert arr[3] = n - 4; 167223183910SDouglas Gilbert break; 167323183910SDouglas Gilbert default: 167423183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 167523183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 167623183910SDouglas Gilbert return check_condition_result; 167723183910SDouglas Gilbert } 167823183910SDouglas Gilbert } else { 167923183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 168023183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 168123183910SDouglas Gilbert return check_condition_result; 168223183910SDouglas Gilbert } 1683c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1684c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1685c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1686c65b1445SDouglas Gilbert } 1687c65b1445SDouglas Gilbert 168819789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi, 168919789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 16901da177e4SLinus Torvalds { 1691c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 169219789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); 16931da177e4SLinus Torvalds return check_condition_result; 16941da177e4SLinus Torvalds } 1695c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1696c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 169719789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 1698c65b1445SDouglas Gilbert return check_condition_result; 1699c65b1445SDouglas Gilbert } 170019789100SFUJITA Tomonori return 0; 170119789100SFUJITA Tomonori } 170219789100SFUJITA Tomonori 1703a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 170419789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd, 170519789100SFUJITA Tomonori struct sdebug_dev_info *devi, 170619789100SFUJITA Tomonori unsigned long long lba, unsigned int num, int write) 170719789100SFUJITA Tomonori { 170819789100SFUJITA Tomonori int ret; 1709a361cc00SDarrick J. Wong unsigned long long block, rest = 0; 1710a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 1711a4517511SAkinobu Mita enum dma_data_direction dir; 1712a4517511SAkinobu Mita size_t (*func)(struct scatterlist *, unsigned int, void *, size_t, 1713a4517511SAkinobu Mita off_t); 171419789100SFUJITA Tomonori 1715a4517511SAkinobu Mita if (write) { 1716a4517511SAkinobu Mita sdb = scsi_out(scmd); 1717a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 1718a4517511SAkinobu Mita func = sg_pcopy_to_buffer; 1719a4517511SAkinobu Mita } else { 1720a4517511SAkinobu Mita sdb = scsi_in(scmd); 1721a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 1722a4517511SAkinobu Mita func = sg_pcopy_from_buffer; 1723a4517511SAkinobu Mita } 1724a4517511SAkinobu Mita 1725a4517511SAkinobu Mita if (!sdb->length) 1726a4517511SAkinobu Mita return 0; 1727a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 1728a4517511SAkinobu Mita return -1; 172919789100SFUJITA Tomonori 173019789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 173119789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 173219789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 173319789100SFUJITA Tomonori 1734a4517511SAkinobu Mita ret = func(sdb->table.sgl, sdb->table.nents, 1735a4517511SAkinobu Mita fake_storep + (block * scsi_debug_sector_size), 1736a4517511SAkinobu Mita (num - rest) * scsi_debug_sector_size, 0); 1737a4517511SAkinobu Mita if (ret != (num - rest) * scsi_debug_sector_size) 1738a4517511SAkinobu Mita return ret; 1739a4517511SAkinobu Mita 1740a4517511SAkinobu Mita if (rest) { 1741a4517511SAkinobu Mita ret += func(sdb->table.sgl, sdb->table.nents, 1742a4517511SAkinobu Mita fake_storep, rest * scsi_debug_sector_size, 1743597136abSMartin K. Petersen (num - rest) * scsi_debug_sector_size); 1744a4517511SAkinobu Mita } 174519789100SFUJITA Tomonori 174619789100SFUJITA Tomonori return ret; 174719789100SFUJITA Tomonori } 174819789100SFUJITA Tomonori 174951d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 1750beb40ea4SAkinobu Mita { 175151d648afSAkinobu Mita __be16 csum; 1752beb40ea4SAkinobu Mita 175351d648afSAkinobu Mita if (scsi_debug_guard) 175451d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 175551d648afSAkinobu Mita else 1756beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 175751d648afSAkinobu Mita 1758beb40ea4SAkinobu Mita return csum; 1759beb40ea4SAkinobu Mita } 1760beb40ea4SAkinobu Mita 1761beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 1762beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 1763beb40ea4SAkinobu Mita { 176451d648afSAkinobu Mita __be16 csum = dif_compute_csum(data, scsi_debug_sector_size); 1765beb40ea4SAkinobu Mita 1766beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 1767beb40ea4SAkinobu Mita pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 1768beb40ea4SAkinobu Mita __func__, 1769beb40ea4SAkinobu Mita (unsigned long)sector, 1770beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 1771beb40ea4SAkinobu Mita be16_to_cpu(csum)); 1772beb40ea4SAkinobu Mita return 0x01; 1773beb40ea4SAkinobu Mita } 1774beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1775beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 1776beb40ea4SAkinobu Mita pr_err("%s: REF check failed on sector %lu\n", 1777beb40ea4SAkinobu Mita __func__, (unsigned long)sector); 1778beb40ea4SAkinobu Mita return 0x03; 1779beb40ea4SAkinobu Mita } 1780beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1781beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 1782beb40ea4SAkinobu Mita pr_err("%s: REF check failed on sector %lu\n", 1783beb40ea4SAkinobu Mita __func__, (unsigned long)sector); 1784beb40ea4SAkinobu Mita return 0x03; 1785beb40ea4SAkinobu Mita } 1786beb40ea4SAkinobu Mita return 0; 1787beb40ea4SAkinobu Mita } 1788beb40ea4SAkinobu Mita 1789bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 179065f72f2aSAkinobu Mita unsigned int sectors, bool read) 1791c6a44287SMartin K. Petersen { 1792be4e11beSAkinobu Mita size_t resid; 1793c6a44287SMartin K. Petersen void *paddr; 179414faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 1795be4e11beSAkinobu Mita struct sg_mapping_iter miter; 1796c6a44287SMartin K. Petersen 1797e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 1798e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 1799c6a44287SMartin K. Petersen 1800be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 1801be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 1802be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 1803be4e11beSAkinobu Mita 1804be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 1805be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 180614faa944SAkinobu Mita void *start = dif_store(sector); 1807be4e11beSAkinobu Mita size_t rest = 0; 180814faa944SAkinobu Mita 180914faa944SAkinobu Mita if (dif_store_end < start + len) 181014faa944SAkinobu Mita rest = start + len - dif_store_end; 1811c6a44287SMartin K. Petersen 1812be4e11beSAkinobu Mita paddr = miter.addr; 181314faa944SAkinobu Mita 181465f72f2aSAkinobu Mita if (read) 181565f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 181665f72f2aSAkinobu Mita else 181765f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 181865f72f2aSAkinobu Mita 181965f72f2aSAkinobu Mita if (rest) { 182065f72f2aSAkinobu Mita if (read) 182114faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 182265f72f2aSAkinobu Mita else 182365f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 182465f72f2aSAkinobu Mita } 1825c6a44287SMartin K. Petersen 1826e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 1827c6a44287SMartin K. Petersen resid -= len; 1828c6a44287SMartin K. Petersen } 1829be4e11beSAkinobu Mita sg_miter_stop(&miter); 1830bb8c063cSAkinobu Mita } 1831c6a44287SMartin K. Petersen 1832bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 1833bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 1834bb8c063cSAkinobu Mita { 1835bb8c063cSAkinobu Mita unsigned int i; 1836bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 1837bb8c063cSAkinobu Mita sector_t sector; 1838bb8c063cSAkinobu Mita 1839c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 1840bb8c063cSAkinobu Mita int ret; 1841bb8c063cSAkinobu Mita 1842bb8c063cSAkinobu Mita sector = start_sec + i; 1843bb8c063cSAkinobu Mita sdt = dif_store(sector); 1844bb8c063cSAkinobu Mita 184551d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 1846bb8c063cSAkinobu Mita continue; 1847bb8c063cSAkinobu Mita 1848bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 1849bb8c063cSAkinobu Mita if (ret) { 1850bb8c063cSAkinobu Mita dif_errors++; 1851bb8c063cSAkinobu Mita return ret; 1852bb8c063cSAkinobu Mita } 1853bb8c063cSAkinobu Mita } 1854bb8c063cSAkinobu Mita 185565f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 1856c6a44287SMartin K. Petersen dix_reads++; 1857c6a44287SMartin K. Petersen 1858c6a44287SMartin K. Petersen return 0; 1859c6a44287SMartin K. Petersen } 1860c6a44287SMartin K. Petersen 186119789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 1862395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 1863395cef03SMartin K. Petersen u32 ei_lba) 186419789100SFUJITA Tomonori { 186519789100SFUJITA Tomonori unsigned long iflags; 186619789100SFUJITA Tomonori int ret; 186719789100SFUJITA Tomonori 186819789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 186919789100SFUJITA Tomonori if (ret) 187019789100SFUJITA Tomonori return ret; 187119789100SFUJITA Tomonori 18721da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 187332f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 1874c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1875c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 187632f7ef73SDouglas Gilbert mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 1877c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1878c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1879c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 188032f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 188132f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 1882c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1883c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1884c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1885c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1886c65b1445SDouglas Gilbert } 1887a87e3a67SDouglas Gilbert scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 18881da177e4SLinus Torvalds return check_condition_result; 18891da177e4SLinus Torvalds } 1890c6a44287SMartin K. Petersen 1891c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 1892c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 1893395cef03SMartin K. Petersen int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); 1894c6a44287SMartin K. Petersen 1895c6a44287SMartin K. Petersen if (prot_ret) { 1896c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); 1897c6a44287SMartin K. Petersen return illegal_condition_result; 1898c6a44287SMartin K. Petersen } 1899c6a44287SMartin K. Petersen } 1900c6a44287SMartin K. Petersen 19011da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 190219789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 0); 19031da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 1904a4517511SAkinobu Mita if (ret == -1) 1905a4517511SAkinobu Mita return DID_ERROR << 16; 1906a4517511SAkinobu Mita 1907a4517511SAkinobu Mita scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret; 1908a4517511SAkinobu Mita 1909a4517511SAkinobu Mita return 0; 19101da177e4SLinus Torvalds } 19111da177e4SLinus Torvalds 1912c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len) 1913c6a44287SMartin K. Petersen { 1914c6a44287SMartin K. Petersen int i, j; 1915c6a44287SMartin K. Petersen 1916c6a44287SMartin K. Petersen printk(KERN_ERR ">>> Sector Dump <<<\n"); 1917c6a44287SMartin K. Petersen 1918c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 1919c6a44287SMartin K. Petersen printk(KERN_ERR "%04d: ", i); 1920c6a44287SMartin K. Petersen 1921c6a44287SMartin K. Petersen for (j = 0 ; j < 16 ; j++) { 1922c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 1923c6a44287SMartin K. Petersen if (c >= 0x20 && c < 0x7e) 1924c6a44287SMartin K. Petersen printk(" %c ", buf[i+j]); 1925c6a44287SMartin K. Petersen else 1926c6a44287SMartin K. Petersen printk("%02x ", buf[i+j]); 1927c6a44287SMartin K. Petersen } 1928c6a44287SMartin K. Petersen 1929c6a44287SMartin K. Petersen printk("\n"); 1930c6a44287SMartin K. Petersen } 1931c6a44287SMartin K. Petersen } 1932c6a44287SMartin K. Petersen 1933c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 1934395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 1935c6a44287SMartin K. Petersen { 1936be4e11beSAkinobu Mita int ret; 1937c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 1938be4e11beSAkinobu Mita void *daddr; 193965f72f2aSAkinobu Mita sector_t sector = start_sec; 1940c6a44287SMartin K. Petersen int ppage_offset; 1941be4e11beSAkinobu Mita int dpage_offset; 1942be4e11beSAkinobu Mita struct sg_mapping_iter diter; 1943be4e11beSAkinobu Mita struct sg_mapping_iter piter; 1944c6a44287SMartin K. Petersen 1945c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 1946c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 1947c6a44287SMartin K. Petersen 1948be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 1949be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 1950be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 1951be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 1952be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 1953c6a44287SMartin K. Petersen 1954be4e11beSAkinobu Mita /* For each protection page */ 1955be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 1956be4e11beSAkinobu Mita dpage_offset = 0; 1957be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 1958be4e11beSAkinobu Mita ret = 0x01; 1959be4e11beSAkinobu Mita goto out; 1960c6a44287SMartin K. Petersen } 1961c6a44287SMartin K. Petersen 1962be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 1963be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 1964be4e11beSAkinobu Mita /* If we're at the end of the current 1965be4e11beSAkinobu Mita * data page advance to the next one 1966be4e11beSAkinobu Mita */ 1967be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 1968be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 1969be4e11beSAkinobu Mita ret = 0x01; 1970be4e11beSAkinobu Mita goto out; 1971be4e11beSAkinobu Mita } 1972be4e11beSAkinobu Mita dpage_offset = 0; 1973be4e11beSAkinobu Mita } 1974c6a44287SMartin K. Petersen 1975be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 1976be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 1977be4e11beSAkinobu Mita 1978be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 1979beb40ea4SAkinobu Mita if (ret) { 1980be4e11beSAkinobu Mita dump_sector(daddr, scsi_debug_sector_size); 1981395cef03SMartin K. Petersen goto out; 1982395cef03SMartin K. Petersen } 1983395cef03SMartin K. Petersen 1984c6a44287SMartin K. Petersen sector++; 1985395cef03SMartin K. Petersen ei_lba++; 1986be4e11beSAkinobu Mita dpage_offset += scsi_debug_sector_size; 1987c6a44287SMartin K. Petersen } 1988be4e11beSAkinobu Mita diter.consumed = dpage_offset; 1989be4e11beSAkinobu Mita sg_miter_stop(&diter); 1990c6a44287SMartin K. Petersen } 1991be4e11beSAkinobu Mita sg_miter_stop(&piter); 1992c6a44287SMartin K. Petersen 199365f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 1994c6a44287SMartin K. Petersen dix_writes++; 1995c6a44287SMartin K. Petersen 1996c6a44287SMartin K. Petersen return 0; 1997c6a44287SMartin K. Petersen 1998c6a44287SMartin K. Petersen out: 1999c6a44287SMartin K. Petersen dif_errors++; 2000be4e11beSAkinobu Mita sg_miter_stop(&diter); 2001be4e11beSAkinobu Mita sg_miter_stop(&piter); 2002c6a44287SMartin K. Petersen return ret; 2003c6a44287SMartin K. Petersen } 2004c6a44287SMartin K. Petersen 2005b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2006b90ebc3dSAkinobu Mita { 2007b90ebc3dSAkinobu Mita if (scsi_debug_unmap_alignment) { 2008b90ebc3dSAkinobu Mita lba += scsi_debug_unmap_granularity - 2009b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2010b90ebc3dSAkinobu Mita } 2011b90ebc3dSAkinobu Mita do_div(lba, scsi_debug_unmap_granularity); 2012b90ebc3dSAkinobu Mita 2013b90ebc3dSAkinobu Mita return lba; 2014b90ebc3dSAkinobu Mita } 2015b90ebc3dSAkinobu Mita 2016b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2017b90ebc3dSAkinobu Mita { 2018a027b5b9SAkinobu Mita sector_t lba = index * scsi_debug_unmap_granularity; 2019a027b5b9SAkinobu Mita 2020a027b5b9SAkinobu Mita if (scsi_debug_unmap_alignment) { 2021a027b5b9SAkinobu Mita lba -= scsi_debug_unmap_granularity - 2022b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2023b90ebc3dSAkinobu Mita } 2024b90ebc3dSAkinobu Mita 2025a027b5b9SAkinobu Mita return lba; 2026a027b5b9SAkinobu Mita } 2027a027b5b9SAkinobu Mita 202844d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 202944d92694SMartin K. Petersen { 2030b90ebc3dSAkinobu Mita sector_t end; 2031b90ebc3dSAkinobu Mita unsigned int mapped; 2032b90ebc3dSAkinobu Mita unsigned long index; 2033b90ebc3dSAkinobu Mita unsigned long next; 203444d92694SMartin K. Petersen 2035b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2036b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 203744d92694SMartin K. Petersen 203844d92694SMartin K. Petersen if (mapped) 2039b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 204044d92694SMartin K. Petersen else 2041b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 204244d92694SMartin K. Petersen 2043b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 204444d92694SMartin K. Petersen *num = end - lba; 204544d92694SMartin K. Petersen 204644d92694SMartin K. Petersen return mapped; 204744d92694SMartin K. Petersen } 204844d92694SMartin K. Petersen 204944d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 205044d92694SMartin K. Petersen { 205144d92694SMartin K. Petersen sector_t end = lba + len; 205244d92694SMartin K. Petersen 205344d92694SMartin K. Petersen while (lba < end) { 2054b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 205544d92694SMartin K. Petersen 2056b90ebc3dSAkinobu Mita if (index < map_size) 2057b90ebc3dSAkinobu Mita set_bit(index, map_storep); 205844d92694SMartin K. Petersen 2059b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 206044d92694SMartin K. Petersen } 206144d92694SMartin K. Petersen } 206244d92694SMartin K. Petersen 206344d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 206444d92694SMartin K. Petersen { 206544d92694SMartin K. Petersen sector_t end = lba + len; 206644d92694SMartin K. Petersen 206744d92694SMartin K. Petersen while (lba < end) { 2068b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 206944d92694SMartin K. Petersen 2070b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2071b90ebc3dSAkinobu Mita lba + scsi_debug_unmap_granularity <= end && 2072b90ebc3dSAkinobu Mita index < map_size) { 2073b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2074b90ebc3dSAkinobu Mita if (scsi_debug_lbprz) { 2075be1dd78dSEric Sandeen memset(fake_storep + 2076cc34a8e6SAkinobu Mita lba * scsi_debug_sector_size, 0, 2077cc34a8e6SAkinobu Mita scsi_debug_sector_size * 2078cc34a8e6SAkinobu Mita scsi_debug_unmap_granularity); 2079be1dd78dSEric Sandeen } 2080e9926b43SAkinobu Mita if (dif_storep) { 2081e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2082e9926b43SAkinobu Mita sizeof(*dif_storep) * 2083e9926b43SAkinobu Mita scsi_debug_unmap_granularity); 2084e9926b43SAkinobu Mita } 2085b90ebc3dSAkinobu Mita } 2086b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 208744d92694SMartin K. Petersen } 208844d92694SMartin K. Petersen } 208944d92694SMartin K. Petersen 2090c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 2091395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 2092395cef03SMartin K. Petersen u32 ei_lba) 20931da177e4SLinus Torvalds { 20941da177e4SLinus Torvalds unsigned long iflags; 209519789100SFUJITA Tomonori int ret; 20961da177e4SLinus Torvalds 209719789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 209819789100SFUJITA Tomonori if (ret) 209919789100SFUJITA Tomonori return ret; 21001da177e4SLinus Torvalds 2101c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2102c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 2103395cef03SMartin K. Petersen int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); 2104c6a44287SMartin K. Petersen 2105c6a44287SMartin K. Petersen if (prot_ret) { 2106c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); 2107c6a44287SMartin K. Petersen return illegal_condition_result; 2108c6a44287SMartin K. Petersen } 2109c6a44287SMartin K. Petersen } 2110c6a44287SMartin K. Petersen 21111da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 211219789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 1); 21139ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 211444d92694SMartin K. Petersen map_region(lba, num); 21151da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 211619789100SFUJITA Tomonori if (-1 == ret) 21171da177e4SLinus Torvalds return (DID_ERROR << 16); 2118597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 21191da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2120c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 2121597136abSMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 212244d92694SMartin K. Petersen 21231da177e4SLinus Torvalds return 0; 21241da177e4SLinus Torvalds } 21251da177e4SLinus Torvalds 212644d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba, 212744d92694SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 212844d92694SMartin K. Petersen u32 ei_lba, unsigned int unmap) 212944d92694SMartin K. Petersen { 213044d92694SMartin K. Petersen unsigned long iflags; 213144d92694SMartin K. Petersen unsigned long long i; 213244d92694SMartin K. Petersen int ret; 213344d92694SMartin K. Petersen 213444d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 213544d92694SMartin K. Petersen if (ret) 213644d92694SMartin K. Petersen return ret; 213744d92694SMartin K. Petersen 21385b94e232SMartin K. Petersen if (num > scsi_debug_write_same_length) { 21395b94e232SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 21405b94e232SMartin K. Petersen 0); 21415b94e232SMartin K. Petersen return check_condition_result; 21425b94e232SMartin K. Petersen } 21435b94e232SMartin K. Petersen 214444d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 214544d92694SMartin K. Petersen 21469ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 214744d92694SMartin K. Petersen unmap_region(lba, num); 214844d92694SMartin K. Petersen goto out; 214944d92694SMartin K. Petersen } 215044d92694SMartin K. Petersen 215144d92694SMartin K. Petersen /* Else fetch one logical block */ 215244d92694SMartin K. Petersen ret = fetch_to_dev_buffer(scmd, 215344d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 215444d92694SMartin K. Petersen scsi_debug_sector_size); 215544d92694SMartin K. Petersen 215644d92694SMartin K. Petersen if (-1 == ret) { 215744d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 215844d92694SMartin K. Petersen return (DID_ERROR << 16); 215944d92694SMartin K. Petersen } else if ((ret < (num * scsi_debug_sector_size)) && 216044d92694SMartin K. Petersen (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 216144d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, " 216244d92694SMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 216344d92694SMartin K. Petersen 216444d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 216544d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 216644d92694SMartin K. Petersen memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), 216744d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 216844d92694SMartin K. Petersen scsi_debug_sector_size); 216944d92694SMartin K. Petersen 21709ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 217144d92694SMartin K. Petersen map_region(lba, num); 217244d92694SMartin K. Petersen out: 217344d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 217444d92694SMartin K. Petersen 217544d92694SMartin K. Petersen return 0; 217644d92694SMartin K. Petersen } 217744d92694SMartin K. Petersen 217844d92694SMartin K. Petersen struct unmap_block_desc { 217944d92694SMartin K. Petersen __be64 lba; 218044d92694SMartin K. Petersen __be32 blocks; 218144d92694SMartin K. Petersen __be32 __reserved; 218244d92694SMartin K. Petersen }; 218344d92694SMartin K. Petersen 218444d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip) 218544d92694SMartin K. Petersen { 218644d92694SMartin K. Petersen unsigned char *buf; 218744d92694SMartin K. Petersen struct unmap_block_desc *desc; 218844d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 218944d92694SMartin K. Petersen int ret; 219044d92694SMartin K. Petersen 219144d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 219244d92694SMartin K. Petersen if (ret) 219344d92694SMartin K. Petersen return ret; 219444d92694SMartin K. Petersen 219544d92694SMartin K. Petersen payload_len = get_unaligned_be16(&scmd->cmnd[7]); 219644d92694SMartin K. Petersen BUG_ON(scsi_bufflen(scmd) != payload_len); 219744d92694SMartin K. Petersen 219844d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 219944d92694SMartin K. Petersen 220044d92694SMartin K. Petersen buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC); 220144d92694SMartin K. Petersen if (!buf) 220244d92694SMartin K. Petersen return check_condition_result; 220344d92694SMartin K. Petersen 220444d92694SMartin K. Petersen scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); 220544d92694SMartin K. Petersen 220644d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 220744d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 220844d92694SMartin K. Petersen 220944d92694SMartin K. Petersen desc = (void *)&buf[8]; 221044d92694SMartin K. Petersen 221144d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 221244d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 221344d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 221444d92694SMartin K. Petersen 221544d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 221644d92694SMartin K. Petersen if (ret) 221744d92694SMartin K. Petersen goto out; 221844d92694SMartin K. Petersen 221944d92694SMartin K. Petersen unmap_region(lba, num); 222044d92694SMartin K. Petersen } 222144d92694SMartin K. Petersen 222244d92694SMartin K. Petersen ret = 0; 222344d92694SMartin K. Petersen 222444d92694SMartin K. Petersen out: 222544d92694SMartin K. Petersen kfree(buf); 222644d92694SMartin K. Petersen 222744d92694SMartin K. Petersen return ret; 222844d92694SMartin K. Petersen } 222944d92694SMartin K. Petersen 223044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 223144d92694SMartin K. Petersen 223244d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd, 223344d92694SMartin K. Petersen struct sdebug_dev_info * devip) 223444d92694SMartin K. Petersen { 223544d92694SMartin K. Petersen unsigned long long lba; 223644d92694SMartin K. Petersen unsigned int alloc_len, mapped, num; 223744d92694SMartin K. Petersen unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN]; 223844d92694SMartin K. Petersen int ret; 223944d92694SMartin K. Petersen 224044d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 224144d92694SMartin K. Petersen if (ret) 224244d92694SMartin K. Petersen return ret; 224344d92694SMartin K. Petersen 224444d92694SMartin K. Petersen lba = get_unaligned_be64(&scmd->cmnd[2]); 224544d92694SMartin K. Petersen alloc_len = get_unaligned_be32(&scmd->cmnd[10]); 224644d92694SMartin K. Petersen 224744d92694SMartin K. Petersen if (alloc_len < 24) 224844d92694SMartin K. Petersen return 0; 224944d92694SMartin K. Petersen 225044d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, 1); 225144d92694SMartin K. Petersen if (ret) 225244d92694SMartin K. Petersen return ret; 225344d92694SMartin K. Petersen 225444d92694SMartin K. Petersen mapped = map_state(lba, &num); 225544d92694SMartin K. Petersen 225644d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 2257de13e965SDouglas Gilbert put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */ 225844d92694SMartin K. Petersen put_unaligned_be64(lba, &arr[8]); /* LBA */ 225944d92694SMartin K. Petersen put_unaligned_be32(num, &arr[16]); /* Number of blocks */ 226044d92694SMartin K. Petersen arr[20] = !mapped; /* mapped = 0, unmapped = 1 */ 226144d92694SMartin K. Petersen 226244d92694SMartin K. Petersen return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN); 226344d92694SMartin K. Petersen } 226444d92694SMartin K. Petersen 2265c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 22661da177e4SLinus Torvalds 22671da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 22681da177e4SLinus Torvalds struct sdebug_dev_info * devip) 22691da177e4SLinus Torvalds { 22701da177e4SLinus Torvalds unsigned int alloc_len; 2271c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 22721da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 22731da177e4SLinus Torvalds int select_report = (int)cmd[2]; 22741da177e4SLinus Torvalds struct scsi_lun *one_lun; 22751da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 2276c65b1445SDouglas Gilbert unsigned char * max_addr; 22771da177e4SLinus Torvalds 22781da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 2279c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 22801da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 22811da177e4SLinus Torvalds 0); 22821da177e4SLinus Torvalds return check_condition_result; 22831da177e4SLinus Torvalds } 22841da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 22851da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 22861da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 2287c65b1445SDouglas Gilbert if (1 == select_report) 2288c65b1445SDouglas Gilbert lun_cnt = 0; 2289c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 2290c65b1445SDouglas Gilbert --lun_cnt; 2291c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 2292c65b1445SDouglas Gilbert num = lun_cnt + wlun; 2293c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 2294c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 2295c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 2296c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 2297c65b1445SDouglas Gilbert if (n < num) { 2298c65b1445SDouglas Gilbert wlun = 0; 2299c65b1445SDouglas Gilbert lun_cnt = n; 2300c65b1445SDouglas Gilbert } 23011da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 2302c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 2303c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 2304c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 2305c65b1445SDouglas Gilbert i++, lun++) { 2306c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 23071da177e4SLinus Torvalds if (upper) 23081da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 23091da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 2310c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 23111da177e4SLinus Torvalds } 2312c65b1445SDouglas Gilbert if (wlun) { 2313c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 2314c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 2315c65b1445SDouglas Gilbert i++; 2316c65b1445SDouglas Gilbert } 2317c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 23181da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 23191da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 23201da177e4SLinus Torvalds } 23211da177e4SLinus Torvalds 2322c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 2323c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 2324c639d14eSFUJITA Tomonori { 2325be4e11beSAkinobu Mita int j; 2326c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 2327c639d14eSFUJITA Tomonori unsigned int offset; 2328c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 2329be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2330c639d14eSFUJITA Tomonori 2331c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 2332c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 2333c5af0db9SAkinobu Mita if (!buf) { 2334c5af0db9SAkinobu Mita mk_sense_buffer(devip, NOT_READY, 2335c5af0db9SAkinobu Mita LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); 2336c5af0db9SAkinobu Mita return check_condition_result; 2337c5af0db9SAkinobu Mita } 2338c639d14eSFUJITA Tomonori 233921a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 2340c639d14eSFUJITA Tomonori 2341c639d14eSFUJITA Tomonori offset = 0; 2342be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 2343be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 2344c639d14eSFUJITA Tomonori 2345be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 2346be4e11beSAkinobu Mita kaddr = miter.addr; 2347be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 2348be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 2349c639d14eSFUJITA Tomonori 2350be4e11beSAkinobu Mita offset += miter.length; 2351c639d14eSFUJITA Tomonori } 2352be4e11beSAkinobu Mita sg_miter_stop(&miter); 2353c639d14eSFUJITA Tomonori kfree(buf); 2354c639d14eSFUJITA Tomonori 2355be4e11beSAkinobu Mita return 0; 2356c639d14eSFUJITA Tomonori } 2357c639d14eSFUJITA Tomonori 23581da177e4SLinus Torvalds /* When timer goes off this function is called. */ 23591da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 23601da177e4SLinus Torvalds { 23611da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 23621da177e4SLinus Torvalds unsigned long iflags; 23631da177e4SLinus Torvalds 236478d4e5a0SDouglas Gilbert if (indx >= scsi_debug_max_queue) { 23651da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 23661da177e4SLinus Torvalds "large\n"); 23671da177e4SLinus Torvalds return; 23681da177e4SLinus Torvalds } 23691da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 23701da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 23711da177e4SLinus Torvalds if (! sqcp->in_use) { 23721da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 23731da177e4SLinus Torvalds "interrupt\n"); 23741da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23751da177e4SLinus Torvalds return; 23761da177e4SLinus Torvalds } 23771da177e4SLinus Torvalds sqcp->in_use = 0; 23781da177e4SLinus Torvalds if (sqcp->done_funct) { 23791da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 23801da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 23811da177e4SLinus Torvalds } 23821da177e4SLinus Torvalds sqcp->done_funct = NULL; 23831da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23841da177e4SLinus Torvalds } 23851da177e4SLinus Torvalds 23861da177e4SLinus Torvalds 23878dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 23888dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 23895cb2fc06SFUJITA Tomonori { 23905cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 23915cb2fc06SFUJITA Tomonori 23925cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 23935cb2fc06SFUJITA Tomonori if (devip) { 23945cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 23955cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 23965cb2fc06SFUJITA Tomonori } 23975cb2fc06SFUJITA Tomonori return devip; 23985cb2fc06SFUJITA Tomonori } 23995cb2fc06SFUJITA Tomonori 24001da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 24011da177e4SLinus Torvalds { 24021da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 24031da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 24041da177e4SLinus Torvalds struct sdebug_dev_info * devip = 24051da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 24061da177e4SLinus Torvalds 24071da177e4SLinus Torvalds if (devip) 24081da177e4SLinus Torvalds return devip; 2409d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 24101da177e4SLinus Torvalds if (!sdbg_host) { 24111da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 24121da177e4SLinus Torvalds return NULL; 24131da177e4SLinus Torvalds } 24141da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 24151da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 24161da177e4SLinus Torvalds (devip->target == sdev->id) && 24171da177e4SLinus Torvalds (devip->lun == sdev->lun)) 24181da177e4SLinus Torvalds return devip; 24191da177e4SLinus Torvalds else { 24201da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 24211da177e4SLinus Torvalds open_devip = devip; 24221da177e4SLinus Torvalds } 24231da177e4SLinus Torvalds } 24245cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 24255cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 24265cb2fc06SFUJITA Tomonori if (!open_devip) { 24271da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 2428cadbd4a5SHarvey Harrison __func__, __LINE__); 24291da177e4SLinus Torvalds return NULL; 24301da177e4SLinus Torvalds } 24311da177e4SLinus Torvalds } 2432a75869d1SFUJITA Tomonori 24331da177e4SLinus Torvalds open_devip->channel = sdev->channel; 24341da177e4SLinus Torvalds open_devip->target = sdev->id; 24351da177e4SLinus Torvalds open_devip->lun = sdev->lun; 24361da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 24371da177e4SLinus Torvalds open_devip->reset = 1; 24381da177e4SLinus Torvalds open_devip->used = 1; 24391da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 24401da177e4SLinus Torvalds if (scsi_debug_dsense) 24411da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 24421da177e4SLinus Torvalds else { 24431da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 24441da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 24451da177e4SLinus Torvalds } 2446c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 2447c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 2448a75869d1SFUJITA Tomonori 24491da177e4SLinus Torvalds return open_devip; 24501da177e4SLinus Torvalds } 24511da177e4SLinus Torvalds 24528dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 24531da177e4SLinus Torvalds { 24548dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24558dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 24568dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 245775ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 24588dea0d02SFUJITA Tomonori return 0; 24598dea0d02SFUJITA Tomonori } 24601da177e4SLinus Torvalds 24618dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 24628dea0d02SFUJITA Tomonori { 24638dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 2464a34c4e98SFUJITA Tomonori 24651da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24668dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 24678dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24688dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 24698dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 24708dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 24718dea0d02SFUJITA Tomonori if (NULL == devip) 24728dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 24738dea0d02SFUJITA Tomonori sdp->hostdata = devip; 24748dea0d02SFUJITA Tomonori if (sdp->host->cmd_per_lun) 24758dea0d02SFUJITA Tomonori scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 24768dea0d02SFUJITA Tomonori sdp->host->cmd_per_lun); 24778dea0d02SFUJITA Tomonori blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 247878d4e5a0SDouglas Gilbert if (scsi_debug_no_uld) 247978d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 24808dea0d02SFUJITA Tomonori return 0; 24818dea0d02SFUJITA Tomonori } 24828dea0d02SFUJITA Tomonori 24838dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 24848dea0d02SFUJITA Tomonori { 24858dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 24868dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 24878dea0d02SFUJITA Tomonori 24888dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24898dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 24908dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24918dea0d02SFUJITA Tomonori if (devip) { 249225985edcSLucas De Marchi /* make this slot available for re-use */ 24938dea0d02SFUJITA Tomonori devip->used = 0; 24948dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 24958dea0d02SFUJITA Tomonori } 24968dea0d02SFUJITA Tomonori } 24978dea0d02SFUJITA Tomonori 24988dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 24998dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 25008dea0d02SFUJITA Tomonori { 25018dea0d02SFUJITA Tomonori unsigned long iflags; 25028dea0d02SFUJITA Tomonori int k; 25038dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 25048dea0d02SFUJITA Tomonori 25058dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 250678d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 25078dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 25088dea0d02SFUJITA Tomonori if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 25098dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 25108dea0d02SFUJITA Tomonori sqcp->in_use = 0; 25118dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 25128dea0d02SFUJITA Tomonori break; 25138dea0d02SFUJITA Tomonori } 25148dea0d02SFUJITA Tomonori } 25158dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 251678d4e5a0SDouglas Gilbert return (k < scsi_debug_max_queue) ? 1 : 0; 25178dea0d02SFUJITA Tomonori } 25188dea0d02SFUJITA Tomonori 25198dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */ 25208dea0d02SFUJITA Tomonori static void stop_all_queued(void) 25218dea0d02SFUJITA Tomonori { 25228dea0d02SFUJITA Tomonori unsigned long iflags; 25238dea0d02SFUJITA Tomonori int k; 25248dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 25258dea0d02SFUJITA Tomonori 25268dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 252778d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 25288dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 25298dea0d02SFUJITA Tomonori if (sqcp->in_use && sqcp->a_cmnd) { 25308dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 25318dea0d02SFUJITA Tomonori sqcp->in_use = 0; 25328dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 25338dea0d02SFUJITA Tomonori } 25348dea0d02SFUJITA Tomonori } 25358dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 25361da177e4SLinus Torvalds } 25371da177e4SLinus Torvalds 25381da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 25391da177e4SLinus Torvalds { 25401da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25411da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 25421da177e4SLinus Torvalds ++num_aborts; 25431da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 25441da177e4SLinus Torvalds return SUCCESS; 25451da177e4SLinus Torvalds } 25461da177e4SLinus Torvalds 25471da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 25481da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 25491da177e4SLinus Torvalds { 25501da177e4SLinus Torvalds int res; 25511da177e4SLinus Torvalds unsigned char *buf; 25521da177e4SLinus Torvalds 25531da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25541da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 25551da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 25561da177e4SLinus Torvalds if (buf) { 25571da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 25581da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 25591da177e4SLinus Torvalds kfree(buf); 25601da177e4SLinus Torvalds if (! res) 25611da177e4SLinus Torvalds return res; 25621da177e4SLinus Torvalds } 25631da177e4SLinus Torvalds info[0] = sdebug_heads; 25641da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 25651da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 25661da177e4SLinus Torvalds return 0; 25671da177e4SLinus Torvalds } 25681da177e4SLinus Torvalds 25691da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 25701da177e4SLinus Torvalds { 25711da177e4SLinus Torvalds struct sdebug_dev_info * devip; 25721da177e4SLinus Torvalds 25731da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25741da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 25751da177e4SLinus Torvalds ++num_dev_resets; 25761da177e4SLinus Torvalds if (SCpnt) { 25771da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 25781da177e4SLinus Torvalds if (devip) 25791da177e4SLinus Torvalds devip->reset = 1; 25801da177e4SLinus Torvalds } 25811da177e4SLinus Torvalds return SUCCESS; 25821da177e4SLinus Torvalds } 25831da177e4SLinus Torvalds 25841da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 25851da177e4SLinus Torvalds { 25861da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 25871da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 25881da177e4SLinus Torvalds struct scsi_device * sdp; 25891da177e4SLinus Torvalds struct Scsi_Host * hp; 25901da177e4SLinus Torvalds 25911da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25921da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 25931da177e4SLinus Torvalds ++num_bus_resets; 25941da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 2595d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 25961da177e4SLinus Torvalds if (sdbg_host) { 25971da177e4SLinus Torvalds list_for_each_entry(dev_info, 25981da177e4SLinus Torvalds &sdbg_host->dev_info_list, 25991da177e4SLinus Torvalds dev_list) 26001da177e4SLinus Torvalds dev_info->reset = 1; 26011da177e4SLinus Torvalds } 26021da177e4SLinus Torvalds } 26031da177e4SLinus Torvalds return SUCCESS; 26041da177e4SLinus Torvalds } 26051da177e4SLinus Torvalds 26061da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 26071da177e4SLinus Torvalds { 26081da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 26091da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 26101da177e4SLinus Torvalds 26111da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 26121da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 26131da177e4SLinus Torvalds ++num_host_resets; 26141da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 26151da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 26161da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 26171da177e4SLinus Torvalds dev_list) 26181da177e4SLinus Torvalds dev_info->reset = 1; 26191da177e4SLinus Torvalds } 26201da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 26211da177e4SLinus Torvalds stop_all_queued(); 26221da177e4SLinus Torvalds return SUCCESS; 26231da177e4SLinus Torvalds } 26241da177e4SLinus Torvalds 26251da177e4SLinus Torvalds /* Initializes timers in queued array */ 26261da177e4SLinus Torvalds static void __init init_all_queued(void) 26271da177e4SLinus Torvalds { 26281da177e4SLinus Torvalds unsigned long iflags; 26291da177e4SLinus Torvalds int k; 26301da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 26311da177e4SLinus Torvalds 26321da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 263378d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 26341da177e4SLinus Torvalds sqcp = &queued_arr[k]; 26351da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 26361da177e4SLinus Torvalds sqcp->in_use = 0; 26371da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 26381da177e4SLinus Torvalds } 26391da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 26401da177e4SLinus Torvalds } 26411da177e4SLinus Torvalds 2642f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 26435f2578e5SFUJITA Tomonori unsigned long store_size) 26441da177e4SLinus Torvalds { 26451da177e4SLinus Torvalds struct partition * pp; 26461da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 26471da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 26481da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 26491da177e4SLinus Torvalds 26501da177e4SLinus Torvalds /* assume partition table already zeroed */ 2651f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 26521da177e4SLinus Torvalds return; 26531da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 26541da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 26551da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 26561da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 26571da177e4SLinus Torvalds } 2658c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 26591da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 26601da177e4SLinus Torvalds / scsi_debug_num_parts; 26611da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 26621da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 26631da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 26641da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 26651da177e4SLinus Torvalds * heads_by_sects; 26661da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 26671da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 26681da177e4SLinus Torvalds 26691da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 26701da177e4SLinus Torvalds ramp[511] = 0xAA; 26711da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 26721da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 26731da177e4SLinus Torvalds start_sec = starts[k]; 26741da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 26751da177e4SLinus Torvalds pp->boot_ind = 0; 26761da177e4SLinus Torvalds 26771da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 26781da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 26791da177e4SLinus Torvalds / sdebug_sectors_per; 26801da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 26811da177e4SLinus Torvalds 26821da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 26831da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 26841da177e4SLinus Torvalds / sdebug_sectors_per; 26851da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 26861da177e4SLinus Torvalds 2687150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 2688150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 26891da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 26901da177e4SLinus Torvalds } 26911da177e4SLinus Torvalds } 26921da177e4SLinus Torvalds 26931da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 26941da177e4SLinus Torvalds struct sdebug_dev_info * devip, 26951da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 26961da177e4SLinus Torvalds { 26971da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 26981da177e4SLinus Torvalds if (scsi_result) { 26991da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 27001da177e4SLinus Torvalds 2701c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2702c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2703c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 27041da177e4SLinus Torvalds } 27051da177e4SLinus Torvalds } 27061da177e4SLinus Torvalds if (cmnd && devip) { 27071da177e4SLinus Torvalds /* simulate autosense by this driver */ 27081da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 27091da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 27101da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 27111da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 27121da177e4SLinus Torvalds } 27131da177e4SLinus Torvalds if (delta_jiff <= 0) { 27141da177e4SLinus Torvalds if (cmnd) 27151da177e4SLinus Torvalds cmnd->result = scsi_result; 27161da177e4SLinus Torvalds if (done) 27171da177e4SLinus Torvalds done(cmnd); 27181da177e4SLinus Torvalds return 0; 27191da177e4SLinus Torvalds } else { 27201da177e4SLinus Torvalds unsigned long iflags; 27211da177e4SLinus Torvalds int k; 27221da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 27231da177e4SLinus Torvalds 27241da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 272578d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 27261da177e4SLinus Torvalds sqcp = &queued_arr[k]; 27271da177e4SLinus Torvalds if (! sqcp->in_use) 27281da177e4SLinus Torvalds break; 27291da177e4SLinus Torvalds } 273078d4e5a0SDouglas Gilbert if (k >= scsi_debug_max_queue) { 27311da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 27321da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 27331da177e4SLinus Torvalds return 1; /* report busy to mid level */ 27341da177e4SLinus Torvalds } 27351da177e4SLinus Torvalds sqcp->in_use = 1; 27361da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 27371da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 27381da177e4SLinus Torvalds sqcp->done_funct = done; 27391da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 27401da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 27411da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 27421da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 27431da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 27441da177e4SLinus Torvalds if (cmnd) 27451da177e4SLinus Torvalds cmnd->result = 0; 27461da177e4SLinus Torvalds return 0; 27471da177e4SLinus Torvalds } 27481da177e4SLinus Torvalds } 274923183910SDouglas Gilbert /* Note: The following macros create attribute files in the 275023183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 275123183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 275223183910SDouglas Gilbert as it can when the corresponding attribute in the 275323183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 275423183910SDouglas Gilbert */ 2755c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 27565b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO); 2757c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2758c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 27595b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO); 27605b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO); 2761c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2762c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 276323183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 276468aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO); 27655b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); 27665b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); 27675b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); 2768be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); 27695b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); 2770c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 277178d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); 2772c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 277378d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); 2774c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2775c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 27765b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); 2777c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 27785b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); 2779c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2780d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR); 2781c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 27825b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 27835b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); 27845b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); 27855b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); 27865b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); 2787c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 278823183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 278923183910SDouglas Gilbert S_IRUGO | S_IWUSR); 27905b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int, 27915b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 27921da177e4SLinus Torvalds 27931da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 27941da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 27951da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 27961da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 27995b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 28001da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2801c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 28025b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 28035b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 2804c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2805beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 280623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 28075b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 28085b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 28095b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 28105b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 2811be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); 28125b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 2813c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 281478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))"); 2815c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 281678d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 28171da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2818c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 28195b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); 28206f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 28215b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 28221da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 2823d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 28241da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2825ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 28265b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 28275b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 28286014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 28296014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 28305b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 28315b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 28325b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 28331da177e4SLinus Torvalds 28341da177e4SLinus Torvalds static char sdebug_info[256]; 28351da177e4SLinus Torvalds 28361da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 28371da177e4SLinus Torvalds { 28381da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 28391da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 28401da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 28411da177e4SLinus Torvalds scsi_debug_opts); 28421da177e4SLinus Torvalds return sdebug_info; 28431da177e4SLinus Torvalds } 28441da177e4SLinus Torvalds 28451da177e4SLinus Torvalds /* scsi_debug_proc_info 28461da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 28471da177e4SLinus Torvalds */ 2848c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length) 28491da177e4SLinus Torvalds { 28501da177e4SLinus Torvalds char arr[16]; 2851c8ed555aSAl Viro int opts; 28521da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 28531da177e4SLinus Torvalds 28541da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 28551da177e4SLinus Torvalds return -EACCES; 28561da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 28571da177e4SLinus Torvalds arr[minLen] = '\0'; 2858c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 28591da177e4SLinus Torvalds return -EINVAL; 2860c8ed555aSAl Viro scsi_debug_opts = opts; 28611da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 28621da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 28631da177e4SLinus Torvalds return length; 28641da177e4SLinus Torvalds } 2865c8ed555aSAl Viro 2866c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 2867c8ed555aSAl Viro { 2868c8ed555aSAl Viro seq_printf(m, "scsi_debug adapter driver, version " 28691da177e4SLinus Torvalds "%s [%s]\n" 28701da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 28711da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 28721da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 28731da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 28741da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 2875c6a44287SMartin K. Petersen "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", 28761da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 28771da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 28781da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 28791da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 2880597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 2881597136abSMartin K. Petersen sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, 2882c6a44287SMartin K. Petersen num_host_resets, dix_reads, dix_writes, dif_errors); 2883c8ed555aSAl Viro return 0; 28841da177e4SLinus Torvalds } 28851da177e4SLinus Torvalds 288682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 28871da177e4SLinus Torvalds { 28881da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 28891da177e4SLinus Torvalds } 28901da177e4SLinus Torvalds 289182069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 289282069379SAkinobu Mita size_t count) 28931da177e4SLinus Torvalds { 28941da177e4SLinus Torvalds int delay; 28951da177e4SLinus Torvalds char work[20]; 28961da177e4SLinus Torvalds 28971da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 28981da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 28991da177e4SLinus Torvalds scsi_debug_delay = delay; 29001da177e4SLinus Torvalds return count; 29011da177e4SLinus Torvalds } 29021da177e4SLinus Torvalds } 29031da177e4SLinus Torvalds return -EINVAL; 29041da177e4SLinus Torvalds } 290582069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 29061da177e4SLinus Torvalds 290782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 29081da177e4SLinus Torvalds { 29091da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 29101da177e4SLinus Torvalds } 29111da177e4SLinus Torvalds 291282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 291382069379SAkinobu Mita size_t count) 29141da177e4SLinus Torvalds { 29151da177e4SLinus Torvalds int opts; 29161da177e4SLinus Torvalds char work[20]; 29171da177e4SLinus Torvalds 29181da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 29191da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 29201da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 29211da177e4SLinus Torvalds goto opts_done; 29221da177e4SLinus Torvalds } else { 29231da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 29241da177e4SLinus Torvalds goto opts_done; 29251da177e4SLinus Torvalds } 29261da177e4SLinus Torvalds } 29271da177e4SLinus Torvalds return -EINVAL; 29281da177e4SLinus Torvalds opts_done: 29291da177e4SLinus Torvalds scsi_debug_opts = opts; 29301da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 29311da177e4SLinus Torvalds return count; 29321da177e4SLinus Torvalds } 293382069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 29341da177e4SLinus Torvalds 293582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 29361da177e4SLinus Torvalds { 29371da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 29381da177e4SLinus Torvalds } 293982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 294082069379SAkinobu Mita size_t count) 29411da177e4SLinus Torvalds { 29421da177e4SLinus Torvalds int n; 29431da177e4SLinus Torvalds 29441da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29451da177e4SLinus Torvalds scsi_debug_ptype = n; 29461da177e4SLinus Torvalds return count; 29471da177e4SLinus Torvalds } 29481da177e4SLinus Torvalds return -EINVAL; 29491da177e4SLinus Torvalds } 295082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 29511da177e4SLinus Torvalds 295282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 29531da177e4SLinus Torvalds { 29541da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 29551da177e4SLinus Torvalds } 295682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 295782069379SAkinobu Mita size_t count) 29581da177e4SLinus Torvalds { 29591da177e4SLinus Torvalds int n; 29601da177e4SLinus Torvalds 29611da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29621da177e4SLinus Torvalds scsi_debug_dsense = n; 29631da177e4SLinus Torvalds return count; 29641da177e4SLinus Torvalds } 29651da177e4SLinus Torvalds return -EINVAL; 29661da177e4SLinus Torvalds } 296782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 29681da177e4SLinus Torvalds 296982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 297023183910SDouglas Gilbert { 297123183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 297223183910SDouglas Gilbert } 297382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 297482069379SAkinobu Mita size_t count) 297523183910SDouglas Gilbert { 297623183910SDouglas Gilbert int n; 297723183910SDouglas Gilbert 297823183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 297923183910SDouglas Gilbert scsi_debug_fake_rw = n; 298023183910SDouglas Gilbert return count; 298123183910SDouglas Gilbert } 298223183910SDouglas Gilbert return -EINVAL; 298323183910SDouglas Gilbert } 298482069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 298523183910SDouglas Gilbert 298682069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 2987c65b1445SDouglas Gilbert { 2988c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2989c65b1445SDouglas Gilbert } 299082069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 299182069379SAkinobu Mita size_t count) 2992c65b1445SDouglas Gilbert { 2993c65b1445SDouglas Gilbert int n; 2994c65b1445SDouglas Gilbert 2995c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2996c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2997c65b1445SDouglas Gilbert return count; 2998c65b1445SDouglas Gilbert } 2999c65b1445SDouglas Gilbert return -EINVAL; 3000c65b1445SDouglas Gilbert } 300182069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 3002c65b1445SDouglas Gilbert 300382069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 30041da177e4SLinus Torvalds { 30051da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 30061da177e4SLinus Torvalds } 300782069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 300882069379SAkinobu Mita 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_num_tgts = n; 30141da177e4SLinus Torvalds sdebug_max_tgts_luns(); 30151da177e4SLinus Torvalds return count; 30161da177e4SLinus Torvalds } 30171da177e4SLinus Torvalds return -EINVAL; 30181da177e4SLinus Torvalds } 301982069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 30201da177e4SLinus Torvalds 302182069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 30221da177e4SLinus Torvalds { 30231da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 30241da177e4SLinus Torvalds } 302582069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 30261da177e4SLinus Torvalds 302782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 30281da177e4SLinus Torvalds { 30291da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 30301da177e4SLinus Torvalds } 303182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 30321da177e4SLinus Torvalds 303382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 30341da177e4SLinus Torvalds { 30351da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 30361da177e4SLinus Torvalds } 303782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 303882069379SAkinobu Mita size_t count) 30391da177e4SLinus Torvalds { 30401da177e4SLinus Torvalds int nth; 30411da177e4SLinus Torvalds 30421da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 30431da177e4SLinus Torvalds scsi_debug_every_nth = nth; 30441da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 30451da177e4SLinus Torvalds return count; 30461da177e4SLinus Torvalds } 30471da177e4SLinus Torvalds return -EINVAL; 30481da177e4SLinus Torvalds } 304982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 30501da177e4SLinus Torvalds 305182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 30521da177e4SLinus Torvalds { 30531da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 30541da177e4SLinus Torvalds } 305582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 305682069379SAkinobu Mita size_t count) 30571da177e4SLinus Torvalds { 30581da177e4SLinus Torvalds int n; 30591da177e4SLinus Torvalds 30601da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 30611da177e4SLinus Torvalds scsi_debug_max_luns = n; 30621da177e4SLinus Torvalds sdebug_max_tgts_luns(); 30631da177e4SLinus Torvalds return count; 30641da177e4SLinus Torvalds } 30651da177e4SLinus Torvalds return -EINVAL; 30661da177e4SLinus Torvalds } 306782069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 30681da177e4SLinus Torvalds 306982069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 307078d4e5a0SDouglas Gilbert { 307178d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); 307278d4e5a0SDouglas Gilbert } 307382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 307482069379SAkinobu Mita size_t count) 307578d4e5a0SDouglas Gilbert { 307678d4e5a0SDouglas Gilbert int n; 307778d4e5a0SDouglas Gilbert 307878d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 307978d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 308078d4e5a0SDouglas Gilbert scsi_debug_max_queue = n; 308178d4e5a0SDouglas Gilbert return count; 308278d4e5a0SDouglas Gilbert } 308378d4e5a0SDouglas Gilbert return -EINVAL; 308478d4e5a0SDouglas Gilbert } 308582069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 308678d4e5a0SDouglas Gilbert 308782069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 308878d4e5a0SDouglas Gilbert { 308978d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); 309078d4e5a0SDouglas Gilbert } 309182069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 309278d4e5a0SDouglas Gilbert 309382069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 30941da177e4SLinus Torvalds { 30951da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 30961da177e4SLinus Torvalds } 309782069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 30981da177e4SLinus Torvalds 309982069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 3100c65b1445SDouglas Gilbert { 3101c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 3102c65b1445SDouglas Gilbert } 310382069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 310482069379SAkinobu Mita size_t count) 3105c65b1445SDouglas Gilbert { 3106c65b1445SDouglas Gilbert int n; 3107c65b1445SDouglas Gilbert 3108c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 3109c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 311028898873SFUJITA Tomonori 311128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 311228898873SFUJITA Tomonori 3113c65b1445SDouglas Gilbert return count; 3114c65b1445SDouglas Gilbert } 3115c65b1445SDouglas Gilbert return -EINVAL; 3116c65b1445SDouglas Gilbert } 311782069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 3118c65b1445SDouglas Gilbert 311982069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 31201da177e4SLinus Torvalds { 31211da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 31221da177e4SLinus Torvalds } 31231da177e4SLinus Torvalds 312482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 312582069379SAkinobu Mita size_t count) 31261da177e4SLinus Torvalds { 31271da177e4SLinus Torvalds int delta_hosts; 31281da177e4SLinus Torvalds 3129f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 31301da177e4SLinus Torvalds return -EINVAL; 31311da177e4SLinus Torvalds if (delta_hosts > 0) { 31321da177e4SLinus Torvalds do { 31331da177e4SLinus Torvalds sdebug_add_adapter(); 31341da177e4SLinus Torvalds } while (--delta_hosts); 31351da177e4SLinus Torvalds } else if (delta_hosts < 0) { 31361da177e4SLinus Torvalds do { 31371da177e4SLinus Torvalds sdebug_remove_adapter(); 31381da177e4SLinus Torvalds } while (++delta_hosts); 31391da177e4SLinus Torvalds } 31401da177e4SLinus Torvalds return count; 31411da177e4SLinus Torvalds } 314282069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 31431da177e4SLinus Torvalds 314482069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 314523183910SDouglas Gilbert { 314623183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 314723183910SDouglas Gilbert } 314882069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 314982069379SAkinobu Mita size_t count) 315023183910SDouglas Gilbert { 315123183910SDouglas Gilbert int n; 315223183910SDouglas Gilbert 315323183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 315423183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 315523183910SDouglas Gilbert return count; 315623183910SDouglas Gilbert } 315723183910SDouglas Gilbert return -EINVAL; 315823183910SDouglas Gilbert } 315982069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 316023183910SDouglas Gilbert 316182069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 3162597136abSMartin K. Petersen { 3163597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 3164597136abSMartin K. Petersen } 316582069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 3166597136abSMartin K. Petersen 316782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 3168c6a44287SMartin K. Petersen { 3169c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); 3170c6a44287SMartin K. Petersen } 317182069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 3172c6a44287SMartin K. Petersen 317382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 3174c6a44287SMartin K. Petersen { 3175c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); 3176c6a44287SMartin K. Petersen } 317782069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 3178c6a44287SMartin K. Petersen 317982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 3180c6a44287SMartin K. Petersen { 318168aee7baSAkinobu Mita return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard); 3182c6a44287SMartin K. Petersen } 318382069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 3184c6a44287SMartin K. Petersen 318582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 3186c6a44287SMartin K. Petersen { 3187c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); 3188c6a44287SMartin K. Petersen } 318982069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 3190c6a44287SMartin K. Petersen 319182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 319244d92694SMartin K. Petersen { 319344d92694SMartin K. Petersen ssize_t count; 319444d92694SMartin K. Petersen 31955b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 319644d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 319744d92694SMartin K. Petersen sdebug_store_sectors); 319844d92694SMartin K. Petersen 319944d92694SMartin K. Petersen count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); 320044d92694SMartin K. Petersen 320144d92694SMartin K. Petersen buf[count++] = '\n'; 320244d92694SMartin K. Petersen buf[count++] = 0; 320344d92694SMartin K. Petersen 320444d92694SMartin K. Petersen return count; 320544d92694SMartin K. Petersen } 320682069379SAkinobu Mita static DRIVER_ATTR_RO(map); 320744d92694SMartin K. Petersen 320882069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 3209d986788bSMartin Pitt { 3210d986788bSMartin Pitt return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0); 3211d986788bSMartin Pitt } 321282069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 321382069379SAkinobu Mita size_t count) 3214d986788bSMartin Pitt { 3215d986788bSMartin Pitt int n; 3216d986788bSMartin Pitt 3217d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 3218d986788bSMartin Pitt scsi_debug_removable = (n > 0); 3219d986788bSMartin Pitt return count; 3220d986788bSMartin Pitt } 3221d986788bSMartin Pitt return -EINVAL; 3222d986788bSMartin Pitt } 322382069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 3224d986788bSMartin Pitt 322582069379SAkinobu Mita /* Note: The following array creates attribute files in the 322623183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 322723183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 322823183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 322923183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 323023183910SDouglas Gilbert */ 32316ecaff7fSRandy Dunlap 323282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 323382069379SAkinobu Mita &driver_attr_delay.attr, 323482069379SAkinobu Mita &driver_attr_opts.attr, 323582069379SAkinobu Mita &driver_attr_ptype.attr, 323682069379SAkinobu Mita &driver_attr_dsense.attr, 323782069379SAkinobu Mita &driver_attr_fake_rw.attr, 323882069379SAkinobu Mita &driver_attr_no_lun_0.attr, 323982069379SAkinobu Mita &driver_attr_num_tgts.attr, 324082069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 324182069379SAkinobu Mita &driver_attr_num_parts.attr, 324282069379SAkinobu Mita &driver_attr_every_nth.attr, 324382069379SAkinobu Mita &driver_attr_max_luns.attr, 324482069379SAkinobu Mita &driver_attr_max_queue.attr, 324582069379SAkinobu Mita &driver_attr_no_uld.attr, 324682069379SAkinobu Mita &driver_attr_scsi_level.attr, 324782069379SAkinobu Mita &driver_attr_virtual_gb.attr, 324882069379SAkinobu Mita &driver_attr_add_host.attr, 324982069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 325082069379SAkinobu Mita &driver_attr_sector_size.attr, 325182069379SAkinobu Mita &driver_attr_dix.attr, 325282069379SAkinobu Mita &driver_attr_dif.attr, 325382069379SAkinobu Mita &driver_attr_guard.attr, 325482069379SAkinobu Mita &driver_attr_ato.attr, 325582069379SAkinobu Mita &driver_attr_map.attr, 325682069379SAkinobu Mita &driver_attr_removable.attr, 325782069379SAkinobu Mita NULL, 325882069379SAkinobu Mita }; 325982069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 32601da177e4SLinus Torvalds 326111ddcecaSAkinobu Mita static struct device *pseudo_primary; 32628dea0d02SFUJITA Tomonori 32631da177e4SLinus Torvalds static int __init scsi_debug_init(void) 32641da177e4SLinus Torvalds { 32655f2578e5SFUJITA Tomonori unsigned long sz; 32661da177e4SLinus Torvalds int host_to_add; 32671da177e4SLinus Torvalds int k; 32686ecaff7fSRandy Dunlap int ret; 32691da177e4SLinus Torvalds 3270597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 3271597136abSMartin K. Petersen case 512: 3272597136abSMartin K. Petersen case 1024: 3273597136abSMartin K. Petersen case 2048: 3274597136abSMartin K. Petersen case 4096: 3275597136abSMartin K. Petersen break; 3276597136abSMartin K. Petersen default: 3277c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", 3278597136abSMartin K. Petersen scsi_debug_sector_size); 3279597136abSMartin K. Petersen return -EINVAL; 3280597136abSMartin K. Petersen } 3281597136abSMartin K. Petersen 3282c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 3283c6a44287SMartin K. Petersen 3284c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 3285c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 3286395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 3287c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 3288c6a44287SMartin K. Petersen break; 3289c6a44287SMartin K. Petersen 3290c6a44287SMartin K. Petersen default: 3291395cef03SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); 3292c6a44287SMartin K. Petersen return -EINVAL; 3293c6a44287SMartin K. Petersen } 3294c6a44287SMartin K. Petersen 3295c6a44287SMartin K. Petersen if (scsi_debug_guard > 1) { 3296c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); 3297c6a44287SMartin K. Petersen return -EINVAL; 3298c6a44287SMartin K. Petersen } 3299c6a44287SMartin K. Petersen 3300c6a44287SMartin K. Petersen if (scsi_debug_ato > 1) { 3301c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); 3302c6a44287SMartin K. Petersen return -EINVAL; 3303c6a44287SMartin K. Petersen } 3304c6a44287SMartin K. Petersen 3305ea61fca5SMartin K. Petersen if (scsi_debug_physblk_exp > 15) { 3306ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n", 3307ea61fca5SMartin K. Petersen scsi_debug_physblk_exp); 3308ea61fca5SMartin K. Petersen return -EINVAL; 3309ea61fca5SMartin K. Petersen } 3310ea61fca5SMartin K. Petersen 3311ea61fca5SMartin K. Petersen if (scsi_debug_lowest_aligned > 0x3fff) { 3312ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n", 3313ea61fca5SMartin K. Petersen scsi_debug_lowest_aligned); 3314ea61fca5SMartin K. Petersen return -EINVAL; 3315ea61fca5SMartin K. Petersen } 3316ea61fca5SMartin K. Petersen 33171da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 33181da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 33195f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 3320597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 332128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 33221da177e4SLinus Torvalds 33231da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 33241da177e4SLinus Torvalds sdebug_heads = 8; 33251da177e4SLinus Torvalds sdebug_sectors_per = 32; 33261da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 33271da177e4SLinus Torvalds sdebug_heads = 32; 33281da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 33291da177e4SLinus Torvalds sdebug_heads = 64; 33301da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33311da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33321da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 33331da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 33341da177e4SLinus Torvalds sdebug_heads = 255; 33351da177e4SLinus Torvalds sdebug_sectors_per = 63; 33361da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33371da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33381da177e4SLinus Torvalds } 33391da177e4SLinus Torvalds 33401da177e4SLinus Torvalds fake_storep = vmalloc(sz); 33411da177e4SLinus Torvalds if (NULL == fake_storep) { 33421da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 33431da177e4SLinus Torvalds return -ENOMEM; 33441da177e4SLinus Torvalds } 33451da177e4SLinus Torvalds memset(fake_storep, 0, sz); 33461da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 3347f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 33481da177e4SLinus Torvalds 33497cb69d03SAkinobu Mita if (scsi_debug_dix) { 3350c6a44287SMartin K. Petersen int dif_size; 3351c6a44287SMartin K. Petersen 3352c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 3353c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 3354c6a44287SMartin K. Petersen 3355c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", 3356c6a44287SMartin K. Petersen dif_size, dif_storep); 3357c6a44287SMartin K. Petersen 3358c6a44287SMartin K. Petersen if (dif_storep == NULL) { 3359c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); 3360c6a44287SMartin K. Petersen ret = -ENOMEM; 3361c6a44287SMartin K. Petersen goto free_vm; 3362c6a44287SMartin K. Petersen } 3363c6a44287SMartin K. Petersen 3364c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 3365c6a44287SMartin K. Petersen } 3366c6a44287SMartin K. Petersen 33675b94e232SMartin K. Petersen /* Logical Block Provisioning */ 33685b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 33696014759cSMartin K. Petersen scsi_debug_unmap_max_blocks = 33706014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); 33716014759cSMartin K. Petersen 33726014759cSMartin K. Petersen scsi_debug_unmap_max_desc = 33736014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_desc, 0U, 256U); 33746014759cSMartin K. Petersen 33756014759cSMartin K. Petersen scsi_debug_unmap_granularity = 33766014759cSMartin K. Petersen clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); 33776014759cSMartin K. Petersen 33786014759cSMartin K. Petersen if (scsi_debug_unmap_alignment && 3379ac17078aSAkinobu Mita scsi_debug_unmap_granularity <= 3380ac17078aSAkinobu Mita scsi_debug_unmap_alignment) { 338144d92694SMartin K. Petersen printk(KERN_ERR 3382ac17078aSAkinobu Mita "%s: ERR: unmap_granularity <= unmap_alignment\n", 338344d92694SMartin K. Petersen __func__); 338444d92694SMartin K. Petersen return -EINVAL; 338544d92694SMartin K. Petersen } 338644d92694SMartin K. Petersen 3387b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 3388b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 338944d92694SMartin K. Petersen 339044d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", 339144d92694SMartin K. Petersen map_size); 339244d92694SMartin K. Petersen 339344d92694SMartin K. Petersen if (map_storep == NULL) { 339444d92694SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n"); 339544d92694SMartin K. Petersen ret = -ENOMEM; 339644d92694SMartin K. Petersen goto free_vm; 339744d92694SMartin K. Petersen } 339844d92694SMartin K. Petersen 3399b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 340044d92694SMartin K. Petersen 340144d92694SMartin K. Petersen /* Map first 1KB for partition table */ 340244d92694SMartin K. Petersen if (scsi_debug_num_parts) 340344d92694SMartin K. Petersen map_region(0, 2); 340444d92694SMartin K. Petersen } 340544d92694SMartin K. Petersen 34069b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 34079b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 34089b906779SNicholas Bellinger printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); 34099b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 34106ecaff7fSRandy Dunlap goto free_vm; 34116ecaff7fSRandy Dunlap } 34126ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 34136ecaff7fSRandy Dunlap if (ret < 0) { 34146ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 34156ecaff7fSRandy Dunlap ret); 34166ecaff7fSRandy Dunlap goto dev_unreg; 34176ecaff7fSRandy Dunlap } 34186ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 34196ecaff7fSRandy Dunlap if (ret < 0) { 34206ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 34216ecaff7fSRandy Dunlap ret); 34226ecaff7fSRandy Dunlap goto bus_unreg; 34236ecaff7fSRandy Dunlap } 34241da177e4SLinus Torvalds 34256ecaff7fSRandy Dunlap init_all_queued(); 34261da177e4SLinus Torvalds 34271da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 34281da177e4SLinus Torvalds scsi_debug_add_host = 0; 34291da177e4SLinus Torvalds 34301da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 34311da177e4SLinus Torvalds if (sdebug_add_adapter()) { 34321da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 34331da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 34341da177e4SLinus Torvalds break; 34351da177e4SLinus Torvalds } 34361da177e4SLinus Torvalds } 34371da177e4SLinus Torvalds 34381da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 34391da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 34401da177e4SLinus Torvalds scsi_debug_add_host); 34411da177e4SLinus Torvalds } 34421da177e4SLinus Torvalds return 0; 34436ecaff7fSRandy Dunlap 34446ecaff7fSRandy Dunlap bus_unreg: 34456ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 34466ecaff7fSRandy Dunlap dev_unreg: 34479b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 34486ecaff7fSRandy Dunlap free_vm: 344944d92694SMartin K. Petersen if (map_storep) 345044d92694SMartin K. Petersen vfree(map_storep); 3451c6a44287SMartin K. Petersen if (dif_storep) 3452c6a44287SMartin K. Petersen vfree(dif_storep); 34536ecaff7fSRandy Dunlap vfree(fake_storep); 34546ecaff7fSRandy Dunlap 34556ecaff7fSRandy Dunlap return ret; 34561da177e4SLinus Torvalds } 34571da177e4SLinus Torvalds 34581da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 34591da177e4SLinus Torvalds { 34601da177e4SLinus Torvalds int k = scsi_debug_add_host; 34611da177e4SLinus Torvalds 34621da177e4SLinus Torvalds stop_all_queued(); 34631da177e4SLinus Torvalds for (; k; k--) 34641da177e4SLinus Torvalds sdebug_remove_adapter(); 34651da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 34661da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 34679b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 34681da177e4SLinus Torvalds 3469c6a44287SMartin K. Petersen if (dif_storep) 3470c6a44287SMartin K. Petersen vfree(dif_storep); 3471c6a44287SMartin K. Petersen 34721da177e4SLinus Torvalds vfree(fake_storep); 34731da177e4SLinus Torvalds } 34741da177e4SLinus Torvalds 34751da177e4SLinus Torvalds device_initcall(scsi_debug_init); 34761da177e4SLinus Torvalds module_exit(scsi_debug_exit); 34771da177e4SLinus Torvalds 34781da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 34791da177e4SLinus Torvalds { 34801da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 34811da177e4SLinus Torvalds 34821da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 34831da177e4SLinus Torvalds kfree(sdbg_host); 34841da177e4SLinus Torvalds } 34851da177e4SLinus Torvalds 34861da177e4SLinus Torvalds static int sdebug_add_adapter(void) 34871da177e4SLinus Torvalds { 34881da177e4SLinus Torvalds int k, devs_per_host; 34891da177e4SLinus Torvalds int error = 0; 34901da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 34918b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 34921da177e4SLinus Torvalds 349324669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 34941da177e4SLinus Torvalds if (NULL == sdbg_host) { 34951da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3496cadbd4a5SHarvey Harrison __func__, __LINE__); 34971da177e4SLinus Torvalds return -ENOMEM; 34981da177e4SLinus Torvalds } 34991da177e4SLinus Torvalds 35001da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 35011da177e4SLinus Torvalds 35021da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 35031da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 35045cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 35055cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 35061da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3507cadbd4a5SHarvey Harrison __func__, __LINE__); 35081da177e4SLinus Torvalds error = -ENOMEM; 35091da177e4SLinus Torvalds goto clean; 35101da177e4SLinus Torvalds } 35111da177e4SLinus Torvalds } 35121da177e4SLinus Torvalds 35131da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 35141da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 35151da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 35161da177e4SLinus Torvalds 35171da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 35189b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 35191da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 352071610f55SKay Sievers dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); 35211da177e4SLinus Torvalds 35221da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 35231da177e4SLinus Torvalds 35241da177e4SLinus Torvalds if (error) 35251da177e4SLinus Torvalds goto clean; 35261da177e4SLinus Torvalds 35271da177e4SLinus Torvalds ++scsi_debug_add_host; 35281da177e4SLinus Torvalds return error; 35291da177e4SLinus Torvalds 35301da177e4SLinus Torvalds clean: 35318b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 35328b40228fSFUJITA Tomonori dev_list) { 35331da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 35341da177e4SLinus Torvalds kfree(sdbg_devinfo); 35351da177e4SLinus Torvalds } 35361da177e4SLinus Torvalds 35371da177e4SLinus Torvalds kfree(sdbg_host); 35381da177e4SLinus Torvalds return error; 35391da177e4SLinus Torvalds } 35401da177e4SLinus Torvalds 35411da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 35421da177e4SLinus Torvalds { 35431da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 35441da177e4SLinus Torvalds 35451da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 35461da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 35471da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 35481da177e4SLinus Torvalds struct sdebug_host_info, host_list); 35491da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 35501da177e4SLinus Torvalds } 35511da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 35521da177e4SLinus Torvalds 35531da177e4SLinus Torvalds if (!sdbg_host) 35541da177e4SLinus Torvalds return; 35551da177e4SLinus Torvalds 35561da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 35571da177e4SLinus Torvalds --scsi_debug_add_host; 35581da177e4SLinus Torvalds } 35591da177e4SLinus Torvalds 3560639db475SFUJITA Tomonori static 3561f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) 3562639db475SFUJITA Tomonori { 3563639db475SFUJITA Tomonori unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 3564639db475SFUJITA Tomonori int len, k; 3565639db475SFUJITA Tomonori unsigned int num; 3566639db475SFUJITA Tomonori unsigned long long lba; 3567395cef03SMartin K. Petersen u32 ei_lba; 3568639db475SFUJITA Tomonori int errsts = 0; 3569639db475SFUJITA Tomonori int target = SCpnt->device->id; 3570639db475SFUJITA Tomonori struct sdebug_dev_info *devip = NULL; 3571639db475SFUJITA Tomonori int inj_recovered = 0; 3572639db475SFUJITA Tomonori int inj_transport = 0; 3573c6a44287SMartin K. Petersen int inj_dif = 0; 3574c6a44287SMartin K. Petersen int inj_dix = 0; 3575639db475SFUJITA Tomonori int delay_override = 0; 357644d92694SMartin K. Petersen int unmap = 0; 3577639db475SFUJITA Tomonori 3578639db475SFUJITA Tomonori scsi_set_resid(SCpnt, 0); 3579639db475SFUJITA Tomonori if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 3580639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: cmd "); 3581639db475SFUJITA Tomonori for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 3582639db475SFUJITA Tomonori printk("%02x ", (int)cmd[k]); 3583639db475SFUJITA Tomonori printk("\n"); 3584639db475SFUJITA Tomonori } 3585639db475SFUJITA Tomonori 3586639db475SFUJITA Tomonori if (target == SCpnt->device->host->hostt->this_id) { 3587639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: initiator's id used as " 3588639db475SFUJITA Tomonori "target!\n"); 3589639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3590639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3591639db475SFUJITA Tomonori } 3592639db475SFUJITA Tomonori 3593639db475SFUJITA Tomonori if ((SCpnt->device->lun >= scsi_debug_max_luns) && 3594639db475SFUJITA Tomonori (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 3595639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3596639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3597639db475SFUJITA Tomonori devip = devInfoReg(SCpnt->device); 3598639db475SFUJITA Tomonori if (NULL == devip) 3599639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3600639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3601639db475SFUJITA Tomonori 3602639db475SFUJITA Tomonori if ((scsi_debug_every_nth != 0) && 3603639db475SFUJITA Tomonori (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3604639db475SFUJITA Tomonori scsi_debug_cmnd_count = 0; 3605639db475SFUJITA Tomonori if (scsi_debug_every_nth < -1) 3606639db475SFUJITA Tomonori scsi_debug_every_nth = -1; 3607639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3608639db475SFUJITA Tomonori return 0; /* ignore command causing timeout */ 360918a4d0a2SMartin K. Petersen else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && 361018a4d0a2SMartin K. Petersen scsi_medium_access_command(SCpnt)) 361118a4d0a2SMartin K. Petersen return 0; /* time out reads and writes */ 3612639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3613639db475SFUJITA Tomonori inj_recovered = 1; /* to reads and writes below */ 3614639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 3615639db475SFUJITA Tomonori inj_transport = 1; /* to reads and writes below */ 3616c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) 3617c6a44287SMartin K. Petersen inj_dif = 1; /* to reads and writes below */ 3618c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) 3619c6a44287SMartin K. Petersen inj_dix = 1; /* to reads and writes below */ 3620639db475SFUJITA Tomonori } 3621639db475SFUJITA Tomonori 3622639db475SFUJITA Tomonori if (devip->wlun) { 3623639db475SFUJITA Tomonori switch (*cmd) { 3624639db475SFUJITA Tomonori case INQUIRY: 3625639db475SFUJITA Tomonori case REQUEST_SENSE: 3626639db475SFUJITA Tomonori case TEST_UNIT_READY: 3627639db475SFUJITA Tomonori case REPORT_LUNS: 3628639db475SFUJITA Tomonori break; /* only allowable wlun commands */ 3629639db475SFUJITA Tomonori default: 3630639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3631639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 3632639db475SFUJITA Tomonori "not supported for wlun\n", *cmd); 3633639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3634639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3635639db475SFUJITA Tomonori errsts = check_condition_result; 3636639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3637639db475SFUJITA Tomonori 0); 3638639db475SFUJITA Tomonori } 3639639db475SFUJITA Tomonori } 3640639db475SFUJITA Tomonori 3641639db475SFUJITA Tomonori switch (*cmd) { 3642639db475SFUJITA Tomonori case INQUIRY: /* mandatory, ignore unit attention */ 3643639db475SFUJITA Tomonori delay_override = 1; 3644639db475SFUJITA Tomonori errsts = resp_inquiry(SCpnt, target, devip); 3645639db475SFUJITA Tomonori break; 3646639db475SFUJITA Tomonori case REQUEST_SENSE: /* mandatory, ignore unit attention */ 3647639db475SFUJITA Tomonori delay_override = 1; 3648639db475SFUJITA Tomonori errsts = resp_requests(SCpnt, devip); 3649639db475SFUJITA Tomonori break; 3650639db475SFUJITA Tomonori case REZERO_UNIT: /* actually this is REWIND for SSC */ 3651639db475SFUJITA Tomonori case START_STOP: 3652639db475SFUJITA Tomonori errsts = resp_start_stop(SCpnt, devip); 3653639db475SFUJITA Tomonori break; 3654639db475SFUJITA Tomonori case ALLOW_MEDIUM_REMOVAL: 3655639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3656639db475SFUJITA Tomonori if (errsts) 3657639db475SFUJITA Tomonori break; 3658639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3659639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Medium removal %s\n", 3660639db475SFUJITA Tomonori cmd[4] ? "inhibited" : "enabled"); 3661639db475SFUJITA Tomonori break; 3662639db475SFUJITA Tomonori case SEND_DIAGNOSTIC: /* mandatory */ 3663639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3664639db475SFUJITA Tomonori break; 3665639db475SFUJITA Tomonori case TEST_UNIT_READY: /* mandatory */ 3666639db475SFUJITA Tomonori delay_override = 1; 3667639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3668639db475SFUJITA Tomonori break; 3669639db475SFUJITA Tomonori case RESERVE: 3670639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3671639db475SFUJITA Tomonori break; 3672639db475SFUJITA Tomonori case RESERVE_10: 3673639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3674639db475SFUJITA Tomonori break; 3675639db475SFUJITA Tomonori case RELEASE: 3676639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3677639db475SFUJITA Tomonori break; 3678639db475SFUJITA Tomonori case RELEASE_10: 3679639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3680639db475SFUJITA Tomonori break; 3681639db475SFUJITA Tomonori case READ_CAPACITY: 3682639db475SFUJITA Tomonori errsts = resp_readcap(SCpnt, devip); 3683639db475SFUJITA Tomonori break; 3684639db475SFUJITA Tomonori case SERVICE_ACTION_IN: 368544d92694SMartin K. Petersen if (cmd[1] == SAI_READ_CAPACITY_16) 368644d92694SMartin K. Petersen errsts = resp_readcap16(SCpnt, devip); 368744d92694SMartin K. Petersen else if (cmd[1] == SAI_GET_LBA_STATUS) { 368844d92694SMartin K. Petersen 36895b94e232SMartin K. Petersen if (scsi_debug_lbp() == 0) { 369044d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 369144d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 369244d92694SMartin K. Petersen errsts = check_condition_result; 369344d92694SMartin K. Petersen } else 369444d92694SMartin K. Petersen errsts = resp_get_lba_status(SCpnt, devip); 369544d92694SMartin K. Petersen } else { 3696639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3697639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3698639db475SFUJITA Tomonori errsts = check_condition_result; 3699639db475SFUJITA Tomonori } 3700639db475SFUJITA Tomonori break; 3701639db475SFUJITA Tomonori case MAINTENANCE_IN: 3702639db475SFUJITA Tomonori if (MI_REPORT_TARGET_PGS != cmd[1]) { 3703639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3704639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3705639db475SFUJITA Tomonori errsts = check_condition_result; 3706639db475SFUJITA Tomonori break; 3707639db475SFUJITA Tomonori } 3708639db475SFUJITA Tomonori errsts = resp_report_tgtpgs(SCpnt, devip); 3709639db475SFUJITA Tomonori break; 3710639db475SFUJITA Tomonori case READ_16: 3711639db475SFUJITA Tomonori case READ_12: 3712639db475SFUJITA Tomonori case READ_10: 3713395cef03SMartin K. Petersen /* READ{10,12,16} and DIF Type 2 are natural enemies */ 3714395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3715395cef03SMartin K. Petersen cmd[1] & 0xe0) { 3716395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3717395cef03SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 3718395cef03SMartin K. Petersen errsts = check_condition_result; 3719395cef03SMartin K. Petersen break; 3720395cef03SMartin K. Petersen } 3721395cef03SMartin K. Petersen 3722395cef03SMartin K. Petersen if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3723395cef03SMartin K. Petersen scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3724395cef03SMartin K. Petersen (cmd[1] & 0xe0) == 0) 3725395cef03SMartin K. Petersen printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3726395cef03SMartin K. Petersen 3727395cef03SMartin K. Petersen /* fall through */ 3728639db475SFUJITA Tomonori case READ_6: 3729395cef03SMartin K. Petersen read: 3730639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3731639db475SFUJITA Tomonori if (errsts) 3732639db475SFUJITA Tomonori break; 3733639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3734639db475SFUJITA Tomonori break; 3735395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3736395cef03SMartin K. Petersen errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3737639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 3738639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 3739639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 3740639db475SFUJITA Tomonori errsts = check_condition_result; 3741639db475SFUJITA Tomonori } else if (inj_transport && (0 == errsts)) { 3742639db475SFUJITA Tomonori mk_sense_buffer(devip, ABORTED_COMMAND, 3743639db475SFUJITA Tomonori TRANSPORT_PROBLEM, ACK_NAK_TO); 3744639db475SFUJITA Tomonori errsts = check_condition_result; 3745c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3746c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3747c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3748c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3749c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3750c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3751639db475SFUJITA Tomonori } 3752639db475SFUJITA Tomonori break; 3753639db475SFUJITA Tomonori case REPORT_LUNS: /* mandatory, ignore unit attention */ 3754639db475SFUJITA Tomonori delay_override = 1; 3755639db475SFUJITA Tomonori errsts = resp_report_luns(SCpnt, devip); 3756639db475SFUJITA Tomonori break; 3757639db475SFUJITA Tomonori case VERIFY: /* 10 byte SBC-2 command */ 3758639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3759639db475SFUJITA Tomonori break; 3760639db475SFUJITA Tomonori case WRITE_16: 3761639db475SFUJITA Tomonori case WRITE_12: 3762639db475SFUJITA Tomonori case WRITE_10: 3763395cef03SMartin K. Petersen /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ 3764395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3765395cef03SMartin K. Petersen cmd[1] & 0xe0) { 3766395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3767395cef03SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 3768395cef03SMartin K. Petersen errsts = check_condition_result; 3769395cef03SMartin K. Petersen break; 3770395cef03SMartin K. Petersen } 3771395cef03SMartin K. Petersen 3772395cef03SMartin K. Petersen if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3773395cef03SMartin K. Petersen scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3774395cef03SMartin K. Petersen (cmd[1] & 0xe0) == 0) 3775395cef03SMartin K. Petersen printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3776395cef03SMartin K. Petersen 3777395cef03SMartin K. Petersen /* fall through */ 3778639db475SFUJITA Tomonori case WRITE_6: 3779395cef03SMartin K. Petersen write: 3780639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3781639db475SFUJITA Tomonori if (errsts) 3782639db475SFUJITA Tomonori break; 3783639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3784639db475SFUJITA Tomonori break; 3785395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3786395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3787639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 3788639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 3789639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 3790639db475SFUJITA Tomonori errsts = check_condition_result; 3791c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3792c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3793c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3794c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3795c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3796c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3797639db475SFUJITA Tomonori } 3798639db475SFUJITA Tomonori break; 379944d92694SMartin K. Petersen case WRITE_SAME_16: 38005b94e232SMartin K. Petersen case WRITE_SAME: 38016014759cSMartin K. Petersen if (cmd[1] & 0x8) { 38025b94e232SMartin K. Petersen if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) || 38035b94e232SMartin K. Petersen (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) { 38046014759cSMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 38056014759cSMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 38066014759cSMartin K. Petersen errsts = check_condition_result; 38076014759cSMartin K. Petersen } else 380844d92694SMartin K. Petersen unmap = 1; 38096014759cSMartin K. Petersen } 38106014759cSMartin K. Petersen if (errsts) 38116014759cSMartin K. Petersen break; 381244d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 381344d92694SMartin K. Petersen if (errsts) 381444d92694SMartin K. Petersen break; 381544d92694SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 381644d92694SMartin K. Petersen errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap); 381744d92694SMartin K. Petersen break; 381844d92694SMartin K. Petersen case UNMAP: 381944d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 382044d92694SMartin K. Petersen if (errsts) 382144d92694SMartin K. Petersen break; 382244d92694SMartin K. Petersen 38235b94e232SMartin K. Petersen if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) { 382444d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 382544d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 382644d92694SMartin K. Petersen errsts = check_condition_result; 382744d92694SMartin K. Petersen } else 382844d92694SMartin K. Petersen errsts = resp_unmap(SCpnt, devip); 382944d92694SMartin K. Petersen break; 3830639db475SFUJITA Tomonori case MODE_SENSE: 3831639db475SFUJITA Tomonori case MODE_SENSE_10: 3832639db475SFUJITA Tomonori errsts = resp_mode_sense(SCpnt, target, devip); 3833639db475SFUJITA Tomonori break; 3834639db475SFUJITA Tomonori case MODE_SELECT: 3835639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 1, devip); 3836639db475SFUJITA Tomonori break; 3837639db475SFUJITA Tomonori case MODE_SELECT_10: 3838639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 0, devip); 3839639db475SFUJITA Tomonori break; 3840639db475SFUJITA Tomonori case LOG_SENSE: 3841639db475SFUJITA Tomonori errsts = resp_log_sense(SCpnt, devip); 3842639db475SFUJITA Tomonori break; 3843639db475SFUJITA Tomonori case SYNCHRONIZE_CACHE: 3844639db475SFUJITA Tomonori delay_override = 1; 3845639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3846639db475SFUJITA Tomonori break; 3847639db475SFUJITA Tomonori case WRITE_BUFFER: 3848639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3849639db475SFUJITA Tomonori break; 3850639db475SFUJITA Tomonori case XDWRITEREAD_10: 3851639db475SFUJITA Tomonori if (!scsi_bidi_cmnd(SCpnt)) { 3852639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3853639db475SFUJITA Tomonori INVALID_FIELD_IN_CDB, 0); 3854639db475SFUJITA Tomonori errsts = check_condition_result; 3855639db475SFUJITA Tomonori break; 3856639db475SFUJITA Tomonori } 3857639db475SFUJITA Tomonori 3858639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3859639db475SFUJITA Tomonori if (errsts) 3860639db475SFUJITA Tomonori break; 3861639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3862639db475SFUJITA Tomonori break; 3863395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3864395cef03SMartin K. Petersen errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3865639db475SFUJITA Tomonori if (errsts) 3866639db475SFUJITA Tomonori break; 3867395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3868639db475SFUJITA Tomonori if (errsts) 3869639db475SFUJITA Tomonori break; 3870639db475SFUJITA Tomonori errsts = resp_xdwriteread(SCpnt, lba, num, devip); 3871639db475SFUJITA Tomonori break; 3872395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 3873395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { 3874395cef03SMartin K. Petersen 3875395cef03SMartin K. Petersen if ((cmd[10] & 0xe0) == 0) 3876395cef03SMartin K. Petersen printk(KERN_ERR 3877395cef03SMartin K. Petersen "Unprotected RD/WR to DIF device\n"); 3878395cef03SMartin K. Petersen 3879395cef03SMartin K. Petersen if (cmd[9] == READ_32) { 3880395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3881395cef03SMartin K. Petersen goto read; 3882395cef03SMartin K. Petersen } 3883395cef03SMartin K. Petersen 3884395cef03SMartin K. Petersen if (cmd[9] == WRITE_32) { 3885395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3886395cef03SMartin K. Petersen goto write; 3887395cef03SMartin K. Petersen } 3888395cef03SMartin K. Petersen } 3889395cef03SMartin K. Petersen 3890395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3891395cef03SMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 3892395cef03SMartin K. Petersen errsts = check_condition_result; 3893395cef03SMartin K. Petersen break; 3894395cef03SMartin K. Petersen 3895639db475SFUJITA Tomonori default: 3896639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3897639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 3898639db475SFUJITA Tomonori "supported\n", *cmd); 3899639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3900639db475SFUJITA Tomonori if (errsts) 3901639db475SFUJITA Tomonori break; /* Unit attention takes precedence */ 3902639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 3903639db475SFUJITA Tomonori errsts = check_condition_result; 3904639db475SFUJITA Tomonori break; 3905639db475SFUJITA Tomonori } 3906639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3907639db475SFUJITA Tomonori (delay_override ? 0 : scsi_debug_delay)); 3908639db475SFUJITA Tomonori } 3909639db475SFUJITA Tomonori 3910f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand) 3911f281233dSJeff Garzik 39129e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 3913c8ed555aSAl Viro .show_info = scsi_debug_show_info, 3914c8ed555aSAl Viro .write_info = scsi_debug_write_info, 39159e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 39169e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 39179e603ca0SFUJITA Tomonori .info = scsi_debug_info, 39189e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 39199e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 39209e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 39219e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 39229e603ca0SFUJITA Tomonori .queuecommand = scsi_debug_queuecommand, 39239e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 39249e603ca0SFUJITA Tomonori .eh_bus_reset_handler = scsi_debug_bus_reset, 39259e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 39269e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 39279e603ca0SFUJITA Tomonori .bios_param = scsi_debug_biosparam, 39289e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 39299e603ca0SFUJITA Tomonori .this_id = 7, 39309e603ca0SFUJITA Tomonori .sg_tablesize = 256, 39319e603ca0SFUJITA Tomonori .cmd_per_lun = 16, 39329e603ca0SFUJITA Tomonori .max_sectors = 0xffff, 39339e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 39349e603ca0SFUJITA Tomonori .module = THIS_MODULE, 39359e603ca0SFUJITA Tomonori }; 39369e603ca0SFUJITA Tomonori 39371da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 39381da177e4SLinus Torvalds { 39391da177e4SLinus Torvalds int error = 0; 39401da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 39411da177e4SLinus Torvalds struct Scsi_Host *hpnt; 3942c6a44287SMartin K. Petersen int host_prot; 39431da177e4SLinus Torvalds 39441da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 39451da177e4SLinus Torvalds 394678d4e5a0SDouglas Gilbert sdebug_driver_template.can_queue = scsi_debug_max_queue; 39471da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 39481da177e4SLinus Torvalds if (NULL == hpnt) { 3949cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_register failed\n", __func__); 39501da177e4SLinus Torvalds error = -ENODEV; 39511da177e4SLinus Torvalds return error; 39521da177e4SLinus Torvalds } 39531da177e4SLinus Torvalds 39541da177e4SLinus Torvalds sdbg_host->shost = hpnt; 39551da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 39561da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 39571da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 39581da177e4SLinus Torvalds else 39591da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 3960c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 39611da177e4SLinus Torvalds 3962c6a44287SMartin K. Petersen host_prot = 0; 3963c6a44287SMartin K. Petersen 3964c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 3965c6a44287SMartin K. Petersen 3966c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 3967c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE1_PROTECTION; 3968c6a44287SMartin K. Petersen if (scsi_debug_dix) 3969c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE1_PROTECTION; 3970c6a44287SMartin K. Petersen break; 3971c6a44287SMartin K. Petersen 3972c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 3973c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE2_PROTECTION; 3974c6a44287SMartin K. Petersen if (scsi_debug_dix) 3975c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE2_PROTECTION; 3976c6a44287SMartin K. Petersen break; 3977c6a44287SMartin K. Petersen 3978c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 3979c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE3_PROTECTION; 3980c6a44287SMartin K. Petersen if (scsi_debug_dix) 3981c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE3_PROTECTION; 3982c6a44287SMartin K. Petersen break; 3983c6a44287SMartin K. Petersen 3984c6a44287SMartin K. Petersen default: 3985c6a44287SMartin K. Petersen if (scsi_debug_dix) 3986c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE0_PROTECTION; 3987c6a44287SMartin K. Petersen break; 3988c6a44287SMartin K. Petersen } 3989c6a44287SMartin K. Petersen 3990c6a44287SMartin K. Petersen scsi_host_set_prot(hpnt, host_prot); 3991c6a44287SMartin K. Petersen 3992c6a44287SMartin K. Petersen printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", 3993c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 3994c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 3995c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 3996c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 3997c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 3998c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 3999c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 4000c6a44287SMartin K. Petersen 4001c6a44287SMartin K. Petersen if (scsi_debug_guard == 1) 4002c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 4003c6a44287SMartin K. Petersen else 4004c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 4005c6a44287SMartin K. Petersen 40061da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 40071da177e4SLinus Torvalds if (error) { 4008cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); 40091da177e4SLinus Torvalds error = -ENODEV; 40101da177e4SLinus Torvalds scsi_host_put(hpnt); 40111da177e4SLinus Torvalds } else 40121da177e4SLinus Torvalds scsi_scan_host(hpnt); 40131da177e4SLinus Torvalds 40141da177e4SLinus Torvalds 40151da177e4SLinus Torvalds return error; 40161da177e4SLinus Torvalds } 40171da177e4SLinus Torvalds 40181da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 40191da177e4SLinus Torvalds { 40201da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 40218b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 40221da177e4SLinus Torvalds 40231da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 40241da177e4SLinus Torvalds 40251da177e4SLinus Torvalds if (!sdbg_host) { 40261da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 4027cadbd4a5SHarvey Harrison __func__); 40281da177e4SLinus Torvalds return -ENODEV; 40291da177e4SLinus Torvalds } 40301da177e4SLinus Torvalds 40311da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 40321da177e4SLinus Torvalds 40338b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 40348b40228fSFUJITA Tomonori dev_list) { 40351da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 40361da177e4SLinus Torvalds kfree(sdbg_devinfo); 40371da177e4SLinus Torvalds } 40381da177e4SLinus Torvalds 40391da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 40401da177e4SLinus Torvalds return 0; 40411da177e4SLinus Torvalds } 40421da177e4SLinus Torvalds 40438dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 40448dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 40451da177e4SLinus Torvalds { 40468dea0d02SFUJITA Tomonori return 1; 40478dea0d02SFUJITA Tomonori } 40481da177e4SLinus Torvalds 40498dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 40508dea0d02SFUJITA Tomonori .name = "pseudo", 40518dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 40528dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 40538dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 405482069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 40558dea0d02SFUJITA Tomonori }; 4056