11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This version is more generic, simulating a variable number of disk 1023183910SDouglas Gilbert * (or disk like devices) sharing a common amount of RAM. To be more 1123183910SDouglas Gilbert * realistic, the simulated devices have the transport attributes of 1223183910SDouglas Gilbert * SAS disks. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * 1578d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] 181da177e4SLinus Torvalds * dpg: work for devfs large number of disks [20010809] 191da177e4SLinus Torvalds * forked for lk 2.5 series [20011216, 20020101] 201da177e4SLinus Torvalds * use vmalloc() more inquiry+mode_sense [20020302] 211da177e4SLinus Torvalds * add timers for delayed responses [20020721] 221da177e4SLinus Torvalds * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] 231da177e4SLinus Torvalds * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] 241da177e4SLinus Torvalds * dpg: change style of boot options to "scsi_debug.num_tgts=2" and 251da177e4SLinus Torvalds * module options to "modprobe scsi_debug num_tgts=2" [20021221] 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #include <linux/kernel.h> 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/timer.h> 335a0e3ad6STejun Heo #include <linux/slab.h> 341da177e4SLinus Torvalds #include <linux/types.h> 351da177e4SLinus Torvalds #include <linux/string.h> 361da177e4SLinus Torvalds #include <linux/genhd.h> 371da177e4SLinus Torvalds #include <linux/fs.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/proc_fs.h> 401da177e4SLinus Torvalds #include <linux/vmalloc.h> 411da177e4SLinus Torvalds #include <linux/moduleparam.h> 42852e034dSJens Axboe #include <linux/scatterlist.h> 431da177e4SLinus Torvalds #include <linux/blkdev.h> 44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 45c6a44287SMartin K. Petersen 46c6a44287SMartin K. Petersen #include <net/checksum.h> 479ff26eefSFUJITA Tomonori 4844d92694SMartin K. Petersen #include <asm/unaligned.h> 4944d92694SMartin K. Petersen 509ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 531da177e4SLinus Torvalds #include <scsi/scsi_host.h> 541da177e4SLinus Torvalds #include <scsi/scsicam.h> 55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 571da177e4SLinus Torvalds 58c6a44287SMartin K. Petersen #include "sd.h" 591da177e4SLinus Torvalds #include "scsi_logging.h" 601da177e4SLinus Torvalds 6178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.82" 6278d4e5a0SDouglas Gilbert static const char * scsi_debug_version_date = "20100324"; 631da177e4SLinus Torvalds 646f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 65c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 66c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 671da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 68c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 691da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 701da177e4SLinus Torvalds #define ADDR_OUT_OF_RANGE 0x21 71395cef03SMartin K. Petersen #define INVALID_COMMAND_OPCODE 0x20 721da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 73c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 741da177e4SLinus Torvalds #define POWERON_RESET 0x29 751da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 766f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 77c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 78c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 791da177e4SLinus Torvalds 806f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 816f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 826f3cbf55SDouglas Gilbert 831da177e4SLinus Torvalds #define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */ 841da177e4SLinus Torvalds 851da177e4SLinus Torvalds /* Default values for driver parameters */ 861da177e4SLinus Torvalds #define DEF_NUM_HOST 1 871da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 881da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 891da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 901da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 911da177e4SLinus Torvalds */ 925b94e232SMartin K. Petersen #define DEF_ATO 1 931da177e4SLinus Torvalds #define DEF_DELAY 1 941da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 955b94e232SMartin K. Petersen #define DEF_DIF 0 965b94e232SMartin K. Petersen #define DEF_DIX 0 975b94e232SMartin K. Petersen #define DEF_D_SENSE 0 981da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 995b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1005b94e232SMartin K. Petersen #define DEF_GUARD 0 1015b94e232SMartin K. Petersen #define DEF_LBPU 0 1025b94e232SMartin K. Petersen #define DEF_LBPWS 0 1035b94e232SMartin K. Petersen #define DEF_LBPWS10 0 104be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1055b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 1065b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1071da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1081da177e4SLinus Torvalds #define DEF_OPTS 0 109e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64 1105b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 1115b94e232SMartin K. Petersen #define DEF_PTYPE 0 112d986788bSMartin Pitt #define DEF_REMOVABLE false 1135b94e232SMartin K. Petersen #define DEF_SCSI_LEVEL 5 /* INQUIRY, byte2 [5->SPC-3] */ 1145b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1155b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1165b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1176014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1186014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1195b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1205b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1215b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 1221da177e4SLinus Torvalds 1231da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1241da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1251da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1261da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1271da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1286f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 129c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR 32 130c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR 64 13118a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT 128 1321da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1331da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1341da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1351da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1366f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1376f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1381da177e4SLinus Torvalds * 1391da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1401da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1411da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1421da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1436f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1446f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1451da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1461da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1471da177e4SLinus Torvalds */ 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1501da177e4SLinus Torvalds * sector on read commands: */ 1511da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 15232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1551da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1561da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 157c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1581da177e4SLinus Torvalds 15978d4e5a0SDouglas Gilbert /* Can queue up to this number of commands. Typically commands that 16078d4e5a0SDouglas Gilbert * that have a non-zero delay are queued. */ 16178d4e5a0SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE 255 16278d4e5a0SDouglas Gilbert 1631da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 1645b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO; 1651da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 1661da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 1675b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF; 1685b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX; 1695b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE; 1701da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 1715b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW; 1725b94e232SMartin K. Petersen static int scsi_debug_guard = DEF_GUARD; 1735b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; 1741da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 17578d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; 176c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 1775b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0; 1785b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS; 1795b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 180e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS; 1815b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS; 1825b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; 1835b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 1845b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 1855b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 1865b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 1875b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 1885b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU; 1895b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS; 1905b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; 191be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ; 1926014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 1935b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; 1945b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 1955b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 1965b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; 197d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds static int scsi_debug_cmnd_count = 0; 2001da177e4SLinus Torvalds 2011da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 2021da177e4SLinus Torvalds 203c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 2041da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 2071da177e4SLinus Torvalds may still need them */ 2081da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 2091da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 2101da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 2131da177e4SLinus Torvalds 2141da177e4SLinus Torvalds #define SDEBUG_SENSE_LEN 32 2151da177e4SLinus Torvalds 216395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32 2179e603ca0SFUJITA Tomonori 2185b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void) 2195b94e232SMartin K. Petersen { 2205b94e232SMartin K. Petersen return scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10; 2215b94e232SMartin K. Petersen } 2225b94e232SMartin K. Petersen 2231da177e4SLinus Torvalds struct sdebug_dev_info { 2241da177e4SLinus Torvalds struct list_head dev_list; 2251da177e4SLinus Torvalds unsigned char sense_buff[SDEBUG_SENSE_LEN]; /* weak nexus */ 2261da177e4SLinus Torvalds unsigned int channel; 2271da177e4SLinus Torvalds unsigned int target; 2281da177e4SLinus Torvalds unsigned int lun; 2291da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 230c65b1445SDouglas Gilbert unsigned int wlun; 2311da177e4SLinus Torvalds char reset; 232c65b1445SDouglas Gilbert char stopped; 2331da177e4SLinus Torvalds char used; 2341da177e4SLinus Torvalds }; 2351da177e4SLinus Torvalds 2361da177e4SLinus Torvalds struct sdebug_host_info { 2371da177e4SLinus Torvalds struct list_head host_list; 2381da177e4SLinus Torvalds struct Scsi_Host *shost; 2391da177e4SLinus Torvalds struct device dev; 2401da177e4SLinus Torvalds struct list_head dev_info_list; 2411da177e4SLinus Torvalds }; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds #define to_sdebug_host(d) \ 2441da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 2451da177e4SLinus Torvalds 2461da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 2471da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 2481da177e4SLinus Torvalds 2491da177e4SLinus Torvalds typedef void (* done_funct_t) (struct scsi_cmnd *); 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds struct sdebug_queued_cmd { 2521da177e4SLinus Torvalds int in_use; 2531da177e4SLinus Torvalds struct timer_list cmnd_timer; 2541da177e4SLinus Torvalds done_funct_t done_funct; 2551da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 2561da177e4SLinus Torvalds int scsi_result; 2571da177e4SLinus Torvalds }; 2581da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 261c6a44287SMartin K. Petersen static unsigned char *dif_storep; /* protection info */ 26244d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 2631da177e4SLinus Torvalds 26444d92694SMartin K. Petersen static unsigned long map_size; 2651da177e4SLinus Torvalds static int num_aborts = 0; 2661da177e4SLinus Torvalds static int num_dev_resets = 0; 2671da177e4SLinus Torvalds static int num_bus_resets = 0; 2681da177e4SLinus Torvalds static int num_host_resets = 0; 269c6a44287SMartin K. Petersen static int dix_writes; 270c6a44287SMartin K. Petersen static int dix_reads; 271c6a44287SMartin K. Petersen static int dif_errors; 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 2741da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds static char sdebug_proc_name[] = "scsi_debug"; 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 2791da177e4SLinus Torvalds 280c6a44287SMartin K. Petersen static inline sector_t dif_offset(sector_t sector) 281c6a44287SMartin K. Petersen { 282c6a44287SMartin K. Petersen return sector << 3; 283c6a44287SMartin K. Petersen } 284c6a44287SMartin K. Petersen 2851da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 2861da177e4SLinus Torvalds .name = sdebug_proc_name, 2871da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 2881da177e4SLinus Torvalds }; 2891da177e4SLinus Torvalds 2901da177e4SLinus Torvalds static const int check_condition_result = 2911da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 2921da177e4SLinus Torvalds 293c6a44287SMartin K. Petersen static const int illegal_condition_result = 294c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 295c6a44287SMartin K. Petersen 296c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 297c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 298c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 299c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 300c65b1445SDouglas Gilbert 3011da177e4SLinus Torvalds static int sdebug_add_adapter(void); 3021da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 3031da177e4SLinus Torvalds 3048dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 3058dea0d02SFUJITA Tomonori { 3068dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 3078dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 3088dea0d02SFUJITA Tomonori 3098dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 3108dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3118dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 3128dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 3138dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 3148dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 3158dea0d02SFUJITA Tomonori else 3168dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 3178dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 3188dea0d02SFUJITA Tomonori hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; 3198dea0d02SFUJITA Tomonori } 3208dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 3218dea0d02SFUJITA Tomonori } 3228dea0d02SFUJITA Tomonori 3238dea0d02SFUJITA Tomonori static void mk_sense_buffer(struct sdebug_dev_info *devip, int key, 3248dea0d02SFUJITA Tomonori int asc, int asq) 3258dea0d02SFUJITA Tomonori { 3268dea0d02SFUJITA Tomonori unsigned char *sbuff; 3278dea0d02SFUJITA Tomonori 3288dea0d02SFUJITA Tomonori sbuff = devip->sense_buff; 3298dea0d02SFUJITA Tomonori memset(sbuff, 0, SDEBUG_SENSE_LEN); 3308dea0d02SFUJITA Tomonori 3318dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 3328dea0d02SFUJITA Tomonori 3338dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3348dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: [sense_key,asc,ascq]: " 3358dea0d02SFUJITA Tomonori "[0x%x,0x%x,0x%x]\n", key, asc, asq); 3368dea0d02SFUJITA Tomonori } 3371da177e4SLinus Torvalds 3383de9f944SFUJITA Tomonori static void get_data_transfer_info(unsigned char *cmd, 339395cef03SMartin K. Petersen unsigned long long *lba, unsigned int *num, 340395cef03SMartin K. Petersen u32 *ei_lba) 3413de9f944SFUJITA Tomonori { 342395cef03SMartin K. Petersen *ei_lba = 0; 343395cef03SMartin K. Petersen 3443de9f944SFUJITA Tomonori switch (*cmd) { 345395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 346395cef03SMartin K. Petersen *lba = (u64)cmd[19] | (u64)cmd[18] << 8 | 347395cef03SMartin K. Petersen (u64)cmd[17] << 16 | (u64)cmd[16] << 24 | 348395cef03SMartin K. Petersen (u64)cmd[15] << 32 | (u64)cmd[14] << 40 | 349395cef03SMartin K. Petersen (u64)cmd[13] << 48 | (u64)cmd[12] << 56; 350395cef03SMartin K. Petersen 351395cef03SMartin K. Petersen *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 | 352395cef03SMartin K. Petersen (u32)cmd[21] << 16 | (u32)cmd[20] << 24; 353395cef03SMartin K. Petersen 354395cef03SMartin K. Petersen *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 | 355395cef03SMartin K. Petersen (u32)cmd[28] << 24; 356395cef03SMartin K. Petersen break; 357395cef03SMartin K. Petersen 35844d92694SMartin K. Petersen case WRITE_SAME_16: 3593de9f944SFUJITA Tomonori case WRITE_16: 3603de9f944SFUJITA Tomonori case READ_16: 361d5cdc989SFUJITA Tomonori *lba = (u64)cmd[9] | (u64)cmd[8] << 8 | 362d5cdc989SFUJITA Tomonori (u64)cmd[7] << 16 | (u64)cmd[6] << 24 | 363d5cdc989SFUJITA Tomonori (u64)cmd[5] << 32 | (u64)cmd[4] << 40 | 364d5cdc989SFUJITA Tomonori (u64)cmd[3] << 48 | (u64)cmd[2] << 56; 365d5cdc989SFUJITA Tomonori 366d5cdc989SFUJITA Tomonori *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 | 367d5cdc989SFUJITA Tomonori (u32)cmd[10] << 24; 3683de9f944SFUJITA Tomonori break; 3693de9f944SFUJITA Tomonori case WRITE_12: 3703de9f944SFUJITA Tomonori case READ_12: 371d5cdc989SFUJITA Tomonori *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 | 372d5cdc989SFUJITA Tomonori (u32)cmd[2] << 24; 373d5cdc989SFUJITA Tomonori 374d5cdc989SFUJITA Tomonori *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 | 375d5cdc989SFUJITA Tomonori (u32)cmd[6] << 24; 3763de9f944SFUJITA Tomonori break; 37744d92694SMartin K. Petersen case WRITE_SAME: 3783de9f944SFUJITA Tomonori case WRITE_10: 3793de9f944SFUJITA Tomonori case READ_10: 380c639d14eSFUJITA Tomonori case XDWRITEREAD_10: 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[8] | (u32)cmd[7] << 8; 3853de9f944SFUJITA Tomonori break; 3863de9f944SFUJITA Tomonori case WRITE_6: 3873de9f944SFUJITA Tomonori case READ_6: 388d5cdc989SFUJITA Tomonori *lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 389d5cdc989SFUJITA Tomonori (u32)(cmd[1] & 0x1f) << 16; 3903de9f944SFUJITA Tomonori *num = (0 == cmd[4]) ? 256 : cmd[4]; 3913de9f944SFUJITA Tomonori break; 3923de9f944SFUJITA Tomonori default: 3933de9f944SFUJITA Tomonori break; 3943de9f944SFUJITA Tomonori } 3953de9f944SFUJITA Tomonori } 3961da177e4SLinus Torvalds 3971da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 3981da177e4SLinus Torvalds { 3991da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 4001da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd); 4011da177e4SLinus Torvalds } 4021da177e4SLinus Torvalds return -EINVAL; 4031da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 406c65b1445SDouglas Gilbert static int check_readiness(struct scsi_cmnd * SCpnt, int reset_only, 407c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 4081da177e4SLinus Torvalds { 4091da177e4SLinus Torvalds if (devip->reset) { 4101da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4111da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: Reporting Unit " 4121da177e4SLinus Torvalds "attention: power on reset\n"); 4131da177e4SLinus Torvalds devip->reset = 0; 4141da177e4SLinus Torvalds mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0); 4151da177e4SLinus Torvalds return check_condition_result; 4161da177e4SLinus Torvalds } 417c65b1445SDouglas Gilbert if ((0 == reset_only) && devip->stopped) { 418c65b1445SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 419c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: Reporting Not " 420c65b1445SDouglas Gilbert "ready: initializing command required\n"); 421c65b1445SDouglas Gilbert mk_sense_buffer(devip, NOT_READY, LOGICAL_UNIT_NOT_READY, 422c65b1445SDouglas Gilbert 0x2); 423c65b1445SDouglas Gilbert return check_condition_result; 424c65b1445SDouglas Gilbert } 4251da177e4SLinus Torvalds return 0; 4261da177e4SLinus Torvalds } 4271da177e4SLinus Torvalds 4281da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 4291da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 4301da177e4SLinus Torvalds int arr_len) 4311da177e4SLinus Torvalds { 43221a61829SFUJITA Tomonori int act_len; 433072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 4341da177e4SLinus Torvalds 435072d0bb3SFUJITA Tomonori if (!sdb->length) 4361da177e4SLinus Torvalds return 0; 437072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 4381da177e4SLinus Torvalds return (DID_ERROR << 16); 43921a61829SFUJITA Tomonori 44021a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 44121a61829SFUJITA Tomonori arr, arr_len); 442072d0bb3SFUJITA Tomonori if (sdb->resid) 443072d0bb3SFUJITA Tomonori sdb->resid -= act_len; 444c65b1445SDouglas Gilbert else 44521a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 44621a61829SFUJITA Tomonori 4471da177e4SLinus Torvalds return 0; 4481da177e4SLinus Torvalds } 4491da177e4SLinus Torvalds 4501da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 4511da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 45221a61829SFUJITA Tomonori int arr_len) 4531da177e4SLinus Torvalds { 45421a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 4551da177e4SLinus Torvalds return 0; 456072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 4571da177e4SLinus Torvalds return -1; 45821a61829SFUJITA Tomonori 45921a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 4601da177e4SLinus Torvalds } 4611da177e4SLinus Torvalds 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 4641da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 4651da177e4SLinus Torvalds static const char * inq_product_rev = "0004"; 4661da177e4SLinus Torvalds 4675a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 4685a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 4695a09e398SHannes Reinecke const char * dev_id_str, 470c65b1445SDouglas Gilbert int dev_id_str_len) 4711da177e4SLinus Torvalds { 472c65b1445SDouglas Gilbert int num, port_a; 473c65b1445SDouglas Gilbert char b[32]; 4741da177e4SLinus Torvalds 475c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 4761da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 4771da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 4781da177e4SLinus Torvalds arr[1] = 0x1; 4791da177e4SLinus Torvalds arr[2] = 0x0; 4801da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 4811da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 4821da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 4831da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 4841da177e4SLinus Torvalds arr[3] = num; 4851da177e4SLinus Torvalds num += 4; 486c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 487c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 488c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 489c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 490c65b1445SDouglas Gilbert arr[num++] = 0x0; 491c65b1445SDouglas Gilbert arr[num++] = 0x8; 492c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 493c65b1445SDouglas Gilbert arr[num++] = 0x33; 494c65b1445SDouglas Gilbert arr[num++] = 0x33; 495c65b1445SDouglas Gilbert arr[num++] = 0x30; 496c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 497c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 498c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 499c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 500c65b1445SDouglas Gilbert /* Target relative port number */ 501c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 502c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 503c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 504c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 505c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 506c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 507c65b1445SDouglas Gilbert arr[num++] = 0x0; 508c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 509c65b1445SDouglas Gilbert } 510c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 511c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 512c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 513c65b1445SDouglas Gilbert arr[num++] = 0x0; 514c65b1445SDouglas Gilbert arr[num++] = 0x8; 515c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 516c65b1445SDouglas Gilbert arr[num++] = 0x22; 517c65b1445SDouglas Gilbert arr[num++] = 0x22; 518c65b1445SDouglas Gilbert arr[num++] = 0x20; 519c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 520c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 521c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 522c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 5235a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 5245a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 5255a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 5265a09e398SHannes Reinecke arr[num++] = 0x0; 5275a09e398SHannes Reinecke arr[num++] = 0x4; 5285a09e398SHannes Reinecke arr[num++] = 0; 5295a09e398SHannes Reinecke arr[num++] = 0; 5305a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 5315a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 532c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 533c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 534c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 535c65b1445SDouglas Gilbert arr[num++] = 0x0; 536c65b1445SDouglas Gilbert arr[num++] = 0x8; 537c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 538c65b1445SDouglas Gilbert arr[num++] = 0x22; 539c65b1445SDouglas Gilbert arr[num++] = 0x22; 540c65b1445SDouglas Gilbert arr[num++] = 0x20; 541c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 542c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 543c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 544c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 545c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 546c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 547c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 548c65b1445SDouglas Gilbert arr[num++] = 0x0; 549c65b1445SDouglas Gilbert arr[num++] = 24; 550c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 551c65b1445SDouglas Gilbert num += 12; 552c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 553c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 554c65b1445SDouglas Gilbert num += 8; 555c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 556c65b1445SDouglas Gilbert num += 4; 557c65b1445SDouglas Gilbert return num; 558c65b1445SDouglas Gilbert } 559c65b1445SDouglas Gilbert 560c65b1445SDouglas Gilbert 561c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 562c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 563c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 564c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 565c65b1445SDouglas Gilbert }; 566c65b1445SDouglas Gilbert 567c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 568c65b1445SDouglas Gilbert { 569c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 570c65b1445SDouglas Gilbert return sizeof(vpd84_data); 571c65b1445SDouglas Gilbert } 572c65b1445SDouglas Gilbert 573c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 574c65b1445SDouglas Gilbert { 575c65b1445SDouglas Gilbert int num = 0; 576c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 577c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 578c65b1445SDouglas Gilbert int plen, olen; 579c65b1445SDouglas Gilbert 580c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 581c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 582c65b1445SDouglas Gilbert arr[num++] = 0x0; 583c65b1445SDouglas Gilbert olen = strlen(na1); 584c65b1445SDouglas Gilbert plen = olen + 1; 585c65b1445SDouglas Gilbert if (plen % 4) 586c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 587c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 588c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 589c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 590c65b1445SDouglas Gilbert num += plen; 591c65b1445SDouglas Gilbert 592c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 593c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 594c65b1445SDouglas Gilbert arr[num++] = 0x0; 595c65b1445SDouglas Gilbert olen = strlen(na2); 596c65b1445SDouglas Gilbert plen = olen + 1; 597c65b1445SDouglas Gilbert if (plen % 4) 598c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 599c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 600c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 601c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 602c65b1445SDouglas Gilbert num += plen; 603c65b1445SDouglas Gilbert 604c65b1445SDouglas Gilbert return num; 605c65b1445SDouglas Gilbert } 606c65b1445SDouglas Gilbert 607c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 608c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 609c65b1445SDouglas Gilbert { 610c65b1445SDouglas Gilbert int num = 0; 611c65b1445SDouglas Gilbert int port_a, port_b; 612c65b1445SDouglas Gilbert 613c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 614c65b1445SDouglas Gilbert port_b = port_a + 1; 615c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 616c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 617c65b1445SDouglas Gilbert arr[num++] = 0x0; 618c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 619c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 620c65b1445SDouglas Gilbert num += 6; 621c65b1445SDouglas Gilbert arr[num++] = 0x0; 622c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 623c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 624c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 625c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 626c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 627c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 628c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 629c65b1445SDouglas Gilbert arr[num++] = 0x22; 630c65b1445SDouglas Gilbert arr[num++] = 0x22; 631c65b1445SDouglas Gilbert arr[num++] = 0x20; 632c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 633c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 634c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 635c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 636c65b1445SDouglas Gilbert 637c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 638c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 639c65b1445SDouglas Gilbert arr[num++] = 0x0; 640c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 641c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 642c65b1445SDouglas Gilbert num += 6; 643c65b1445SDouglas Gilbert arr[num++] = 0x0; 644c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 645c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 646c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 647c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 648c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 649c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 650c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 651c65b1445SDouglas Gilbert arr[num++] = 0x22; 652c65b1445SDouglas Gilbert arr[num++] = 0x22; 653c65b1445SDouglas Gilbert arr[num++] = 0x20; 654c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 655c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 656c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 657c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 658c65b1445SDouglas Gilbert 659c65b1445SDouglas Gilbert return num; 660c65b1445SDouglas Gilbert } 661c65b1445SDouglas Gilbert 662c65b1445SDouglas Gilbert 663c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 664c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 665c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 666c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 667c65b1445SDouglas Gilbert '1','2','3','4', 668c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 669c65b1445SDouglas Gilbert 0xec,0,0,0, 670c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 671c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 672c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 673c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 674c65b1445SDouglas Gilbert 0x53,0x41, 675c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 676c65b1445SDouglas Gilbert 0x20,0x20, 677c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 678c65b1445SDouglas Gilbert 0x10,0x80, 679c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 680c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 681c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 682c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 683c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 684c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 685c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 686c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 687c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 688c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 689c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 690c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 691c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 692c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 697c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 698c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 699c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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,0xa5,0x51, 705c65b1445SDouglas Gilbert }; 706c65b1445SDouglas Gilbert 707c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 708c65b1445SDouglas Gilbert { 709c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 710c65b1445SDouglas Gilbert return sizeof(vpd89_data); 711c65b1445SDouglas Gilbert } 712c65b1445SDouglas Gilbert 713c65b1445SDouglas Gilbert 7141e49f785SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 715c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 7161e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 7171e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7181e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 7191e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 720c65b1445SDouglas Gilbert }; 721c65b1445SDouglas Gilbert 722c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 723c65b1445SDouglas Gilbert { 724ea61fca5SMartin K. Petersen unsigned int gran; 725ea61fca5SMartin K. Petersen 726c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 727e308b3d1SMartin K. Petersen 728e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 729ea61fca5SMartin K. Petersen gran = 1 << scsi_debug_physblk_exp; 730ea61fca5SMartin K. Petersen arr[2] = (gran >> 8) & 0xff; 731ea61fca5SMartin K. Petersen arr[3] = gran & 0xff; 732e308b3d1SMartin K. Petersen 733e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 734c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 735c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 736c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 737c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 738c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 739c65b1445SDouglas Gilbert } 74044d92694SMartin K. Petersen 741e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 742e308b3d1SMartin K. Petersen put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); 743e308b3d1SMartin K. Petersen 7445b94e232SMartin K. Petersen if (scsi_debug_lbpu) { 745e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 7466014759cSMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); 747e308b3d1SMartin K. Petersen 748e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 74944d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); 75044d92694SMartin K. Petersen } 75144d92694SMartin K. Petersen 752e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 75344d92694SMartin K. Petersen if (scsi_debug_unmap_alignment) { 75444d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); 75544d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 75644d92694SMartin K. Petersen } 75744d92694SMartin K. Petersen 758e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 75944d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); 7606014759cSMartin K. Petersen 7615b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 7625b94e232SMartin K. Petersen put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); 7635b94e232SMartin K. Petersen 7645b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 76544d92694SMartin K. Petersen 766c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 7671da177e4SLinus Torvalds } 7681da177e4SLinus Torvalds 7691e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 770eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 771eac6e8e4SMatthew Wilcox { 772eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 773eac6e8e4SMatthew Wilcox arr[0] = 0; 7741e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 7751e49f785SDouglas Gilbert arr[2] = 0; 7761e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 777eac6e8e4SMatthew Wilcox 778eac6e8e4SMatthew Wilcox return 0x3c; 779eac6e8e4SMatthew Wilcox } 7801da177e4SLinus Torvalds 781be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */ 7826014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 7836014759cSMartin K. Petersen { 7843f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 7856014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 7866014759cSMartin K. Petersen 7875b94e232SMartin K. Petersen if (scsi_debug_lbpu) 7886014759cSMartin K. Petersen arr[1] = 1 << 7; 7896014759cSMartin K. Petersen 7905b94e232SMartin K. Petersen if (scsi_debug_lbpws) 7916014759cSMartin K. Petersen arr[1] |= 1 << 6; 7926014759cSMartin K. Petersen 7935b94e232SMartin K. Petersen if (scsi_debug_lbpws10) 7945b94e232SMartin K. Petersen arr[1] |= 1 << 5; 7955b94e232SMartin K. Petersen 796be1dd78dSEric Sandeen if (scsi_debug_lbprz) 797be1dd78dSEric Sandeen arr[1] |= 1 << 2; 798be1dd78dSEric Sandeen 7993f0bc3b3SMartin K. Petersen return 0x4; 8006014759cSMartin K. Petersen } 8016014759cSMartin K. Petersen 8021da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 803c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 8041da177e4SLinus Torvalds 8051da177e4SLinus Torvalds static int resp_inquiry(struct scsi_cmnd * scp, int target, 8061da177e4SLinus Torvalds struct sdebug_dev_info * devip) 8071da177e4SLinus Torvalds { 8081da177e4SLinus Torvalds unsigned char pq_pdt; 8095a09e398SHannes Reinecke unsigned char * arr; 8101da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 8115a09e398SHannes Reinecke int alloc_len, n, ret; 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 8146f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 8156f3cbf55SDouglas Gilbert if (! arr) 8166f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 817c65b1445SDouglas Gilbert if (devip->wlun) 818c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 819c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 820c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 821c65b1445SDouglas Gilbert else 8221da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 8231da177e4SLinus Torvalds arr[0] = pq_pdt; 8241da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 8251da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 8261da177e4SLinus Torvalds 0); 8275a09e398SHannes Reinecke kfree(arr); 8281da177e4SLinus Torvalds return check_condition_result; 8291da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 8305a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 831c65b1445SDouglas Gilbert char lu_id_str[6]; 832c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 8331da177e4SLinus Torvalds 8345a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 8355a09e398SHannes Reinecke (devip->channel & 0x7f); 83623183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 83723183910SDouglas Gilbert host_no = 0; 838c65b1445SDouglas Gilbert lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) + 839c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 840c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 841c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 842c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 8431da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 844c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 845c65b1445SDouglas Gilbert n = 4; 846c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 847c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 848c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 849c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 850c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 851c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 852c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 853c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 854c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 855c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 856eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 8575b94e232SMartin K. Petersen if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ 8585b94e232SMartin K. Petersen arr[n++] = 0xb2; 859c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 8601da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 861c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8621da177e4SLinus Torvalds arr[3] = len; 863c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 8641da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 865c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 8665a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 8675a09e398SHannes Reinecke target_dev_id, lu_id_num, 8685a09e398SHannes Reinecke lu_id_str, len); 869c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 870c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 871c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 872c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 873c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 874c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 875c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 876c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 877c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 878c6a44287SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) 879c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 880c6a44287SMartin K. Petersen else if (scsi_debug_dif) 881c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 882c6a44287SMartin K. Petersen else 883c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 884c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 885c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 886c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 887c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 888c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 889c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 890c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 891c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 892c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 893c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 894c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 895c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 896c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 897c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 898c65b1445SDouglas Gilbert arr[2] = (n >> 8); 899c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 900c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 901c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 902c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 903eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 904eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 905eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 9065b94e232SMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ 9076014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 9086014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 9091da177e4SLinus Torvalds } else { 9101da177e4SLinus Torvalds /* Illegal request, invalid field in cdb */ 9111da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, 9121da177e4SLinus Torvalds INVALID_FIELD_IN_CDB, 0); 9135a09e398SHannes Reinecke kfree(arr); 9141da177e4SLinus Torvalds return check_condition_result; 9151da177e4SLinus Torvalds } 916c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 9175a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 918c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 9195a09e398SHannes Reinecke kfree(arr); 9205a09e398SHannes Reinecke return ret; 9211da177e4SLinus Torvalds } 9221da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 923d986788bSMartin Pitt arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */ 9241da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 9251da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 9261da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 927c6a44287SMartin K. Petersen arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ 9285a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 9295a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 930c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 9311da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 932c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 9331da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 9341da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 9351da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 9361da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 937c65b1445SDouglas Gilbert arr[58] = 0x0; arr[59] = 0x77; /* SAM-3 ANSI */ 938c65b1445SDouglas Gilbert arr[60] = 0x3; arr[61] = 0x14; /* SPC-3 ANSI */ 939c65b1445SDouglas Gilbert n = 62; 9401da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 941c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x3d; /* SBC-2 ANSI */ 9421da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 943c65b1445SDouglas Gilbert arr[n++] = 0x3; arr[n++] = 0x60; /* SSC-2 no version */ 9441da177e4SLinus Torvalds } 945c65b1445SDouglas Gilbert arr[n++] = 0xc; arr[n++] = 0xf; /* SAS-1.1 rev 10 */ 9465a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 9471da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 9485a09e398SHannes Reinecke kfree(arr); 9495a09e398SHannes Reinecke return ret; 9501da177e4SLinus Torvalds } 9511da177e4SLinus Torvalds 9521da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 9531da177e4SLinus Torvalds struct sdebug_dev_info * devip) 9541da177e4SLinus Torvalds { 9551da177e4SLinus Torvalds unsigned char * sbuff; 9561da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 9571da177e4SLinus Torvalds unsigned char arr[SDEBUG_SENSE_LEN]; 958c65b1445SDouglas Gilbert int want_dsense; 9591da177e4SLinus Torvalds int len = 18; 9601da177e4SLinus Torvalds 961c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9621da177e4SLinus Torvalds if (devip->reset == 1) 963c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 964c65b1445SDouglas Gilbert want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense; 9651da177e4SLinus Torvalds sbuff = devip->sense_buff; 966c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 967c65b1445SDouglas Gilbert if (want_dsense) { 968c65b1445SDouglas Gilbert arr[0] = 0x72; 969c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 970c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 971c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 972c65b1445SDouglas Gilbert } else { 973c65b1445SDouglas Gilbert arr[0] = 0x70; 974c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 975c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 976c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 977c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 978c65b1445SDouglas Gilbert } 979c65b1445SDouglas Gilbert } else { 980c65b1445SDouglas Gilbert memcpy(arr, sbuff, SDEBUG_SENSE_LEN); 9811da177e4SLinus Torvalds if ((cmd[1] & 1) && (! scsi_debug_dsense)) { 9821da177e4SLinus Torvalds /* DESC bit set and sense_buff in fixed format */ 983c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 9841da177e4SLinus Torvalds arr[0] = 0x72; 9851da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 9861da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 9871da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 9881da177e4SLinus Torvalds len = 8; 989c65b1445SDouglas Gilbert } 990c65b1445SDouglas Gilbert } 991c65b1445SDouglas Gilbert mk_sense_buffer(devip, 0, NO_ADDITIONAL_SENSE, 0); 9921da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 9931da177e4SLinus Torvalds } 9941da177e4SLinus Torvalds 995c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 996c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 997c65b1445SDouglas Gilbert { 998c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 999c65b1445SDouglas Gilbert int power_cond, errsts, start; 1000c65b1445SDouglas Gilbert 1001c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1002c65b1445SDouglas Gilbert return errsts; 1003c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1004c65b1445SDouglas Gilbert if (power_cond) { 1005c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 1006c65b1445SDouglas Gilbert 0); 1007c65b1445SDouglas Gilbert return check_condition_result; 1008c65b1445SDouglas Gilbert } 1009c65b1445SDouglas Gilbert start = cmd[4] & 1; 1010c65b1445SDouglas Gilbert if (start == devip->stopped) 1011c65b1445SDouglas Gilbert devip->stopped = !start; 1012c65b1445SDouglas Gilbert return 0; 1013c65b1445SDouglas Gilbert } 1014c65b1445SDouglas Gilbert 101528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 101628898873SFUJITA Tomonori { 101728898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 10185447ed6cSDouglas Gilbert return (sector_t)scsi_debug_virtual_gb * 10195447ed6cSDouglas Gilbert (1073741824 / scsi_debug_sector_size); 102028898873SFUJITA Tomonori else 102128898873SFUJITA Tomonori return sdebug_store_sectors; 102228898873SFUJITA Tomonori } 102328898873SFUJITA Tomonori 10241da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 10251da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 10261da177e4SLinus Torvalds struct sdebug_dev_info * devip) 10271da177e4SLinus Torvalds { 10281da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1029c65b1445SDouglas Gilbert unsigned int capac; 10301da177e4SLinus Torvalds int errsts; 10311da177e4SLinus Torvalds 1032c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 10331da177e4SLinus Torvalds return errsts; 1034c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 103528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 10361da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1037c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1038c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 10391da177e4SLinus Torvalds arr[0] = (capac >> 24); 10401da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 10411da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 10421da177e4SLinus Torvalds arr[3] = capac & 0xff; 1043c65b1445SDouglas Gilbert } else { 1044c65b1445SDouglas Gilbert arr[0] = 0xff; 1045c65b1445SDouglas Gilbert arr[1] = 0xff; 1046c65b1445SDouglas Gilbert arr[2] = 0xff; 1047c65b1445SDouglas Gilbert arr[3] = 0xff; 1048c65b1445SDouglas Gilbert } 1049597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 1050597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 10511da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 10521da177e4SLinus Torvalds } 10531da177e4SLinus Torvalds 1054c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1055c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1056c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1057c65b1445SDouglas Gilbert { 1058c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1059c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1060c65b1445SDouglas Gilbert unsigned long long capac; 1061c65b1445SDouglas Gilbert int errsts, k, alloc_len; 1062c65b1445SDouglas Gilbert 1063c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1064c65b1445SDouglas Gilbert return errsts; 1065c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1066c65b1445SDouglas Gilbert + cmd[13]); 1067c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 106828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1069c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1070c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1071c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1072c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1073597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 1074597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 1075597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 1076597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 1077ea61fca5SMartin K. Petersen arr[13] = scsi_debug_physblk_exp & 0xf; 1078ea61fca5SMartin K. Petersen arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; 107944d92694SMartin K. Petersen 1080be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 10815b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1082be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1083be1dd78dSEric Sandeen arr[14] |= 0x40; /* LBPRZ */ 1084be1dd78dSEric Sandeen } 108544d92694SMartin K. Petersen 1086ea61fca5SMartin K. Petersen arr[15] = scsi_debug_lowest_aligned & 0xff; 1087c6a44287SMartin K. Petersen 1088c6a44287SMartin K. Petersen if (scsi_debug_dif) { 1089c6a44287SMartin K. Petersen arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ 1090c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1091c6a44287SMartin K. Petersen } 1092c6a44287SMartin K. Petersen 1093c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1094c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1095c65b1445SDouglas Gilbert } 1096c65b1445SDouglas Gilbert 10975a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 10985a09e398SHannes Reinecke 10995a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 11005a09e398SHannes Reinecke struct sdebug_dev_info * devip) 11015a09e398SHannes Reinecke { 11025a09e398SHannes Reinecke unsigned char *cmd = (unsigned char *)scp->cmnd; 11035a09e398SHannes Reinecke unsigned char * arr; 11045a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 11055a09e398SHannes Reinecke int n, ret, alen, rlen; 11065a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 11075a09e398SHannes Reinecke 11085a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 11095a09e398SHannes Reinecke + cmd[9]); 11105a09e398SHannes Reinecke 11116f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 11126f3cbf55SDouglas Gilbert if (! arr) 11136f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 11145a09e398SHannes Reinecke /* 11155a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 11165a09e398SHannes Reinecke * real and a fake port with no device connected. 11175a09e398SHannes Reinecke * So we create two port groups with one port each 11185a09e398SHannes Reinecke * and set the group with port B to unavailable. 11195a09e398SHannes Reinecke */ 11205a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 11215a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 11225a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 11235a09e398SHannes Reinecke (devip->channel & 0x7f); 11245a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 11255a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 11265a09e398SHannes Reinecke 11275a09e398SHannes Reinecke /* 11285a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 11295a09e398SHannes Reinecke */ 11305a09e398SHannes Reinecke n = 4; 11315a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 11325a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 11335a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 11345a09e398SHannes Reinecke } else { 11355a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 11365a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 11375a09e398SHannes Reinecke } 11385a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 11395a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 11405a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11415a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11425a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11435a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11445a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11455a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11465a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 11475a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 11485a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 11495a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 11505a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 11515a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 11525a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11535a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 11545a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 11555a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 11565a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11575a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 11585a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 11595a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 11605a09e398SHannes Reinecke 11615a09e398SHannes Reinecke rlen = n - 4; 11625a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 11635a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 11645a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 11655a09e398SHannes Reinecke arr[3] = rlen & 0xff; 11665a09e398SHannes Reinecke 11675a09e398SHannes Reinecke /* 11685a09e398SHannes Reinecke * Return the smallest value of either 11695a09e398SHannes Reinecke * - The allocated length 11705a09e398SHannes Reinecke * - The constructed command length 11715a09e398SHannes Reinecke * - The maximum array size 11725a09e398SHannes Reinecke */ 11735a09e398SHannes Reinecke rlen = min(alen,n); 11745a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 11755a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 11765a09e398SHannes Reinecke kfree(arr); 11775a09e398SHannes Reinecke return ret; 11785a09e398SHannes Reinecke } 11795a09e398SHannes Reinecke 11801da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 11811da177e4SLinus Torvalds 11821da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 11831da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 11841da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 11851da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 11861da177e4SLinus Torvalds 11871da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 11881da177e4SLinus Torvalds if (1 == pcontrol) 11891da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 11901da177e4SLinus Torvalds return sizeof(err_recov_pg); 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds 11931da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 11941da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 11951da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 11961da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 11971da177e4SLinus Torvalds 11981da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 11991da177e4SLinus Torvalds if (1 == pcontrol) 12001da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 12011da177e4SLinus Torvalds return sizeof(disconnect_pg); 12021da177e4SLinus Torvalds } 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 12051da177e4SLinus Torvalds { /* Format device page for mode_sense */ 12061da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 12071da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 12081da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 12111da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 12121da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1213597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1214597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 1215d986788bSMartin Pitt if (scsi_debug_removable) 12161da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 12171da177e4SLinus Torvalds if (1 == pcontrol) 12181da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 12191da177e4SLinus Torvalds return sizeof(format_pg); 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 12231da177e4SLinus Torvalds { /* Caching page for mode_sense */ 12241da177e4SLinus Torvalds unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 12251da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 12261da177e4SLinus Torvalds 12271da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 12281da177e4SLinus Torvalds if (1 == pcontrol) 12291da177e4SLinus Torvalds memset(p + 2, 0, sizeof(caching_pg) - 2); 12301da177e4SLinus Torvalds return sizeof(caching_pg); 12311da177e4SLinus Torvalds } 12321da177e4SLinus Torvalds 12331da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 12341da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1235c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1236c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1237c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 12381da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 12391da177e4SLinus Torvalds 12401da177e4SLinus Torvalds if (scsi_debug_dsense) 12411da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1242c65b1445SDouglas Gilbert else 1243c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1244c6a44287SMartin K. Petersen 1245c6a44287SMartin K. Petersen if (scsi_debug_ato) 1246c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1247c6a44287SMartin K. Petersen 12481da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 12491da177e4SLinus Torvalds if (1 == pcontrol) 1250c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1251c65b1445SDouglas Gilbert else if (2 == pcontrol) 1252c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 12531da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 12541da177e4SLinus Torvalds } 12551da177e4SLinus Torvalds 1256c65b1445SDouglas Gilbert 12571da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 12581da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1259c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 12601da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1261c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1262c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1263c65b1445SDouglas Gilbert 12641da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 12651da177e4SLinus Torvalds if (1 == pcontrol) 1266c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1267c65b1445SDouglas Gilbert else if (2 == pcontrol) 1268c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 12691da177e4SLinus Torvalds return sizeof(iec_m_pg); 12701da177e4SLinus Torvalds } 12711da177e4SLinus Torvalds 1272c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1273c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1274c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1275c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1276c65b1445SDouglas Gilbert 1277c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1278c65b1445SDouglas Gilbert if (1 == pcontrol) 1279c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1280c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1281c65b1445SDouglas Gilbert } 1282c65b1445SDouglas Gilbert 1283c65b1445SDouglas Gilbert 1284c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1285c65b1445SDouglas Gilbert int target_dev_id) 1286c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1287c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1288c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1289c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1290c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1291c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1292c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1293c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1294c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1295c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1296c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1297c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1298c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1299c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1300c65b1445SDouglas Gilbert }; 1301c65b1445SDouglas Gilbert int port_a, port_b; 1302c65b1445SDouglas Gilbert 1303c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1304c65b1445SDouglas Gilbert port_b = port_a + 1; 1305c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1306c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1307c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1308c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1309c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1310c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1311c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1312c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1313c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1314c65b1445SDouglas Gilbert if (1 == pcontrol) 1315c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1316c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1317c65b1445SDouglas Gilbert } 1318c65b1445SDouglas Gilbert 1319c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1320c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1321c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1322c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1323c65b1445SDouglas Gilbert }; 1324c65b1445SDouglas Gilbert 1325c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1326c65b1445SDouglas Gilbert if (1 == pcontrol) 1327c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1328c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1329c65b1445SDouglas Gilbert } 1330c65b1445SDouglas Gilbert 13311da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds static int resp_mode_sense(struct scsi_cmnd * scp, int target, 13341da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13351da177e4SLinus Torvalds { 133623183910SDouglas Gilbert unsigned char dbd, llbaa; 133723183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 13381da177e4SLinus Torvalds unsigned char dev_spec; 133923183910SDouglas Gilbert int k, alloc_len, msense_6, offset, len, errsts, target_dev_id; 13401da177e4SLinus Torvalds unsigned char * ap; 13411da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 13421da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 13431da177e4SLinus Torvalds 1344c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 13451da177e4SLinus Torvalds return errsts; 134623183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 13471da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 13481da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 13491da177e4SLinus Torvalds subpcode = cmd[3]; 13501da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 135123183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 135223183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 135323183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 135423183910SDouglas Gilbert else 135523183910SDouglas Gilbert bd_len = 0; 13561da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 13571da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 13581da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 13591da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 13601da177e4SLinus Torvalds 0); 13611da177e4SLinus Torvalds return check_condition_result; 13621da177e4SLinus Torvalds } 1363c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1364c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 136523183910SDouglas Gilbert /* set DPOFUA bit for disks */ 136623183910SDouglas Gilbert if (0 == scsi_debug_ptype) 136723183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 136823183910SDouglas Gilbert else 136923183910SDouglas Gilbert dev_spec = 0x0; 13701da177e4SLinus Torvalds if (msense_6) { 13711da177e4SLinus Torvalds arr[2] = dev_spec; 137223183910SDouglas Gilbert arr[3] = bd_len; 13731da177e4SLinus Torvalds offset = 4; 13741da177e4SLinus Torvalds } else { 13751da177e4SLinus Torvalds arr[3] = dev_spec; 137623183910SDouglas Gilbert if (16 == bd_len) 137723183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 137823183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 13791da177e4SLinus Torvalds offset = 8; 13801da177e4SLinus Torvalds } 13811da177e4SLinus Torvalds ap = arr + offset; 138228898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 138328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 138428898873SFUJITA Tomonori 138523183910SDouglas Gilbert if (8 == bd_len) { 138623183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 138723183910SDouglas Gilbert ap[0] = 0xff; 138823183910SDouglas Gilbert ap[1] = 0xff; 138923183910SDouglas Gilbert ap[2] = 0xff; 139023183910SDouglas Gilbert ap[3] = 0xff; 139123183910SDouglas Gilbert } else { 139223183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 139323183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 139423183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 139523183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 139623183910SDouglas Gilbert } 1397597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 1398597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 139923183910SDouglas Gilbert offset += bd_len; 140023183910SDouglas Gilbert ap = arr + offset; 140123183910SDouglas Gilbert } else if (16 == bd_len) { 140223183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 140323183910SDouglas Gilbert 140423183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 140523183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 1406597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 1407597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 1408597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 1409597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 141023183910SDouglas Gilbert offset += bd_len; 141123183910SDouglas Gilbert ap = arr + offset; 141223183910SDouglas Gilbert } 14131da177e4SLinus Torvalds 1414c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1415c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 14161da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14171da177e4SLinus Torvalds 0); 14181da177e4SLinus Torvalds return check_condition_result; 14191da177e4SLinus Torvalds } 14201da177e4SLinus Torvalds switch (pcode) { 14211da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 14221da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14231da177e4SLinus Torvalds offset += len; 14241da177e4SLinus Torvalds break; 14251da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 14261da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 14271da177e4SLinus Torvalds offset += len; 14281da177e4SLinus Torvalds break; 14291da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 14301da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 14311da177e4SLinus Torvalds offset += len; 14321da177e4SLinus Torvalds break; 14331da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 14341da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 14351da177e4SLinus Torvalds offset += len; 14361da177e4SLinus Torvalds break; 14371da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 14381da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 14391da177e4SLinus Torvalds offset += len; 14401da177e4SLinus Torvalds break; 1441c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 1442c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 1443c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1444c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1445c65b1445SDouglas Gilbert return check_condition_result; 1446c65b1445SDouglas Gilbert } 1447c65b1445SDouglas Gilbert len = 0; 1448c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 1449c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1450c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 1451c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 1452c65b1445SDouglas Gilbert target_dev_id); 1453c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 1454c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1455c65b1445SDouglas Gilbert offset += len; 1456c65b1445SDouglas Gilbert break; 14571da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 14581da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 14591da177e4SLinus Torvalds offset += len; 14601da177e4SLinus Torvalds break; 14611da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 1462c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 14631da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 14641da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 14651da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 14661da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 14671da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 1468c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 1469c65b1445SDouglas Gilbert if (0xff == subpcode) { 1470c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 1471c65b1445SDouglas Gilbert target, target_dev_id); 1472c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 1473c65b1445SDouglas Gilbert } 14741da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 1475c65b1445SDouglas Gilbert } else { 1476c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1477c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1478c65b1445SDouglas Gilbert return check_condition_result; 1479c65b1445SDouglas Gilbert } 14801da177e4SLinus Torvalds offset += len; 14811da177e4SLinus Torvalds break; 14821da177e4SLinus Torvalds default: 14831da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 14841da177e4SLinus Torvalds 0); 14851da177e4SLinus Torvalds return check_condition_result; 14861da177e4SLinus Torvalds } 14871da177e4SLinus Torvalds if (msense_6) 14881da177e4SLinus Torvalds arr[0] = offset - 1; 14891da177e4SLinus Torvalds else { 14901da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 14911da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 14941da177e4SLinus Torvalds } 14951da177e4SLinus Torvalds 1496c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 1497c65b1445SDouglas Gilbert 1498c65b1445SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd * scp, int mselect6, 1499c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1500c65b1445SDouglas Gilbert { 1501c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 1502c65b1445SDouglas Gilbert int param_len, res, errsts, mpage; 1503c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 1504c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1505c65b1445SDouglas Gilbert 1506c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1507c65b1445SDouglas Gilbert return errsts; 1508c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1509c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 1510c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1511c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 1512c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 1513c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1514c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1515c65b1445SDouglas Gilbert return check_condition_result; 1516c65b1445SDouglas Gilbert } 1517c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 1518c65b1445SDouglas Gilbert if (-1 == res) 1519c65b1445SDouglas Gilbert return (DID_ERROR << 16); 1520c65b1445SDouglas Gilbert else if ((res < param_len) && 1521c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 1522c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: mode_select: cdb indicated=%d, " 1523c65b1445SDouglas Gilbert " IO sent=%d bytes\n", param_len, res); 1524c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 1525c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 152623183910SDouglas Gilbert if (md_len > 2) { 1527c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1528c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1529c65b1445SDouglas Gilbert return check_condition_result; 1530c65b1445SDouglas Gilbert } 1531c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 1532c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 1533c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 1534c65b1445SDouglas Gilbert if (ps) { 1535c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1536c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1537c65b1445SDouglas Gilbert return check_condition_result; 1538c65b1445SDouglas Gilbert } 1539c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 1540c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 1541c65b1445SDouglas Gilbert (arr[off + 1] + 2); 1542c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 1543c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1544c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 1545c65b1445SDouglas Gilbert return check_condition_result; 1546c65b1445SDouglas Gilbert } 1547c65b1445SDouglas Gilbert switch (mpage) { 1548c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 1549c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 1550c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 1551c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 1552c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 1553c65b1445SDouglas Gilbert return 0; 1554c65b1445SDouglas Gilbert } 1555c65b1445SDouglas Gilbert break; 1556c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 1557c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 1558c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 1559c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 1560c65b1445SDouglas Gilbert return 0; 1561c65b1445SDouglas Gilbert } 1562c65b1445SDouglas Gilbert break; 1563c65b1445SDouglas Gilbert default: 1564c65b1445SDouglas Gilbert break; 1565c65b1445SDouglas Gilbert } 1566c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1567c65b1445SDouglas Gilbert INVALID_FIELD_IN_PARAM_LIST, 0); 1568c65b1445SDouglas Gilbert return check_condition_result; 1569c65b1445SDouglas Gilbert } 1570c65b1445SDouglas Gilbert 1571c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 1572c65b1445SDouglas Gilbert { 1573c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 1574c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 1575c65b1445SDouglas Gilbert }; 1576c65b1445SDouglas Gilbert 1577c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 1578c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 1579c65b1445SDouglas Gilbert } 1580c65b1445SDouglas Gilbert 1581c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 1582c65b1445SDouglas Gilbert { 1583c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 1584c65b1445SDouglas Gilbert }; 1585c65b1445SDouglas Gilbert 1586c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 1587c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 1588c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 1589c65b1445SDouglas Gilbert arr[5] = 0xff; 1590c65b1445SDouglas Gilbert } 1591c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 1592c65b1445SDouglas Gilbert } 1593c65b1445SDouglas Gilbert 1594c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 1595c65b1445SDouglas Gilbert 1596c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 1597c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1598c65b1445SDouglas Gilbert { 159923183910SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n; 1600c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 1601c65b1445SDouglas Gilbert unsigned char *cmd = (unsigned char *)scp->cmnd; 1602c65b1445SDouglas Gilbert 1603c65b1445SDouglas Gilbert if ((errsts = check_readiness(scp, 1, devip))) 1604c65b1445SDouglas Gilbert return errsts; 1605c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1606c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 1607c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 1608c65b1445SDouglas Gilbert if (ppc || sp) { 1609c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1610c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1611c65b1445SDouglas Gilbert return check_condition_result; 1612c65b1445SDouglas Gilbert } 1613c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 1614c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 161523183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 1616c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 1617c65b1445SDouglas Gilbert arr[0] = pcode; 161823183910SDouglas Gilbert if (0 == subpcode) { 1619c65b1445SDouglas Gilbert switch (pcode) { 1620c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 1621c65b1445SDouglas Gilbert n = 4; 1622c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1623c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 1624c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 1625c65b1445SDouglas Gilbert arr[3] = n - 4; 1626c65b1445SDouglas Gilbert break; 1627c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 1628c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 1629c65b1445SDouglas Gilbert break; 1630c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 1631c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 1632c65b1445SDouglas Gilbert break; 1633c65b1445SDouglas Gilbert default: 1634c65b1445SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 1635c65b1445SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 1636c65b1445SDouglas Gilbert return check_condition_result; 1637c65b1445SDouglas Gilbert } 163823183910SDouglas Gilbert } else if (0xff == subpcode) { 163923183910SDouglas Gilbert arr[0] |= 0x40; 164023183910SDouglas Gilbert arr[1] = subpcode; 164123183910SDouglas Gilbert switch (pcode) { 164223183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 164323183910SDouglas Gilbert n = 4; 164423183910SDouglas Gilbert arr[n++] = 0x0; 164523183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 164623183910SDouglas Gilbert arr[n++] = 0x0; 164723183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 164823183910SDouglas Gilbert arr[n++] = 0xd; 164923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 165023183910SDouglas Gilbert arr[n++] = 0x2f; 165123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 165223183910SDouglas Gilbert arr[3] = n - 4; 165323183910SDouglas Gilbert break; 165423183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 165523183910SDouglas Gilbert n = 4; 165623183910SDouglas Gilbert arr[n++] = 0xd; 165723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 165823183910SDouglas Gilbert arr[3] = n - 4; 165923183910SDouglas Gilbert break; 166023183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 166123183910SDouglas Gilbert n = 4; 166223183910SDouglas Gilbert arr[n++] = 0x2f; 166323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 166423183910SDouglas Gilbert arr[3] = n - 4; 166523183910SDouglas Gilbert break; 166623183910SDouglas Gilbert default: 166723183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 166823183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 166923183910SDouglas Gilbert return check_condition_result; 167023183910SDouglas Gilbert } 167123183910SDouglas Gilbert } else { 167223183910SDouglas Gilbert mk_sense_buffer(devip, ILLEGAL_REQUEST, 167323183910SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 167423183910SDouglas Gilbert return check_condition_result; 167523183910SDouglas Gilbert } 1676c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 1677c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1678c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 1679c65b1445SDouglas Gilbert } 1680c65b1445SDouglas Gilbert 168119789100SFUJITA Tomonori static int check_device_access_params(struct sdebug_dev_info *devi, 168219789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 16831da177e4SLinus Torvalds { 1684c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 168519789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0); 16861da177e4SLinus Torvalds return check_condition_result; 16871da177e4SLinus Torvalds } 1688c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 1689c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 169019789100SFUJITA Tomonori mk_sense_buffer(devi, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 1691c65b1445SDouglas Gilbert return check_condition_result; 1692c65b1445SDouglas Gilbert } 169319789100SFUJITA Tomonori return 0; 169419789100SFUJITA Tomonori } 169519789100SFUJITA Tomonori 169619789100SFUJITA Tomonori static int do_device_access(struct scsi_cmnd *scmd, 169719789100SFUJITA Tomonori struct sdebug_dev_info *devi, 169819789100SFUJITA Tomonori unsigned long long lba, unsigned int num, int write) 169919789100SFUJITA Tomonori { 170019789100SFUJITA Tomonori int ret; 1701a361cc00SDarrick J. Wong unsigned long long block, rest = 0; 170219789100SFUJITA Tomonori int (*func)(struct scsi_cmnd *, unsigned char *, int); 170319789100SFUJITA Tomonori 170419789100SFUJITA Tomonori func = write ? fetch_to_dev_buffer : fill_from_dev_buffer; 170519789100SFUJITA Tomonori 170619789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 170719789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 170819789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 170919789100SFUJITA Tomonori 1710597136abSMartin K. Petersen ret = func(scmd, fake_storep + (block * scsi_debug_sector_size), 1711597136abSMartin K. Petersen (num - rest) * scsi_debug_sector_size); 171219789100SFUJITA Tomonori if (!ret && rest) 1713597136abSMartin K. Petersen ret = func(scmd, fake_storep, rest * scsi_debug_sector_size); 171419789100SFUJITA Tomonori 171519789100SFUJITA Tomonori return ret; 171619789100SFUJITA Tomonori } 171719789100SFUJITA Tomonori 1718c6a44287SMartin K. Petersen static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 1719395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 1720c6a44287SMartin K. Petersen { 1721c6a44287SMartin K. Petersen unsigned int i, resid; 1722c6a44287SMartin K. Petersen struct scatterlist *psgl; 1723c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 1724c6a44287SMartin K. Petersen sector_t sector; 1725c6a44287SMartin K. Petersen sector_t tmp_sec = start_sec; 1726c6a44287SMartin K. Petersen void *paddr; 1727c6a44287SMartin K. Petersen 1728c6a44287SMartin K. Petersen start_sec = do_div(tmp_sec, sdebug_store_sectors); 1729c6a44287SMartin K. Petersen 1730c6a44287SMartin K. Petersen sdt = (struct sd_dif_tuple *)(dif_storep + dif_offset(start_sec)); 1731c6a44287SMartin K. Petersen 1732c6a44287SMartin K. Petersen for (i = 0 ; i < sectors ; i++) { 1733c6a44287SMartin K. Petersen u16 csum; 1734c6a44287SMartin K. Petersen 1735c6a44287SMartin K. Petersen if (sdt[i].app_tag == 0xffff) 1736c6a44287SMartin K. Petersen continue; 1737c6a44287SMartin K. Petersen 1738c6a44287SMartin K. Petersen sector = start_sec + i; 1739c6a44287SMartin K. Petersen 1740c6a44287SMartin K. Petersen switch (scsi_debug_guard) { 1741c6a44287SMartin K. Petersen case 1: 1742c6a44287SMartin K. Petersen csum = ip_compute_csum(fake_storep + 1743c6a44287SMartin K. Petersen sector * scsi_debug_sector_size, 1744c6a44287SMartin K. Petersen scsi_debug_sector_size); 1745c6a44287SMartin K. Petersen break; 1746c6a44287SMartin K. Petersen case 0: 1747c6a44287SMartin K. Petersen csum = crc_t10dif(fake_storep + 1748c6a44287SMartin K. Petersen sector * scsi_debug_sector_size, 1749c6a44287SMartin K. Petersen scsi_debug_sector_size); 1750c6a44287SMartin K. Petersen csum = cpu_to_be16(csum); 1751c6a44287SMartin K. Petersen break; 1752c6a44287SMartin K. Petersen default: 1753c6a44287SMartin K. Petersen BUG(); 1754c6a44287SMartin K. Petersen } 1755c6a44287SMartin K. Petersen 1756c6a44287SMartin K. Petersen if (sdt[i].guard_tag != csum) { 1757c6a44287SMartin K. Petersen printk(KERN_ERR "%s: GUARD check failed on sector %lu" \ 1758c6a44287SMartin K. Petersen " rcvd 0x%04x, data 0x%04x\n", __func__, 1759c6a44287SMartin K. Petersen (unsigned long)sector, 1760c6a44287SMartin K. Petersen be16_to_cpu(sdt[i].guard_tag), 1761c6a44287SMartin K. Petersen be16_to_cpu(csum)); 1762c6a44287SMartin K. Petersen dif_errors++; 1763c6a44287SMartin K. Petersen return 0x01; 1764c6a44287SMartin K. Petersen } 1765c6a44287SMartin K. Petersen 1766395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1767c6a44287SMartin K. Petersen be32_to_cpu(sdt[i].ref_tag) != (sector & 0xffffffff)) { 1768c6a44287SMartin K. Petersen printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1769c6a44287SMartin K. Petersen __func__, (unsigned long)sector); 1770c6a44287SMartin K. Petersen dif_errors++; 1771c6a44287SMartin K. Petersen return 0x03; 1772c6a44287SMartin K. Petersen } 1773395cef03SMartin K. Petersen 1774395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1775395cef03SMartin K. Petersen be32_to_cpu(sdt[i].ref_tag) != ei_lba) { 1776395cef03SMartin K. Petersen printk(KERN_ERR "%s: REF check failed on sector %lu\n", 1777395cef03SMartin K. Petersen __func__, (unsigned long)sector); 1778395cef03SMartin K. Petersen dif_errors++; 1779395cef03SMartin K. Petersen return 0x03; 1780395cef03SMartin K. Petersen } 1781395cef03SMartin K. Petersen 1782395cef03SMartin K. Petersen ei_lba++; 1783c6a44287SMartin K. Petersen } 1784c6a44287SMartin K. Petersen 1785c6a44287SMartin K. Petersen resid = sectors * 8; /* Bytes of protection data to copy into sgl */ 1786c6a44287SMartin K. Petersen sector = start_sec; 1787c6a44287SMartin K. Petersen 1788c6a44287SMartin K. Petersen scsi_for_each_prot_sg(SCpnt, psgl, scsi_prot_sg_count(SCpnt), i) { 1789c6a44287SMartin K. Petersen int len = min(psgl->length, resid); 1790c6a44287SMartin K. Petersen 179177dfce07SCong Wang paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; 1792c6a44287SMartin K. Petersen memcpy(paddr, dif_storep + dif_offset(sector), len); 1793c6a44287SMartin K. Petersen 1794c6a44287SMartin K. Petersen sector += len >> 3; 1795c6a44287SMartin K. Petersen if (sector >= sdebug_store_sectors) { 1796c6a44287SMartin K. Petersen /* Force wrap */ 1797c6a44287SMartin K. Petersen tmp_sec = sector; 1798c6a44287SMartin K. Petersen sector = do_div(tmp_sec, sdebug_store_sectors); 1799c6a44287SMartin K. Petersen } 1800c6a44287SMartin K. Petersen resid -= len; 180177dfce07SCong Wang kunmap_atomic(paddr); 1802c6a44287SMartin K. Petersen } 1803c6a44287SMartin K. Petersen 1804c6a44287SMartin K. Petersen dix_reads++; 1805c6a44287SMartin K. Petersen 1806c6a44287SMartin K. Petersen return 0; 1807c6a44287SMartin K. Petersen } 1808c6a44287SMartin K. Petersen 180919789100SFUJITA Tomonori static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba, 1810395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 1811395cef03SMartin K. Petersen u32 ei_lba) 181219789100SFUJITA Tomonori { 181319789100SFUJITA Tomonori unsigned long iflags; 181419789100SFUJITA Tomonori int ret; 181519789100SFUJITA Tomonori 181619789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 181719789100SFUJITA Tomonori if (ret) 181819789100SFUJITA Tomonori return ret; 181919789100SFUJITA Tomonori 18201da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 182132f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 1822c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 1823c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 182432f7ef73SDouglas Gilbert mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 1825c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 1826c65b1445SDouglas Gilbert if (0x70 == (devip->sense_buff[0] & 0x7f)) { 1827c65b1445SDouglas Gilbert devip->sense_buff[0] |= 0x80; /* Valid bit */ 182832f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 182932f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 1830c65b1445SDouglas Gilbert devip->sense_buff[3] = (ret >> 24) & 0xff; 1831c65b1445SDouglas Gilbert devip->sense_buff[4] = (ret >> 16) & 0xff; 1832c65b1445SDouglas Gilbert devip->sense_buff[5] = (ret >> 8) & 0xff; 1833c65b1445SDouglas Gilbert devip->sense_buff[6] = ret & 0xff; 1834c65b1445SDouglas Gilbert } 1835a87e3a67SDouglas Gilbert scsi_set_resid(SCpnt, scsi_bufflen(SCpnt)); 18361da177e4SLinus Torvalds return check_condition_result; 18371da177e4SLinus Torvalds } 1838c6a44287SMartin K. Petersen 1839c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 1840c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 1841395cef03SMartin K. Petersen int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba); 1842c6a44287SMartin K. Petersen 1843c6a44287SMartin K. Petersen if (prot_ret) { 1844c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, prot_ret); 1845c6a44287SMartin K. Petersen return illegal_condition_result; 1846c6a44287SMartin K. Petersen } 1847c6a44287SMartin K. Petersen } 1848c6a44287SMartin K. Petersen 18491da177e4SLinus Torvalds read_lock_irqsave(&atomic_rw, iflags); 185019789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 0); 18511da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 18521da177e4SLinus Torvalds return ret; 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds 1855c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len) 1856c6a44287SMartin K. Petersen { 1857c6a44287SMartin K. Petersen int i, j; 1858c6a44287SMartin K. Petersen 1859c6a44287SMartin K. Petersen printk(KERN_ERR ">>> Sector Dump <<<\n"); 1860c6a44287SMartin K. Petersen 1861c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 1862c6a44287SMartin K. Petersen printk(KERN_ERR "%04d: ", i); 1863c6a44287SMartin K. Petersen 1864c6a44287SMartin K. Petersen for (j = 0 ; j < 16 ; j++) { 1865c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 1866c6a44287SMartin K. Petersen if (c >= 0x20 && c < 0x7e) 1867c6a44287SMartin K. Petersen printk(" %c ", buf[i+j]); 1868c6a44287SMartin K. Petersen else 1869c6a44287SMartin K. Petersen printk("%02x ", buf[i+j]); 1870c6a44287SMartin K. Petersen } 1871c6a44287SMartin K. Petersen 1872c6a44287SMartin K. Petersen printk("\n"); 1873c6a44287SMartin K. Petersen } 1874c6a44287SMartin K. Petersen } 1875c6a44287SMartin K. Petersen 1876c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 1877395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 1878c6a44287SMartin K. Petersen { 1879c6a44287SMartin K. Petersen int i, j, ret; 1880c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 1881c6a44287SMartin K. Petersen struct scatterlist *dsgl = scsi_sglist(SCpnt); 1882c6a44287SMartin K. Petersen struct scatterlist *psgl = scsi_prot_sglist(SCpnt); 1883c6a44287SMartin K. Petersen void *daddr, *paddr; 1884c6a44287SMartin K. Petersen sector_t tmp_sec = start_sec; 1885c6a44287SMartin K. Petersen sector_t sector; 1886c6a44287SMartin K. Petersen int ppage_offset; 1887c6a44287SMartin K. Petersen unsigned short csum; 1888c6a44287SMartin K. Petersen 1889c6a44287SMartin K. Petersen sector = do_div(tmp_sec, sdebug_store_sectors); 1890c6a44287SMartin K. Petersen 1891c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 1892c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 1893c6a44287SMartin K. Petersen 189477dfce07SCong Wang paddr = kmap_atomic(sg_page(psgl)) + psgl->offset; 1895c6a44287SMartin K. Petersen ppage_offset = 0; 1896c6a44287SMartin K. Petersen 1897c6a44287SMartin K. Petersen /* For each data page */ 1898c6a44287SMartin K. Petersen scsi_for_each_sg(SCpnt, dsgl, scsi_sg_count(SCpnt), i) { 189977dfce07SCong Wang daddr = kmap_atomic(sg_page(dsgl)) + dsgl->offset; 1900c6a44287SMartin K. Petersen 1901c6a44287SMartin K. Petersen /* For each sector-sized chunk in data page */ 1902c6a44287SMartin K. Petersen for (j = 0 ; j < dsgl->length ; j += scsi_debug_sector_size) { 1903c6a44287SMartin K. Petersen 1904c6a44287SMartin K. Petersen /* If we're at the end of the current 1905c6a44287SMartin K. Petersen * protection page advance to the next one 1906c6a44287SMartin K. Petersen */ 1907c6a44287SMartin K. Petersen if (ppage_offset >= psgl->length) { 190877dfce07SCong Wang kunmap_atomic(paddr); 1909c6a44287SMartin K. Petersen psgl = sg_next(psgl); 1910c6a44287SMartin K. Petersen BUG_ON(psgl == NULL); 191177dfce07SCong Wang paddr = kmap_atomic(sg_page(psgl)) 1912c6a44287SMartin K. Petersen + psgl->offset; 1913c6a44287SMartin K. Petersen ppage_offset = 0; 1914c6a44287SMartin K. Petersen } 1915c6a44287SMartin K. Petersen 1916c6a44287SMartin K. Petersen sdt = paddr + ppage_offset; 1917c6a44287SMartin K. Petersen 1918c6a44287SMartin K. Petersen switch (scsi_debug_guard) { 1919c6a44287SMartin K. Petersen case 1: 1920c6a44287SMartin K. Petersen csum = ip_compute_csum(daddr, 1921c6a44287SMartin K. Petersen scsi_debug_sector_size); 1922c6a44287SMartin K. Petersen break; 1923c6a44287SMartin K. Petersen case 0: 1924c6a44287SMartin K. Petersen csum = cpu_to_be16(crc_t10dif(daddr, 1925c6a44287SMartin K. Petersen scsi_debug_sector_size)); 1926c6a44287SMartin K. Petersen break; 1927c6a44287SMartin K. Petersen default: 1928c6a44287SMartin K. Petersen BUG(); 1929c6a44287SMartin K. Petersen ret = 0; 1930c6a44287SMartin K. Petersen goto out; 1931c6a44287SMartin K. Petersen } 1932c6a44287SMartin K. Petersen 1933c6a44287SMartin K. Petersen if (sdt->guard_tag != csum) { 1934c6a44287SMartin K. Petersen printk(KERN_ERR 1935c6a44287SMartin K. Petersen "%s: GUARD check failed on sector %lu " \ 1936c6a44287SMartin K. Petersen "rcvd 0x%04x, calculated 0x%04x\n", 1937c6a44287SMartin K. Petersen __func__, (unsigned long)sector, 1938c6a44287SMartin K. Petersen be16_to_cpu(sdt->guard_tag), 1939c6a44287SMartin K. Petersen be16_to_cpu(csum)); 1940c6a44287SMartin K. Petersen ret = 0x01; 1941c6a44287SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1942c6a44287SMartin K. Petersen goto out; 1943c6a44287SMartin K. Petersen } 1944c6a44287SMartin K. Petersen 1945395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 1946c6a44287SMartin K. Petersen be32_to_cpu(sdt->ref_tag) 1947c6a44287SMartin K. Petersen != (start_sec & 0xffffffff)) { 1948c6a44287SMartin K. Petersen printk(KERN_ERR 1949c6a44287SMartin K. Petersen "%s: REF check failed on sector %lu\n", 1950c6a44287SMartin K. Petersen __func__, (unsigned long)sector); 1951c6a44287SMartin K. Petersen ret = 0x03; 1952c6a44287SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1953c6a44287SMartin K. Petersen goto out; 1954c6a44287SMartin K. Petersen } 1955c6a44287SMartin K. Petersen 1956395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 1957395cef03SMartin K. Petersen be32_to_cpu(sdt->ref_tag) != ei_lba) { 1958395cef03SMartin K. Petersen printk(KERN_ERR 1959395cef03SMartin K. Petersen "%s: REF check failed on sector %lu\n", 1960395cef03SMartin K. Petersen __func__, (unsigned long)sector); 1961395cef03SMartin K. Petersen ret = 0x03; 1962395cef03SMartin K. Petersen dump_sector(daddr, scsi_debug_sector_size); 1963395cef03SMartin K. Petersen goto out; 1964395cef03SMartin K. Petersen } 1965395cef03SMartin K. Petersen 1966c6a44287SMartin K. Petersen /* Would be great to copy this in bigger 1967c6a44287SMartin K. Petersen * chunks. However, for the sake of 1968c6a44287SMartin K. Petersen * correctness we need to verify each sector 1969c6a44287SMartin K. Petersen * before writing it to "stable" storage 1970c6a44287SMartin K. Petersen */ 1971c6a44287SMartin K. Petersen memcpy(dif_storep + dif_offset(sector), sdt, 8); 1972c6a44287SMartin K. Petersen 1973c6a44287SMartin K. Petersen sector++; 1974c6a44287SMartin K. Petersen 1975c6a44287SMartin K. Petersen if (sector == sdebug_store_sectors) 1976c6a44287SMartin K. Petersen sector = 0; /* Force wrap */ 1977c6a44287SMartin K. Petersen 1978c6a44287SMartin K. Petersen start_sec++; 1979395cef03SMartin K. Petersen ei_lba++; 1980c6a44287SMartin K. Petersen daddr += scsi_debug_sector_size; 1981c6a44287SMartin K. Petersen ppage_offset += sizeof(struct sd_dif_tuple); 1982c6a44287SMartin K. Petersen } 1983c6a44287SMartin K. Petersen 198477dfce07SCong Wang kunmap_atomic(daddr); 1985c6a44287SMartin K. Petersen } 1986c6a44287SMartin K. Petersen 198777dfce07SCong Wang kunmap_atomic(paddr); 1988c6a44287SMartin K. Petersen 1989c6a44287SMartin K. Petersen dix_writes++; 1990c6a44287SMartin K. Petersen 1991c6a44287SMartin K. Petersen return 0; 1992c6a44287SMartin K. Petersen 1993c6a44287SMartin K. Petersen out: 1994c6a44287SMartin K. Petersen dif_errors++; 199577dfce07SCong Wang kunmap_atomic(daddr); 199677dfce07SCong Wang kunmap_atomic(paddr); 1997c6a44287SMartin K. Petersen return ret; 1998c6a44287SMartin K. Petersen } 1999c6a44287SMartin K. Petersen 2000b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2001b90ebc3dSAkinobu Mita { 2002b90ebc3dSAkinobu Mita if (scsi_debug_unmap_alignment) { 2003b90ebc3dSAkinobu Mita lba += scsi_debug_unmap_granularity - 2004b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2005b90ebc3dSAkinobu Mita } 2006b90ebc3dSAkinobu Mita do_div(lba, scsi_debug_unmap_granularity); 2007b90ebc3dSAkinobu Mita 2008b90ebc3dSAkinobu Mita return lba; 2009b90ebc3dSAkinobu Mita } 2010b90ebc3dSAkinobu Mita 2011b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2012b90ebc3dSAkinobu Mita { 2013b90ebc3dSAkinobu Mita return index * scsi_debug_unmap_granularity - 2014b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2015b90ebc3dSAkinobu Mita } 2016b90ebc3dSAkinobu Mita 201744d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 201844d92694SMartin K. Petersen { 2019b90ebc3dSAkinobu Mita sector_t end; 2020b90ebc3dSAkinobu Mita unsigned int mapped; 2021b90ebc3dSAkinobu Mita unsigned long index; 2022b90ebc3dSAkinobu Mita unsigned long next; 202344d92694SMartin K. Petersen 2024b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2025b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 202644d92694SMartin K. Petersen 202744d92694SMartin K. Petersen if (mapped) 2028b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 202944d92694SMartin K. Petersen else 2030b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 203144d92694SMartin K. Petersen 2032b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 203344d92694SMartin K. Petersen *num = end - lba; 203444d92694SMartin K. Petersen 203544d92694SMartin K. Petersen return mapped; 203644d92694SMartin K. Petersen } 203744d92694SMartin K. Petersen 203844d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 203944d92694SMartin K. Petersen { 204044d92694SMartin K. Petersen sector_t end = lba + len; 204144d92694SMartin K. Petersen 204244d92694SMartin K. Petersen while (lba < end) { 2043b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 204444d92694SMartin K. Petersen 2045b90ebc3dSAkinobu Mita if (index < map_size) 2046b90ebc3dSAkinobu Mita set_bit(index, map_storep); 204744d92694SMartin K. Petersen 2048b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 204944d92694SMartin K. Petersen } 205044d92694SMartin K. Petersen } 205144d92694SMartin K. Petersen 205244d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 205344d92694SMartin K. Petersen { 205444d92694SMartin K. Petersen sector_t end = lba + len; 205544d92694SMartin K. Petersen 205644d92694SMartin K. Petersen while (lba < end) { 2057b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 205844d92694SMartin K. Petersen 2059b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2060b90ebc3dSAkinobu Mita lba + scsi_debug_unmap_granularity <= end && 2061b90ebc3dSAkinobu Mita index < map_size) { 2062b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2063b90ebc3dSAkinobu Mita if (scsi_debug_lbprz) { 2064be1dd78dSEric Sandeen memset(fake_storep + 2065cc34a8e6SAkinobu Mita lba * scsi_debug_sector_size, 0, 2066cc34a8e6SAkinobu Mita scsi_debug_sector_size * 2067cc34a8e6SAkinobu Mita scsi_debug_unmap_granularity); 2068be1dd78dSEric Sandeen } 2069b90ebc3dSAkinobu Mita } 2070b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 207144d92694SMartin K. Petersen } 207244d92694SMartin K. Petersen } 207344d92694SMartin K. Petersen 2074c65b1445SDouglas Gilbert static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba, 2075395cef03SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 2076395cef03SMartin K. Petersen u32 ei_lba) 20771da177e4SLinus Torvalds { 20781da177e4SLinus Torvalds unsigned long iflags; 207919789100SFUJITA Tomonori int ret; 20801da177e4SLinus Torvalds 208119789100SFUJITA Tomonori ret = check_device_access_params(devip, lba, num); 208219789100SFUJITA Tomonori if (ret) 208319789100SFUJITA Tomonori return ret; 20841da177e4SLinus Torvalds 2085c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2086c6a44287SMartin K. Petersen if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) { 2087395cef03SMartin K. Petersen int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba); 2088c6a44287SMartin K. Petersen 2089c6a44287SMartin K. Petersen if (prot_ret) { 2090c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, prot_ret); 2091c6a44287SMartin K. Petersen return illegal_condition_result; 2092c6a44287SMartin K. Petersen } 2093c6a44287SMartin K. Petersen } 2094c6a44287SMartin K. Petersen 20951da177e4SLinus Torvalds write_lock_irqsave(&atomic_rw, iflags); 209619789100SFUJITA Tomonori ret = do_device_access(SCpnt, devip, lba, num, 1); 20979ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 209844d92694SMartin K. Petersen map_region(lba, num); 20991da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 210019789100SFUJITA Tomonori if (-1 == ret) 21011da177e4SLinus Torvalds return (DID_ERROR << 16); 2102597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 21031da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2104c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: write: cdb indicated=%u, " 2105597136abSMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 210644d92694SMartin K. Petersen 21071da177e4SLinus Torvalds return 0; 21081da177e4SLinus Torvalds } 21091da177e4SLinus Torvalds 211044d92694SMartin K. Petersen static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba, 211144d92694SMartin K. Petersen unsigned int num, struct sdebug_dev_info *devip, 211244d92694SMartin K. Petersen u32 ei_lba, unsigned int unmap) 211344d92694SMartin K. Petersen { 211444d92694SMartin K. Petersen unsigned long iflags; 211544d92694SMartin K. Petersen unsigned long long i; 211644d92694SMartin K. Petersen int ret; 211744d92694SMartin K. Petersen 211844d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 211944d92694SMartin K. Petersen if (ret) 212044d92694SMartin K. Petersen return ret; 212144d92694SMartin K. Petersen 21225b94e232SMartin K. Petersen if (num > scsi_debug_write_same_length) { 21235b94e232SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 21245b94e232SMartin K. Petersen 0); 21255b94e232SMartin K. Petersen return check_condition_result; 21265b94e232SMartin K. Petersen } 21275b94e232SMartin K. Petersen 212844d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 212944d92694SMartin K. Petersen 21309ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 213144d92694SMartin K. Petersen unmap_region(lba, num); 213244d92694SMartin K. Petersen goto out; 213344d92694SMartin K. Petersen } 213444d92694SMartin K. Petersen 213544d92694SMartin K. Petersen /* Else fetch one logical block */ 213644d92694SMartin K. Petersen ret = fetch_to_dev_buffer(scmd, 213744d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 213844d92694SMartin K. Petersen scsi_debug_sector_size); 213944d92694SMartin K. Petersen 214044d92694SMartin K. Petersen if (-1 == ret) { 214144d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 214244d92694SMartin K. Petersen return (DID_ERROR << 16); 214344d92694SMartin K. Petersen } else if ((ret < (num * scsi_debug_sector_size)) && 214444d92694SMartin K. Petersen (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 214544d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug: write same: cdb indicated=%u, " 214644d92694SMartin K. Petersen " IO sent=%d bytes\n", num * scsi_debug_sector_size, ret); 214744d92694SMartin K. Petersen 214844d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 214944d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 215044d92694SMartin K. Petersen memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), 215144d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 215244d92694SMartin K. Petersen scsi_debug_sector_size); 215344d92694SMartin K. Petersen 21549ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 215544d92694SMartin K. Petersen map_region(lba, num); 215644d92694SMartin K. Petersen out: 215744d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 215844d92694SMartin K. Petersen 215944d92694SMartin K. Petersen return 0; 216044d92694SMartin K. Petersen } 216144d92694SMartin K. Petersen 216244d92694SMartin K. Petersen struct unmap_block_desc { 216344d92694SMartin K. Petersen __be64 lba; 216444d92694SMartin K. Petersen __be32 blocks; 216544d92694SMartin K. Petersen __be32 __reserved; 216644d92694SMartin K. Petersen }; 216744d92694SMartin K. Petersen 216844d92694SMartin K. Petersen static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip) 216944d92694SMartin K. Petersen { 217044d92694SMartin K. Petersen unsigned char *buf; 217144d92694SMartin K. Petersen struct unmap_block_desc *desc; 217244d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 217344d92694SMartin K. Petersen int ret; 217444d92694SMartin K. Petersen 217544d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 217644d92694SMartin K. Petersen if (ret) 217744d92694SMartin K. Petersen return ret; 217844d92694SMartin K. Petersen 217944d92694SMartin K. Petersen payload_len = get_unaligned_be16(&scmd->cmnd[7]); 218044d92694SMartin K. Petersen BUG_ON(scsi_bufflen(scmd) != payload_len); 218144d92694SMartin K. Petersen 218244d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 218344d92694SMartin K. Petersen 218444d92694SMartin K. Petersen buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC); 218544d92694SMartin K. Petersen if (!buf) 218644d92694SMartin K. Petersen return check_condition_result; 218744d92694SMartin K. Petersen 218844d92694SMartin K. Petersen scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd)); 218944d92694SMartin K. Petersen 219044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 219144d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 219244d92694SMartin K. Petersen 219344d92694SMartin K. Petersen desc = (void *)&buf[8]; 219444d92694SMartin K. Petersen 219544d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 219644d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 219744d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 219844d92694SMartin K. Petersen 219944d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, num); 220044d92694SMartin K. Petersen if (ret) 220144d92694SMartin K. Petersen goto out; 220244d92694SMartin K. Petersen 220344d92694SMartin K. Petersen unmap_region(lba, num); 220444d92694SMartin K. Petersen } 220544d92694SMartin K. Petersen 220644d92694SMartin K. Petersen ret = 0; 220744d92694SMartin K. Petersen 220844d92694SMartin K. Petersen out: 220944d92694SMartin K. Petersen kfree(buf); 221044d92694SMartin K. Petersen 221144d92694SMartin K. Petersen return ret; 221244d92694SMartin K. Petersen } 221344d92694SMartin K. Petersen 221444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 221544d92694SMartin K. Petersen 221644d92694SMartin K. Petersen static int resp_get_lba_status(struct scsi_cmnd * scmd, 221744d92694SMartin K. Petersen struct sdebug_dev_info * devip) 221844d92694SMartin K. Petersen { 221944d92694SMartin K. Petersen unsigned long long lba; 222044d92694SMartin K. Petersen unsigned int alloc_len, mapped, num; 222144d92694SMartin K. Petersen unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN]; 222244d92694SMartin K. Petersen int ret; 222344d92694SMartin K. Petersen 222444d92694SMartin K. Petersen ret = check_readiness(scmd, 1, devip); 222544d92694SMartin K. Petersen if (ret) 222644d92694SMartin K. Petersen return ret; 222744d92694SMartin K. Petersen 222844d92694SMartin K. Petersen lba = get_unaligned_be64(&scmd->cmnd[2]); 222944d92694SMartin K. Petersen alloc_len = get_unaligned_be32(&scmd->cmnd[10]); 223044d92694SMartin K. Petersen 223144d92694SMartin K. Petersen if (alloc_len < 24) 223244d92694SMartin K. Petersen return 0; 223344d92694SMartin K. Petersen 223444d92694SMartin K. Petersen ret = check_device_access_params(devip, lba, 1); 223544d92694SMartin K. Petersen if (ret) 223644d92694SMartin K. Petersen return ret; 223744d92694SMartin K. Petersen 223844d92694SMartin K. Petersen mapped = map_state(lba, &num); 223944d92694SMartin K. Petersen 224044d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 2241de13e965SDouglas Gilbert put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */ 224244d92694SMartin K. Petersen put_unaligned_be64(lba, &arr[8]); /* LBA */ 224344d92694SMartin K. Petersen put_unaligned_be32(num, &arr[16]); /* Number of blocks */ 224444d92694SMartin K. Petersen arr[20] = !mapped; /* mapped = 0, unmapped = 1 */ 224544d92694SMartin K. Petersen 224644d92694SMartin K. Petersen return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN); 224744d92694SMartin K. Petersen } 224844d92694SMartin K. Petersen 2249c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 22521da177e4SLinus Torvalds struct sdebug_dev_info * devip) 22531da177e4SLinus Torvalds { 22541da177e4SLinus Torvalds unsigned int alloc_len; 2255c65b1445SDouglas Gilbert int lun_cnt, i, upper, num, n, wlun, lun; 22561da177e4SLinus Torvalds unsigned char *cmd = (unsigned char *)scp->cmnd; 22571da177e4SLinus Torvalds int select_report = (int)cmd[2]; 22581da177e4SLinus Torvalds struct scsi_lun *one_lun; 22591da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 2260c65b1445SDouglas Gilbert unsigned char * max_addr; 22611da177e4SLinus Torvalds 22621da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 2263c65b1445SDouglas Gilbert if ((alloc_len < 4) || (select_report > 2)) { 22641da177e4SLinus Torvalds mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 22651da177e4SLinus Torvalds 0); 22661da177e4SLinus Torvalds return check_condition_result; 22671da177e4SLinus Torvalds } 22681da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 22691da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 22701da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 2271c65b1445SDouglas Gilbert if (1 == select_report) 2272c65b1445SDouglas Gilbert lun_cnt = 0; 2273c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 2274c65b1445SDouglas Gilbert --lun_cnt; 2275c65b1445SDouglas Gilbert wlun = (select_report > 0) ? 1 : 0; 2276c65b1445SDouglas Gilbert num = lun_cnt + wlun; 2277c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 2278c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 2279c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 2280c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 2281c65b1445SDouglas Gilbert if (n < num) { 2282c65b1445SDouglas Gilbert wlun = 0; 2283c65b1445SDouglas Gilbert lun_cnt = n; 2284c65b1445SDouglas Gilbert } 22851da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 2286c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 2287c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 2288c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 2289c65b1445SDouglas Gilbert i++, lun++) { 2290c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 22911da177e4SLinus Torvalds if (upper) 22921da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 22931da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 2294c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 22951da177e4SLinus Torvalds } 2296c65b1445SDouglas Gilbert if (wlun) { 2297c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 2298c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 2299c65b1445SDouglas Gilbert i++; 2300c65b1445SDouglas Gilbert } 2301c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 23021da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 23031da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 23041da177e4SLinus Torvalds } 23051da177e4SLinus Torvalds 2306c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 2307c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 2308c639d14eSFUJITA Tomonori { 2309c639d14eSFUJITA Tomonori int i, j, ret = -1; 2310c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 2311c639d14eSFUJITA Tomonori unsigned int offset; 2312c639d14eSFUJITA Tomonori struct scatterlist *sg; 2313c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 2314c639d14eSFUJITA Tomonori 2315c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 2316c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 2317c639d14eSFUJITA Tomonori if (!buf) 2318c639d14eSFUJITA Tomonori return ret; 2319c639d14eSFUJITA Tomonori 232021a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 2321c639d14eSFUJITA Tomonori 2322c639d14eSFUJITA Tomonori offset = 0; 2323c639d14eSFUJITA Tomonori for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) { 232477dfce07SCong Wang kaddr = (unsigned char *)kmap_atomic(sg_page(sg)); 2325c639d14eSFUJITA Tomonori if (!kaddr) 2326c639d14eSFUJITA Tomonori goto out; 2327c639d14eSFUJITA Tomonori 2328c639d14eSFUJITA Tomonori for (j = 0; j < sg->length; j++) 2329c639d14eSFUJITA Tomonori *(kaddr + sg->offset + j) ^= *(buf + offset + j); 2330c639d14eSFUJITA Tomonori 2331c639d14eSFUJITA Tomonori offset += sg->length; 233277dfce07SCong Wang kunmap_atomic(kaddr); 2333c639d14eSFUJITA Tomonori } 2334c639d14eSFUJITA Tomonori ret = 0; 2335c639d14eSFUJITA Tomonori out: 2336c639d14eSFUJITA Tomonori kfree(buf); 2337c639d14eSFUJITA Tomonori 2338c639d14eSFUJITA Tomonori return ret; 2339c639d14eSFUJITA Tomonori } 2340c639d14eSFUJITA Tomonori 23411da177e4SLinus Torvalds /* When timer goes off this function is called. */ 23421da177e4SLinus Torvalds static void timer_intr_handler(unsigned long indx) 23431da177e4SLinus Torvalds { 23441da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 23451da177e4SLinus Torvalds unsigned long iflags; 23461da177e4SLinus Torvalds 234778d4e5a0SDouglas Gilbert if (indx >= scsi_debug_max_queue) { 23481da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too " 23491da177e4SLinus Torvalds "large\n"); 23501da177e4SLinus Torvalds return; 23511da177e4SLinus Torvalds } 23521da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 23531da177e4SLinus Torvalds sqcp = &queued_arr[(int)indx]; 23541da177e4SLinus Torvalds if (! sqcp->in_use) { 23551da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected " 23561da177e4SLinus Torvalds "interrupt\n"); 23571da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23581da177e4SLinus Torvalds return; 23591da177e4SLinus Torvalds } 23601da177e4SLinus Torvalds sqcp->in_use = 0; 23611da177e4SLinus Torvalds if (sqcp->done_funct) { 23621da177e4SLinus Torvalds sqcp->a_cmnd->result = sqcp->scsi_result; 23631da177e4SLinus Torvalds sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */ 23641da177e4SLinus Torvalds } 23651da177e4SLinus Torvalds sqcp->done_funct = NULL; 23661da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 23671da177e4SLinus Torvalds } 23681da177e4SLinus Torvalds 23691da177e4SLinus Torvalds 23708dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 23718dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 23725cb2fc06SFUJITA Tomonori { 23735cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 23745cb2fc06SFUJITA Tomonori 23755cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 23765cb2fc06SFUJITA Tomonori if (devip) { 23775cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 23785cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 23795cb2fc06SFUJITA Tomonori } 23805cb2fc06SFUJITA Tomonori return devip; 23815cb2fc06SFUJITA Tomonori } 23825cb2fc06SFUJITA Tomonori 23831da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 23841da177e4SLinus Torvalds { 23851da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 23861da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 23871da177e4SLinus Torvalds struct sdebug_dev_info * devip = 23881da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds if (devip) 23911da177e4SLinus Torvalds return devip; 2392d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 23931da177e4SLinus Torvalds if (!sdbg_host) { 23941da177e4SLinus Torvalds printk(KERN_ERR "Host info NULL\n"); 23951da177e4SLinus Torvalds return NULL; 23961da177e4SLinus Torvalds } 23971da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 23981da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 23991da177e4SLinus Torvalds (devip->target == sdev->id) && 24001da177e4SLinus Torvalds (devip->lun == sdev->lun)) 24011da177e4SLinus Torvalds return devip; 24021da177e4SLinus Torvalds else { 24031da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 24041da177e4SLinus Torvalds open_devip = devip; 24051da177e4SLinus Torvalds } 24061da177e4SLinus Torvalds } 24075cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 24085cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 24095cb2fc06SFUJITA Tomonori if (!open_devip) { 24101da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 2411cadbd4a5SHarvey Harrison __func__, __LINE__); 24121da177e4SLinus Torvalds return NULL; 24131da177e4SLinus Torvalds } 24141da177e4SLinus Torvalds } 2415a75869d1SFUJITA Tomonori 24161da177e4SLinus Torvalds open_devip->channel = sdev->channel; 24171da177e4SLinus Torvalds open_devip->target = sdev->id; 24181da177e4SLinus Torvalds open_devip->lun = sdev->lun; 24191da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 24201da177e4SLinus Torvalds open_devip->reset = 1; 24211da177e4SLinus Torvalds open_devip->used = 1; 24221da177e4SLinus Torvalds memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN); 24231da177e4SLinus Torvalds if (scsi_debug_dsense) 24241da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x72; 24251da177e4SLinus Torvalds else { 24261da177e4SLinus Torvalds open_devip->sense_buff[0] = 0x70; 24271da177e4SLinus Torvalds open_devip->sense_buff[7] = 0xa; 24281da177e4SLinus Torvalds } 2429c65b1445SDouglas Gilbert if (sdev->lun == SAM2_WLUN_REPORT_LUNS) 2430c65b1445SDouglas Gilbert open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff; 2431a75869d1SFUJITA Tomonori 24321da177e4SLinus Torvalds return open_devip; 24331da177e4SLinus Torvalds } 24341da177e4SLinus Torvalds 24358dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 24361da177e4SLinus Torvalds { 24378dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24388dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n", 24398dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 244075ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 24418dea0d02SFUJITA Tomonori return 0; 24428dea0d02SFUJITA Tomonori } 24431da177e4SLinus Torvalds 24448dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 24458dea0d02SFUJITA Tomonori { 24468dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 2447a34c4e98SFUJITA Tomonori 24481da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24498dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n", 24508dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24518dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 24528dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 24538dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 24548dea0d02SFUJITA Tomonori if (NULL == devip) 24558dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 24568dea0d02SFUJITA Tomonori sdp->hostdata = devip; 24578dea0d02SFUJITA Tomonori if (sdp->host->cmd_per_lun) 24588dea0d02SFUJITA Tomonori scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING, 24598dea0d02SFUJITA Tomonori sdp->host->cmd_per_lun); 24608dea0d02SFUJITA Tomonori blk_queue_max_segment_size(sdp->request_queue, 256 * 1024); 246178d4e5a0SDouglas Gilbert if (scsi_debug_no_uld) 246278d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 24638dea0d02SFUJITA Tomonori return 0; 24648dea0d02SFUJITA Tomonori } 24658dea0d02SFUJITA Tomonori 24668dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 24678dea0d02SFUJITA Tomonori { 24688dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 24698dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 24708dea0d02SFUJITA Tomonori 24718dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 24728dea0d02SFUJITA Tomonori printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n", 24738dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 24748dea0d02SFUJITA Tomonori if (devip) { 247525985edcSLucas De Marchi /* make this slot available for re-use */ 24768dea0d02SFUJITA Tomonori devip->used = 0; 24778dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 24788dea0d02SFUJITA Tomonori } 24798dea0d02SFUJITA Tomonori } 24808dea0d02SFUJITA Tomonori 24818dea0d02SFUJITA Tomonori /* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */ 24828dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 24838dea0d02SFUJITA Tomonori { 24848dea0d02SFUJITA Tomonori unsigned long iflags; 24858dea0d02SFUJITA Tomonori int k; 24868dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 24878dea0d02SFUJITA Tomonori 24888dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 248978d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 24908dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 24918dea0d02SFUJITA Tomonori if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) { 24928dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 24938dea0d02SFUJITA Tomonori sqcp->in_use = 0; 24948dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 24958dea0d02SFUJITA Tomonori break; 24968dea0d02SFUJITA Tomonori } 24978dea0d02SFUJITA Tomonori } 24988dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 249978d4e5a0SDouglas Gilbert return (k < scsi_debug_max_queue) ? 1 : 0; 25008dea0d02SFUJITA Tomonori } 25018dea0d02SFUJITA Tomonori 25028dea0d02SFUJITA Tomonori /* Deletes (stops) timers of all queued commands */ 25038dea0d02SFUJITA Tomonori static void stop_all_queued(void) 25048dea0d02SFUJITA Tomonori { 25058dea0d02SFUJITA Tomonori unsigned long iflags; 25068dea0d02SFUJITA Tomonori int k; 25078dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 25088dea0d02SFUJITA Tomonori 25098dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 251078d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 25118dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 25128dea0d02SFUJITA Tomonori if (sqcp->in_use && sqcp->a_cmnd) { 25138dea0d02SFUJITA Tomonori del_timer_sync(&sqcp->cmnd_timer); 25148dea0d02SFUJITA Tomonori sqcp->in_use = 0; 25158dea0d02SFUJITA Tomonori sqcp->a_cmnd = NULL; 25168dea0d02SFUJITA Tomonori } 25178dea0d02SFUJITA Tomonori } 25188dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 25191da177e4SLinus Torvalds } 25201da177e4SLinus Torvalds 25211da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd * SCpnt) 25221da177e4SLinus Torvalds { 25231da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25241da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: abort\n"); 25251da177e4SLinus Torvalds ++num_aborts; 25261da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 25271da177e4SLinus Torvalds return SUCCESS; 25281da177e4SLinus Torvalds } 25291da177e4SLinus Torvalds 25301da177e4SLinus Torvalds static int scsi_debug_biosparam(struct scsi_device *sdev, 25311da177e4SLinus Torvalds struct block_device * bdev, sector_t capacity, int *info) 25321da177e4SLinus Torvalds { 25331da177e4SLinus Torvalds int res; 25341da177e4SLinus Torvalds unsigned char *buf; 25351da177e4SLinus Torvalds 25361da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25371da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: biosparam\n"); 25381da177e4SLinus Torvalds buf = scsi_bios_ptable(bdev); 25391da177e4SLinus Torvalds if (buf) { 25401da177e4SLinus Torvalds res = scsi_partsize(buf, capacity, 25411da177e4SLinus Torvalds &info[2], &info[0], &info[1]); 25421da177e4SLinus Torvalds kfree(buf); 25431da177e4SLinus Torvalds if (! res) 25441da177e4SLinus Torvalds return res; 25451da177e4SLinus Torvalds } 25461da177e4SLinus Torvalds info[0] = sdebug_heads; 25471da177e4SLinus Torvalds info[1] = sdebug_sectors_per; 25481da177e4SLinus Torvalds info[2] = sdebug_cylinders_per; 25491da177e4SLinus Torvalds return 0; 25501da177e4SLinus Torvalds } 25511da177e4SLinus Torvalds 25521da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 25531da177e4SLinus Torvalds { 25541da177e4SLinus Torvalds struct sdebug_dev_info * devip; 25551da177e4SLinus Torvalds 25561da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25571da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: device_reset\n"); 25581da177e4SLinus Torvalds ++num_dev_resets; 25591da177e4SLinus Torvalds if (SCpnt) { 25601da177e4SLinus Torvalds devip = devInfoReg(SCpnt->device); 25611da177e4SLinus Torvalds if (devip) 25621da177e4SLinus Torvalds devip->reset = 1; 25631da177e4SLinus Torvalds } 25641da177e4SLinus Torvalds return SUCCESS; 25651da177e4SLinus Torvalds } 25661da177e4SLinus Torvalds 25671da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 25681da177e4SLinus Torvalds { 25691da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 25701da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 25711da177e4SLinus Torvalds struct scsi_device * sdp; 25721da177e4SLinus Torvalds struct Scsi_Host * hp; 25731da177e4SLinus Torvalds 25741da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25751da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: bus_reset\n"); 25761da177e4SLinus Torvalds ++num_bus_resets; 25771da177e4SLinus Torvalds if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) { 2578d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 25791da177e4SLinus Torvalds if (sdbg_host) { 25801da177e4SLinus Torvalds list_for_each_entry(dev_info, 25811da177e4SLinus Torvalds &sdbg_host->dev_info_list, 25821da177e4SLinus Torvalds dev_list) 25831da177e4SLinus Torvalds dev_info->reset = 1; 25841da177e4SLinus Torvalds } 25851da177e4SLinus Torvalds } 25861da177e4SLinus Torvalds return SUCCESS; 25871da177e4SLinus Torvalds } 25881da177e4SLinus Torvalds 25891da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 25901da177e4SLinus Torvalds { 25911da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 25921da177e4SLinus Torvalds struct sdebug_dev_info * dev_info; 25931da177e4SLinus Torvalds 25941da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 25951da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug: host_reset\n"); 25961da177e4SLinus Torvalds ++num_host_resets; 25971da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 25981da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 25991da177e4SLinus Torvalds list_for_each_entry(dev_info, &sdbg_host->dev_info_list, 26001da177e4SLinus Torvalds dev_list) 26011da177e4SLinus Torvalds dev_info->reset = 1; 26021da177e4SLinus Torvalds } 26031da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 26041da177e4SLinus Torvalds stop_all_queued(); 26051da177e4SLinus Torvalds return SUCCESS; 26061da177e4SLinus Torvalds } 26071da177e4SLinus Torvalds 26081da177e4SLinus Torvalds /* Initializes timers in queued array */ 26091da177e4SLinus Torvalds static void __init init_all_queued(void) 26101da177e4SLinus Torvalds { 26111da177e4SLinus Torvalds unsigned long iflags; 26121da177e4SLinus Torvalds int k; 26131da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp; 26141da177e4SLinus Torvalds 26151da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 261678d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 26171da177e4SLinus Torvalds sqcp = &queued_arr[k]; 26181da177e4SLinus Torvalds init_timer(&sqcp->cmnd_timer); 26191da177e4SLinus Torvalds sqcp->in_use = 0; 26201da177e4SLinus Torvalds sqcp->a_cmnd = NULL; 26211da177e4SLinus Torvalds } 26221da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 26231da177e4SLinus Torvalds } 26241da177e4SLinus Torvalds 2625f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 26265f2578e5SFUJITA Tomonori unsigned long store_size) 26271da177e4SLinus Torvalds { 26281da177e4SLinus Torvalds struct partition * pp; 26291da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 26301da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 26311da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 26321da177e4SLinus Torvalds 26331da177e4SLinus Torvalds /* assume partition table already zeroed */ 2634f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 26351da177e4SLinus Torvalds return; 26361da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 26371da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 26381da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug:build_parts: reducing " 26391da177e4SLinus Torvalds "partitions to %d\n", SDEBUG_MAX_PARTS); 26401da177e4SLinus Torvalds } 2641c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 26421da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 26431da177e4SLinus Torvalds / scsi_debug_num_parts; 26441da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 26451da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 26461da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 26471da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 26481da177e4SLinus Torvalds * heads_by_sects; 26491da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 26501da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 26511da177e4SLinus Torvalds 26521da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 26531da177e4SLinus Torvalds ramp[511] = 0xAA; 26541da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 26551da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 26561da177e4SLinus Torvalds start_sec = starts[k]; 26571da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 26581da177e4SLinus Torvalds pp->boot_ind = 0; 26591da177e4SLinus Torvalds 26601da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 26611da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 26621da177e4SLinus Torvalds / sdebug_sectors_per; 26631da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 26641da177e4SLinus Torvalds 26651da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 26661da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 26671da177e4SLinus Torvalds / sdebug_sectors_per; 26681da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 26691da177e4SLinus Torvalds 26701da177e4SLinus Torvalds pp->start_sect = start_sec; 26711da177e4SLinus Torvalds pp->nr_sects = end_sec - start_sec + 1; 26721da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 26731da177e4SLinus Torvalds } 26741da177e4SLinus Torvalds } 26751da177e4SLinus Torvalds 26761da177e4SLinus Torvalds static int schedule_resp(struct scsi_cmnd * cmnd, 26771da177e4SLinus Torvalds struct sdebug_dev_info * devip, 26781da177e4SLinus Torvalds done_funct_t done, int scsi_result, int delta_jiff) 26791da177e4SLinus Torvalds { 26801da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) { 26811da177e4SLinus Torvalds if (scsi_result) { 26821da177e4SLinus Torvalds struct scsi_device * sdp = cmnd->device; 26831da177e4SLinus Torvalds 2684c65b1445SDouglas Gilbert printk(KERN_INFO "scsi_debug: <%u %u %u %u> " 2685c65b1445SDouglas Gilbert "non-zero result=0x%x\n", sdp->host->host_no, 2686c65b1445SDouglas Gilbert sdp->channel, sdp->id, sdp->lun, scsi_result); 26871da177e4SLinus Torvalds } 26881da177e4SLinus Torvalds } 26891da177e4SLinus Torvalds if (cmnd && devip) { 26901da177e4SLinus Torvalds /* simulate autosense by this driver */ 26911da177e4SLinus Torvalds if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff)) 26921da177e4SLinus Torvalds memcpy(cmnd->sense_buffer, devip->sense_buff, 26931da177e4SLinus Torvalds (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ? 26941da177e4SLinus Torvalds SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE); 26951da177e4SLinus Torvalds } 26961da177e4SLinus Torvalds if (delta_jiff <= 0) { 26971da177e4SLinus Torvalds if (cmnd) 26981da177e4SLinus Torvalds cmnd->result = scsi_result; 26991da177e4SLinus Torvalds if (done) 27001da177e4SLinus Torvalds done(cmnd); 27011da177e4SLinus Torvalds return 0; 27021da177e4SLinus Torvalds } else { 27031da177e4SLinus Torvalds unsigned long iflags; 27041da177e4SLinus Torvalds int k; 27051da177e4SLinus Torvalds struct sdebug_queued_cmd * sqcp = NULL; 27061da177e4SLinus Torvalds 27071da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 270878d4e5a0SDouglas Gilbert for (k = 0; k < scsi_debug_max_queue; ++k) { 27091da177e4SLinus Torvalds sqcp = &queued_arr[k]; 27101da177e4SLinus Torvalds if (! sqcp->in_use) 27111da177e4SLinus Torvalds break; 27121da177e4SLinus Torvalds } 271378d4e5a0SDouglas Gilbert if (k >= scsi_debug_max_queue) { 27141da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 27151da177e4SLinus Torvalds printk(KERN_WARNING "scsi_debug: can_queue exceeded\n"); 27161da177e4SLinus Torvalds return 1; /* report busy to mid level */ 27171da177e4SLinus Torvalds } 27181da177e4SLinus Torvalds sqcp->in_use = 1; 27191da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 27201da177e4SLinus Torvalds sqcp->scsi_result = scsi_result; 27211da177e4SLinus Torvalds sqcp->done_funct = done; 27221da177e4SLinus Torvalds sqcp->cmnd_timer.function = timer_intr_handler; 27231da177e4SLinus Torvalds sqcp->cmnd_timer.data = k; 27241da177e4SLinus Torvalds sqcp->cmnd_timer.expires = jiffies + delta_jiff; 27251da177e4SLinus Torvalds add_timer(&sqcp->cmnd_timer); 27261da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 27271da177e4SLinus Torvalds if (cmnd) 27281da177e4SLinus Torvalds cmnd->result = 0; 27291da177e4SLinus Torvalds return 0; 27301da177e4SLinus Torvalds } 27311da177e4SLinus Torvalds } 273223183910SDouglas Gilbert /* Note: The following macros create attribute files in the 273323183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 273423183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 273523183910SDouglas Gilbert as it can when the corresponding attribute in the 273623183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 273723183910SDouglas Gilbert */ 2738c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 27395b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO); 2740c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 2741c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 27425b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO); 27435b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO); 2744c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 2745c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 274623183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 27475b94e232SMartin K. Petersen module_param_named(guard, scsi_debug_guard, int, S_IRUGO); 27485b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); 27495b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); 27505b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); 2751be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); 27525b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); 2753c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 275478d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); 2755c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 275678d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); 2757c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 2758c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 27595b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); 2760c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 27615b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); 2762c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 2763d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR); 2764c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 27655b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 27665b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); 27675b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); 27685b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); 27695b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); 2770c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 277123183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 277223183910SDouglas Gilbert S_IRUGO | S_IWUSR); 27735b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int, 27745b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 27751da177e4SLinus Torvalds 27761da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 27771da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 27781da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 27791da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 27801da177e4SLinus Torvalds 27811da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 27825b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 27831da177e4SLinus Torvalds MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)"); 2784c65b1445SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)"); 27855b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 27865b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 2787c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 2788beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 278923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 27905b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 27915b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 27925b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 27935b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 2794be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); 27955b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 2796c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 279778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to 255(def))"); 2798c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 279978d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 28001da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 2801c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 28025b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); 28036f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 28045b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 28051da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 2806d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 28071da177e4SLinus Torvalds MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])"); 2808ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 28095b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 28105b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 28116014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 28126014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 28135b94e232SMartin K. Petersen MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)"); 28145b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 28155b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 28161da177e4SLinus Torvalds 28171da177e4SLinus Torvalds static char sdebug_info[256]; 28181da177e4SLinus Torvalds 28191da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 28201da177e4SLinus Torvalds { 28211da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 28221da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 28231da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 28241da177e4SLinus Torvalds scsi_debug_opts); 28251da177e4SLinus Torvalds return sdebug_info; 28261da177e4SLinus Torvalds } 28271da177e4SLinus Torvalds 28281da177e4SLinus Torvalds /* scsi_debug_proc_info 28291da177e4SLinus Torvalds * Used if the driver currently has no own support for /proc/scsi 28301da177e4SLinus Torvalds */ 28311da177e4SLinus Torvalds static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, 28321da177e4SLinus Torvalds int length, int inout) 28331da177e4SLinus Torvalds { 28341da177e4SLinus Torvalds int len, pos, begin; 28351da177e4SLinus Torvalds int orig_length; 28361da177e4SLinus Torvalds 28371da177e4SLinus Torvalds orig_length = length; 28381da177e4SLinus Torvalds 28391da177e4SLinus Torvalds if (inout == 1) { 28401da177e4SLinus Torvalds char arr[16]; 28411da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 28421da177e4SLinus Torvalds 28431da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 28441da177e4SLinus Torvalds return -EACCES; 28451da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 28461da177e4SLinus Torvalds arr[minLen] = '\0'; 28471da177e4SLinus Torvalds if (1 != sscanf(arr, "%d", &pos)) 28481da177e4SLinus Torvalds return -EINVAL; 28491da177e4SLinus Torvalds scsi_debug_opts = pos; 28501da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 28511da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 28521da177e4SLinus Torvalds return length; 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds begin = 0; 28551da177e4SLinus Torvalds pos = len = sprintf(buffer, "scsi_debug adapter driver, version " 28561da177e4SLinus Torvalds "%s [%s]\n" 28571da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 28581da177e4SLinus Torvalds "every_nth=%d(curr:%d)\n" 28591da177e4SLinus Torvalds "delay=%d, max_luns=%d, scsi_level=%d\n" 28601da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 28611da177e4SLinus Torvalds "number of aborts=%d, device_reset=%d, bus_resets=%d, " 2862c6a44287SMartin K. Petersen "host_resets=%d\ndix_reads=%d dix_writes=%d dif_errors=%d\n", 28631da177e4SLinus Torvalds SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts, 28641da177e4SLinus Torvalds scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth, 28651da177e4SLinus Torvalds scsi_debug_cmnd_count, scsi_debug_delay, 28661da177e4SLinus Torvalds scsi_debug_max_luns, scsi_debug_scsi_level, 2867597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 2868597136abSMartin K. Petersen sdebug_sectors_per, num_aborts, num_dev_resets, num_bus_resets, 2869c6a44287SMartin K. Petersen num_host_resets, dix_reads, dix_writes, dif_errors); 28701da177e4SLinus Torvalds if (pos < offset) { 28711da177e4SLinus Torvalds len = 0; 28721da177e4SLinus Torvalds begin = pos; 28731da177e4SLinus Torvalds } 28741da177e4SLinus Torvalds *start = buffer + (offset - begin); /* Start of wanted data */ 28751da177e4SLinus Torvalds len -= (offset - begin); 28761da177e4SLinus Torvalds if (len > length) 28771da177e4SLinus Torvalds len = length; 28781da177e4SLinus Torvalds return len; 28791da177e4SLinus Torvalds } 28801da177e4SLinus Torvalds 28811da177e4SLinus Torvalds static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf) 28821da177e4SLinus Torvalds { 28831da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 28841da177e4SLinus Torvalds } 28851da177e4SLinus Torvalds 28861da177e4SLinus Torvalds static ssize_t sdebug_delay_store(struct device_driver * ddp, 28871da177e4SLinus Torvalds const char * buf, size_t count) 28881da177e4SLinus Torvalds { 28891da177e4SLinus Torvalds int delay; 28901da177e4SLinus Torvalds char work[20]; 28911da177e4SLinus Torvalds 28921da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 28931da177e4SLinus Torvalds if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) { 28941da177e4SLinus Torvalds scsi_debug_delay = delay; 28951da177e4SLinus Torvalds return count; 28961da177e4SLinus Torvalds } 28971da177e4SLinus Torvalds } 28981da177e4SLinus Torvalds return -EINVAL; 28991da177e4SLinus Torvalds } 29001da177e4SLinus Torvalds DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, 29011da177e4SLinus Torvalds sdebug_delay_store); 29021da177e4SLinus Torvalds 29031da177e4SLinus Torvalds static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf) 29041da177e4SLinus Torvalds { 29051da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 29061da177e4SLinus Torvalds } 29071da177e4SLinus Torvalds 29081da177e4SLinus Torvalds static ssize_t sdebug_opts_store(struct device_driver * ddp, 29091da177e4SLinus Torvalds const char * buf, size_t count) 29101da177e4SLinus Torvalds { 29111da177e4SLinus Torvalds int opts; 29121da177e4SLinus Torvalds char work[20]; 29131da177e4SLinus Torvalds 29141da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 29151da177e4SLinus Torvalds if (0 == strnicmp(work,"0x", 2)) { 29161da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 29171da177e4SLinus Torvalds goto opts_done; 29181da177e4SLinus Torvalds } else { 29191da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 29201da177e4SLinus Torvalds goto opts_done; 29211da177e4SLinus Torvalds } 29221da177e4SLinus Torvalds } 29231da177e4SLinus Torvalds return -EINVAL; 29241da177e4SLinus Torvalds opts_done: 29251da177e4SLinus Torvalds scsi_debug_opts = opts; 29261da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 29271da177e4SLinus Torvalds return count; 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, 29301da177e4SLinus Torvalds sdebug_opts_store); 29311da177e4SLinus Torvalds 29321da177e4SLinus Torvalds static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf) 29331da177e4SLinus Torvalds { 29341da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 29351da177e4SLinus Torvalds } 29361da177e4SLinus Torvalds static ssize_t sdebug_ptype_store(struct device_driver * ddp, 29371da177e4SLinus Torvalds const char * buf, size_t count) 29381da177e4SLinus Torvalds { 29391da177e4SLinus Torvalds int n; 29401da177e4SLinus Torvalds 29411da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29421da177e4SLinus Torvalds scsi_debug_ptype = n; 29431da177e4SLinus Torvalds return count; 29441da177e4SLinus Torvalds } 29451da177e4SLinus Torvalds return -EINVAL; 29461da177e4SLinus Torvalds } 29471da177e4SLinus Torvalds DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store); 29481da177e4SLinus Torvalds 29491da177e4SLinus Torvalds static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf) 29501da177e4SLinus Torvalds { 29511da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 29521da177e4SLinus Torvalds } 29531da177e4SLinus Torvalds static ssize_t sdebug_dsense_store(struct device_driver * ddp, 29541da177e4SLinus Torvalds const char * buf, size_t count) 29551da177e4SLinus Torvalds { 29561da177e4SLinus Torvalds int n; 29571da177e4SLinus Torvalds 29581da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 29591da177e4SLinus Torvalds scsi_debug_dsense = n; 29601da177e4SLinus Torvalds return count; 29611da177e4SLinus Torvalds } 29621da177e4SLinus Torvalds return -EINVAL; 29631da177e4SLinus Torvalds } 29641da177e4SLinus Torvalds DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show, 29651da177e4SLinus Torvalds sdebug_dsense_store); 29661da177e4SLinus Torvalds 296723183910SDouglas Gilbert static ssize_t sdebug_fake_rw_show(struct device_driver * ddp, char * buf) 296823183910SDouglas Gilbert { 296923183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 297023183910SDouglas Gilbert } 297123183910SDouglas Gilbert static ssize_t sdebug_fake_rw_store(struct device_driver * ddp, 297223183910SDouglas Gilbert const char * buf, size_t count) 297323183910SDouglas Gilbert { 297423183910SDouglas Gilbert int n; 297523183910SDouglas Gilbert 297623183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 297723183910SDouglas Gilbert scsi_debug_fake_rw = n; 297823183910SDouglas Gilbert return count; 297923183910SDouglas Gilbert } 298023183910SDouglas Gilbert return -EINVAL; 298123183910SDouglas Gilbert } 298223183910SDouglas Gilbert DRIVER_ATTR(fake_rw, S_IRUGO | S_IWUSR, sdebug_fake_rw_show, 298323183910SDouglas Gilbert sdebug_fake_rw_store); 298423183910SDouglas Gilbert 2985c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_show(struct device_driver * ddp, char * buf) 2986c65b1445SDouglas Gilbert { 2987c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 2988c65b1445SDouglas Gilbert } 2989c65b1445SDouglas Gilbert static ssize_t sdebug_no_lun_0_store(struct device_driver * ddp, 2990c65b1445SDouglas Gilbert const char * buf, size_t count) 2991c65b1445SDouglas Gilbert { 2992c65b1445SDouglas Gilbert int n; 2993c65b1445SDouglas Gilbert 2994c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 2995c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 2996c65b1445SDouglas Gilbert return count; 2997c65b1445SDouglas Gilbert } 2998c65b1445SDouglas Gilbert return -EINVAL; 2999c65b1445SDouglas Gilbert } 3000c65b1445SDouglas Gilbert DRIVER_ATTR(no_lun_0, S_IRUGO | S_IWUSR, sdebug_no_lun_0_show, 3001c65b1445SDouglas Gilbert sdebug_no_lun_0_store); 3002c65b1445SDouglas Gilbert 30031da177e4SLinus Torvalds static ssize_t sdebug_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 } 30071da177e4SLinus Torvalds static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, 30081da177e4SLinus Torvalds const char * buf, size_t count) 30091da177e4SLinus Torvalds { 30101da177e4SLinus Torvalds int n; 30111da177e4SLinus Torvalds 30121da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 30131da177e4SLinus Torvalds scsi_debug_num_tgts = n; 30141da177e4SLinus Torvalds sdebug_max_tgts_luns(); 30151da177e4SLinus Torvalds return count; 30161da177e4SLinus Torvalds } 30171da177e4SLinus Torvalds return -EINVAL; 30181da177e4SLinus Torvalds } 30191da177e4SLinus Torvalds DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, 30201da177e4SLinus Torvalds sdebug_num_tgts_store); 30211da177e4SLinus Torvalds 30221da177e4SLinus Torvalds static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf) 30231da177e4SLinus Torvalds { 30241da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 30251da177e4SLinus Torvalds } 30261da177e4SLinus Torvalds DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL); 30271da177e4SLinus Torvalds 30281da177e4SLinus Torvalds static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf) 30291da177e4SLinus Torvalds { 30301da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 30311da177e4SLinus Torvalds } 30321da177e4SLinus Torvalds DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL); 30331da177e4SLinus Torvalds 30341da177e4SLinus Torvalds static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf) 30351da177e4SLinus Torvalds { 30361da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 30371da177e4SLinus Torvalds } 30381da177e4SLinus Torvalds static ssize_t sdebug_every_nth_store(struct device_driver * ddp, 30391da177e4SLinus Torvalds const char * buf, size_t count) 30401da177e4SLinus Torvalds { 30411da177e4SLinus Torvalds int nth; 30421da177e4SLinus Torvalds 30431da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 30441da177e4SLinus Torvalds scsi_debug_every_nth = nth; 30451da177e4SLinus Torvalds scsi_debug_cmnd_count = 0; 30461da177e4SLinus Torvalds return count; 30471da177e4SLinus Torvalds } 30481da177e4SLinus Torvalds return -EINVAL; 30491da177e4SLinus Torvalds } 30501da177e4SLinus Torvalds DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, 30511da177e4SLinus Torvalds sdebug_every_nth_store); 30521da177e4SLinus Torvalds 30531da177e4SLinus Torvalds static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf) 30541da177e4SLinus Torvalds { 30551da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 30561da177e4SLinus Torvalds } 30571da177e4SLinus Torvalds static ssize_t sdebug_max_luns_store(struct device_driver * ddp, 30581da177e4SLinus Torvalds const char * buf, size_t count) 30591da177e4SLinus Torvalds { 30601da177e4SLinus Torvalds int n; 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 30631da177e4SLinus Torvalds scsi_debug_max_luns = n; 30641da177e4SLinus Torvalds sdebug_max_tgts_luns(); 30651da177e4SLinus Torvalds return count; 30661da177e4SLinus Torvalds } 30671da177e4SLinus Torvalds return -EINVAL; 30681da177e4SLinus Torvalds } 30691da177e4SLinus Torvalds DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, 30701da177e4SLinus Torvalds sdebug_max_luns_store); 30711da177e4SLinus Torvalds 307278d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_show(struct device_driver * ddp, char * buf) 307378d4e5a0SDouglas Gilbert { 307478d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); 307578d4e5a0SDouglas Gilbert } 307678d4e5a0SDouglas Gilbert static ssize_t sdebug_max_queue_store(struct device_driver * ddp, 307778d4e5a0SDouglas Gilbert const char * buf, size_t count) 307878d4e5a0SDouglas Gilbert { 307978d4e5a0SDouglas Gilbert int n; 308078d4e5a0SDouglas Gilbert 308178d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 308278d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 308378d4e5a0SDouglas Gilbert scsi_debug_max_queue = n; 308478d4e5a0SDouglas Gilbert return count; 308578d4e5a0SDouglas Gilbert } 308678d4e5a0SDouglas Gilbert return -EINVAL; 308778d4e5a0SDouglas Gilbert } 308878d4e5a0SDouglas Gilbert DRIVER_ATTR(max_queue, S_IRUGO | S_IWUSR, sdebug_max_queue_show, 308978d4e5a0SDouglas Gilbert sdebug_max_queue_store); 309078d4e5a0SDouglas Gilbert 309178d4e5a0SDouglas Gilbert static ssize_t sdebug_no_uld_show(struct device_driver * ddp, char * buf) 309278d4e5a0SDouglas Gilbert { 309378d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); 309478d4e5a0SDouglas Gilbert } 309578d4e5a0SDouglas Gilbert DRIVER_ATTR(no_uld, S_IRUGO, sdebug_no_uld_show, NULL); 309678d4e5a0SDouglas Gilbert 30971da177e4SLinus Torvalds static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf) 30981da177e4SLinus Torvalds { 30991da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 31001da177e4SLinus Torvalds } 31011da177e4SLinus Torvalds DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL); 31021da177e4SLinus Torvalds 3103c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_show(struct device_driver * ddp, char * buf) 3104c65b1445SDouglas Gilbert { 3105c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 3106c65b1445SDouglas Gilbert } 3107c65b1445SDouglas Gilbert static ssize_t sdebug_virtual_gb_store(struct device_driver * ddp, 3108c65b1445SDouglas Gilbert const char * buf, size_t count) 3109c65b1445SDouglas Gilbert { 3110c65b1445SDouglas Gilbert int n; 3111c65b1445SDouglas Gilbert 3112c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 3113c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 311428898873SFUJITA Tomonori 311528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 311628898873SFUJITA Tomonori 3117c65b1445SDouglas Gilbert return count; 3118c65b1445SDouglas Gilbert } 3119c65b1445SDouglas Gilbert return -EINVAL; 3120c65b1445SDouglas Gilbert } 3121c65b1445SDouglas Gilbert DRIVER_ATTR(virtual_gb, S_IRUGO | S_IWUSR, sdebug_virtual_gb_show, 3122c65b1445SDouglas Gilbert sdebug_virtual_gb_store); 3123c65b1445SDouglas Gilbert 31241da177e4SLinus Torvalds static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf) 31251da177e4SLinus Torvalds { 31261da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 31271da177e4SLinus Torvalds } 31281da177e4SLinus Torvalds 31291da177e4SLinus Torvalds static ssize_t sdebug_add_host_store(struct device_driver * ddp, 31301da177e4SLinus Torvalds const char * buf, size_t count) 31311da177e4SLinus Torvalds { 31321da177e4SLinus Torvalds int delta_hosts; 31331da177e4SLinus Torvalds 3134f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 31351da177e4SLinus Torvalds return -EINVAL; 31361da177e4SLinus Torvalds if (delta_hosts > 0) { 31371da177e4SLinus Torvalds do { 31381da177e4SLinus Torvalds sdebug_add_adapter(); 31391da177e4SLinus Torvalds } while (--delta_hosts); 31401da177e4SLinus Torvalds } else if (delta_hosts < 0) { 31411da177e4SLinus Torvalds do { 31421da177e4SLinus Torvalds sdebug_remove_adapter(); 31431da177e4SLinus Torvalds } while (++delta_hosts); 31441da177e4SLinus Torvalds } 31451da177e4SLinus Torvalds return count; 31461da177e4SLinus Torvalds } 31471da177e4SLinus Torvalds DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 31481da177e4SLinus Torvalds sdebug_add_host_store); 31491da177e4SLinus Torvalds 315023183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_show(struct device_driver * ddp, 315123183910SDouglas Gilbert char * buf) 315223183910SDouglas Gilbert { 315323183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 315423183910SDouglas Gilbert } 315523183910SDouglas Gilbert static ssize_t sdebug_vpd_use_hostno_store(struct device_driver * ddp, 315623183910SDouglas Gilbert const char * buf, size_t count) 315723183910SDouglas Gilbert { 315823183910SDouglas Gilbert int n; 315923183910SDouglas Gilbert 316023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 316123183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 316223183910SDouglas Gilbert return count; 316323183910SDouglas Gilbert } 316423183910SDouglas Gilbert return -EINVAL; 316523183910SDouglas Gilbert } 316623183910SDouglas Gilbert DRIVER_ATTR(vpd_use_hostno, S_IRUGO | S_IWUSR, sdebug_vpd_use_hostno_show, 316723183910SDouglas Gilbert sdebug_vpd_use_hostno_store); 316823183910SDouglas Gilbert 3169597136abSMartin K. Petersen static ssize_t sdebug_sector_size_show(struct device_driver * ddp, char * buf) 3170597136abSMartin K. Petersen { 3171597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 3172597136abSMartin K. Petersen } 3173597136abSMartin K. Petersen DRIVER_ATTR(sector_size, S_IRUGO, sdebug_sector_size_show, NULL); 3174597136abSMartin K. Petersen 3175c6a44287SMartin K. Petersen static ssize_t sdebug_dix_show(struct device_driver *ddp, char *buf) 3176c6a44287SMartin K. Petersen { 3177c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); 3178c6a44287SMartin K. Petersen } 3179c6a44287SMartin K. Petersen DRIVER_ATTR(dix, S_IRUGO, sdebug_dix_show, NULL); 3180c6a44287SMartin K. Petersen 3181c6a44287SMartin K. Petersen static ssize_t sdebug_dif_show(struct device_driver *ddp, char *buf) 3182c6a44287SMartin K. Petersen { 3183c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); 3184c6a44287SMartin K. Petersen } 3185c6a44287SMartin K. Petersen DRIVER_ATTR(dif, S_IRUGO, sdebug_dif_show, NULL); 3186c6a44287SMartin K. Petersen 3187c6a44287SMartin K. Petersen static ssize_t sdebug_guard_show(struct device_driver *ddp, char *buf) 3188c6a44287SMartin K. Petersen { 3189c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_guard); 3190c6a44287SMartin K. Petersen } 3191c6a44287SMartin K. Petersen DRIVER_ATTR(guard, S_IRUGO, sdebug_guard_show, NULL); 3192c6a44287SMartin K. Petersen 3193c6a44287SMartin K. Petersen static ssize_t sdebug_ato_show(struct device_driver *ddp, char *buf) 3194c6a44287SMartin K. Petersen { 3195c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); 3196c6a44287SMartin K. Petersen } 3197c6a44287SMartin K. Petersen DRIVER_ATTR(ato, S_IRUGO, sdebug_ato_show, NULL); 3198c6a44287SMartin K. Petersen 319944d92694SMartin K. Petersen static ssize_t sdebug_map_show(struct device_driver *ddp, char *buf) 320044d92694SMartin K. Petersen { 320144d92694SMartin K. Petersen ssize_t count; 320244d92694SMartin K. Petersen 32035b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 320444d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 320544d92694SMartin K. Petersen sdebug_store_sectors); 320644d92694SMartin K. Petersen 320744d92694SMartin K. Petersen count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); 320844d92694SMartin K. Petersen 320944d92694SMartin K. Petersen buf[count++] = '\n'; 321044d92694SMartin K. Petersen buf[count++] = 0; 321144d92694SMartin K. Petersen 321244d92694SMartin K. Petersen return count; 321344d92694SMartin K. Petersen } 321444d92694SMartin K. Petersen DRIVER_ATTR(map, S_IRUGO, sdebug_map_show, NULL); 321544d92694SMartin K. Petersen 3216d986788bSMartin Pitt static ssize_t sdebug_removable_show(struct device_driver *ddp, 3217d986788bSMartin Pitt char *buf) 3218d986788bSMartin Pitt { 3219d986788bSMartin Pitt return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0); 3220d986788bSMartin Pitt } 3221d986788bSMartin Pitt static ssize_t sdebug_removable_store(struct device_driver *ddp, 3222d986788bSMartin Pitt const char *buf, size_t count) 3223d986788bSMartin Pitt { 3224d986788bSMartin Pitt int n; 3225d986788bSMartin Pitt 3226d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 3227d986788bSMartin Pitt scsi_debug_removable = (n > 0); 3228d986788bSMartin Pitt return count; 3229d986788bSMartin Pitt } 3230d986788bSMartin Pitt return -EINVAL; 3231d986788bSMartin Pitt } 3232d986788bSMartin Pitt DRIVER_ATTR(removable, S_IRUGO | S_IWUSR, sdebug_removable_show, 3233d986788bSMartin Pitt sdebug_removable_store); 3234d986788bSMartin Pitt 3235c6a44287SMartin K. Petersen 323623183910SDouglas Gilbert /* Note: The following function creates attribute files in the 323723183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 323823183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 323923183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 324023183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 324123183910SDouglas Gilbert */ 32426ecaff7fSRandy Dunlap static int do_create_driverfs_files(void) 32431da177e4SLinus Torvalds { 32446ecaff7fSRandy Dunlap int ret; 32456ecaff7fSRandy Dunlap 32466ecaff7fSRandy Dunlap ret = driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); 32476ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); 32486ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 32496ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense); 32506ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 325123183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 32526ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 325378d4e5a0SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_queue); 325423183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 325578d4e5a0SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_no_uld); 32566ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 325723183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 32586ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); 32596ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); 3260d986788bSMartin Pitt ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_removable); 32616ecaff7fSRandy Dunlap ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 326223183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 326323183910SDouglas Gilbert ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 3264597136abSMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 3265c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dix); 3266c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_dif); 3267c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_guard); 3268c6a44287SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_ato); 326944d92694SMartin K. Petersen ret |= driver_create_file(&sdebug_driverfs_driver, &driver_attr_map); 32706ecaff7fSRandy Dunlap return ret; 32711da177e4SLinus Torvalds } 32721da177e4SLinus Torvalds 32731da177e4SLinus Torvalds static void do_remove_driverfs_files(void) 32741da177e4SLinus Torvalds { 327544d92694SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_map); 3276c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ato); 3277c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_guard); 3278c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dif); 3279c6a44287SMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dix); 3280597136abSMartin K. Petersen driver_remove_file(&sdebug_driverfs_driver, &driver_attr_sector_size); 328123183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_vpd_use_hostno); 328223183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_virtual_gb); 32831da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); 32841da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); 32851da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); 3286d986788bSMartin Pitt driver_remove_file(&sdebug_driverfs_driver, &driver_attr_removable); 32871da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); 328823183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); 328978d4e5a0SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_uld); 329023183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_no_lun_0); 329178d4e5a0SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_queue); 32921da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); 329323183910SDouglas Gilbert driver_remove_file(&sdebug_driverfs_driver, &driver_attr_fake_rw); 32941da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); 32951da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense); 32961da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); 32971da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); 32981da177e4SLinus Torvalds driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host); 32991da177e4SLinus Torvalds } 33001da177e4SLinus Torvalds 33019b906779SNicholas Bellinger struct device *pseudo_primary; 33028dea0d02SFUJITA Tomonori 33031da177e4SLinus Torvalds static int __init scsi_debug_init(void) 33041da177e4SLinus Torvalds { 33055f2578e5SFUJITA Tomonori unsigned long sz; 33061da177e4SLinus Torvalds int host_to_add; 33071da177e4SLinus Torvalds int k; 33086ecaff7fSRandy Dunlap int ret; 33091da177e4SLinus Torvalds 3310597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 3311597136abSMartin K. Petersen case 512: 3312597136abSMartin K. Petersen case 1024: 3313597136abSMartin K. Petersen case 2048: 3314597136abSMartin K. Petersen case 4096: 3315597136abSMartin K. Petersen break; 3316597136abSMartin K. Petersen default: 3317c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid sector_size %d\n", 3318597136abSMartin K. Petersen scsi_debug_sector_size); 3319597136abSMartin K. Petersen return -EINVAL; 3320597136abSMartin K. Petersen } 3321597136abSMartin K. Petersen 3322c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 3323c6a44287SMartin K. Petersen 3324c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 3325c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 3326395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 3327c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 3328c6a44287SMartin K. Petersen break; 3329c6a44287SMartin K. Petersen 3330c6a44287SMartin K. Petersen default: 3331395cef03SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif must be 0, 1, 2 or 3\n"); 3332c6a44287SMartin K. Petersen return -EINVAL; 3333c6a44287SMartin K. Petersen } 3334c6a44287SMartin K. Petersen 3335c6a44287SMartin K. Petersen if (scsi_debug_guard > 1) { 3336c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: guard must be 0 or 1\n"); 3337c6a44287SMartin K. Petersen return -EINVAL; 3338c6a44287SMartin K. Petersen } 3339c6a44287SMartin K. Petersen 3340c6a44287SMartin K. Petersen if (scsi_debug_ato > 1) { 3341c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: ato must be 0 or 1\n"); 3342c6a44287SMartin K. Petersen return -EINVAL; 3343c6a44287SMartin K. Petersen } 3344c6a44287SMartin K. Petersen 3345ea61fca5SMartin K. Petersen if (scsi_debug_physblk_exp > 15) { 3346ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: invalid physblk_exp %u\n", 3347ea61fca5SMartin K. Petersen scsi_debug_physblk_exp); 3348ea61fca5SMartin K. Petersen return -EINVAL; 3349ea61fca5SMartin K. Petersen } 3350ea61fca5SMartin K. Petersen 3351ea61fca5SMartin K. Petersen if (scsi_debug_lowest_aligned > 0x3fff) { 3352ea61fca5SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: lowest_aligned too big: %u\n", 3353ea61fca5SMartin K. Petersen scsi_debug_lowest_aligned); 3354ea61fca5SMartin K. Petersen return -EINVAL; 3355ea61fca5SMartin K. Petersen } 3356ea61fca5SMartin K. Petersen 33571da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 33581da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 33595f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 3360597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 336128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 33621da177e4SLinus Torvalds 33631da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 33641da177e4SLinus Torvalds sdebug_heads = 8; 33651da177e4SLinus Torvalds sdebug_sectors_per = 32; 33661da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 33671da177e4SLinus Torvalds sdebug_heads = 32; 33681da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 33691da177e4SLinus Torvalds sdebug_heads = 64; 33701da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33711da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33721da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 33731da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 33741da177e4SLinus Torvalds sdebug_heads = 255; 33751da177e4SLinus Torvalds sdebug_sectors_per = 63; 33761da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 33771da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 33781da177e4SLinus Torvalds } 33791da177e4SLinus Torvalds 33801da177e4SLinus Torvalds fake_storep = vmalloc(sz); 33811da177e4SLinus Torvalds if (NULL == fake_storep) { 33821da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); 33831da177e4SLinus Torvalds return -ENOMEM; 33841da177e4SLinus Torvalds } 33851da177e4SLinus Torvalds memset(fake_storep, 0, sz); 33861da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 3387f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 33881da177e4SLinus Torvalds 3389c6a44287SMartin K. Petersen if (scsi_debug_dif) { 3390c6a44287SMartin K. Petersen int dif_size; 3391c6a44287SMartin K. Petersen 3392c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 3393c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 3394c6a44287SMartin K. Petersen 3395c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: dif_storep %u bytes @ %p\n", 3396c6a44287SMartin K. Petersen dif_size, dif_storep); 3397c6a44287SMartin K. Petersen 3398c6a44287SMartin K. Petersen if (dif_storep == NULL) { 3399c6a44287SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (DIX)\n"); 3400c6a44287SMartin K. Petersen ret = -ENOMEM; 3401c6a44287SMartin K. Petersen goto free_vm; 3402c6a44287SMartin K. Petersen } 3403c6a44287SMartin K. Petersen 3404c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 3405c6a44287SMartin K. Petersen } 3406c6a44287SMartin K. Petersen 34075b94e232SMartin K. Petersen /* Logical Block Provisioning */ 34085b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 34096014759cSMartin K. Petersen scsi_debug_unmap_max_blocks = 34106014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); 34116014759cSMartin K. Petersen 34126014759cSMartin K. Petersen scsi_debug_unmap_max_desc = 34136014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_desc, 0U, 256U); 34146014759cSMartin K. Petersen 34156014759cSMartin K. Petersen scsi_debug_unmap_granularity = 34166014759cSMartin K. Petersen clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); 34176014759cSMartin K. Petersen 34186014759cSMartin K. Petersen if (scsi_debug_unmap_alignment && 3419ac17078aSAkinobu Mita scsi_debug_unmap_granularity <= 3420ac17078aSAkinobu Mita scsi_debug_unmap_alignment) { 342144d92694SMartin K. Petersen printk(KERN_ERR 3422ac17078aSAkinobu Mita "%s: ERR: unmap_granularity <= unmap_alignment\n", 342344d92694SMartin K. Petersen __func__); 342444d92694SMartin K. Petersen return -EINVAL; 342544d92694SMartin K. Petersen } 342644d92694SMartin K. Petersen 3427b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 3428b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 342944d92694SMartin K. Petersen 343044d92694SMartin K. Petersen printk(KERN_INFO "scsi_debug_init: %lu provisioning blocks\n", 343144d92694SMartin K. Petersen map_size); 343244d92694SMartin K. Petersen 343344d92694SMartin K. Petersen if (map_storep == NULL) { 343444d92694SMartin K. Petersen printk(KERN_ERR "scsi_debug_init: out of mem. (MAP)\n"); 343544d92694SMartin K. Petersen ret = -ENOMEM; 343644d92694SMartin K. Petersen goto free_vm; 343744d92694SMartin K. Petersen } 343844d92694SMartin K. Petersen 3439b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 344044d92694SMartin K. Petersen 344144d92694SMartin K. Petersen /* Map first 1KB for partition table */ 344244d92694SMartin K. Petersen if (scsi_debug_num_parts) 344344d92694SMartin K. Petersen map_region(0, 2); 344444d92694SMartin K. Petersen } 344544d92694SMartin K. Petersen 34469b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 34479b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 34489b906779SNicholas Bellinger printk(KERN_WARNING "scsi_debug: root_device_register() error\n"); 34499b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 34506ecaff7fSRandy Dunlap goto free_vm; 34516ecaff7fSRandy Dunlap } 34526ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 34536ecaff7fSRandy Dunlap if (ret < 0) { 34546ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: bus_register error: %d\n", 34556ecaff7fSRandy Dunlap ret); 34566ecaff7fSRandy Dunlap goto dev_unreg; 34576ecaff7fSRandy Dunlap } 34586ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 34596ecaff7fSRandy Dunlap if (ret < 0) { 34606ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_register error: %d\n", 34616ecaff7fSRandy Dunlap ret); 34626ecaff7fSRandy Dunlap goto bus_unreg; 34636ecaff7fSRandy Dunlap } 34646ecaff7fSRandy Dunlap ret = do_create_driverfs_files(); 34656ecaff7fSRandy Dunlap if (ret < 0) { 34666ecaff7fSRandy Dunlap printk(KERN_WARNING "scsi_debug: driver_create_file error: %d\n", 34676ecaff7fSRandy Dunlap ret); 34686ecaff7fSRandy Dunlap goto del_files; 34696ecaff7fSRandy Dunlap } 34701da177e4SLinus Torvalds 34716ecaff7fSRandy Dunlap init_all_queued(); 34721da177e4SLinus Torvalds 34731da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 34741da177e4SLinus Torvalds scsi_debug_add_host = 0; 34751da177e4SLinus Torvalds 34761da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 34771da177e4SLinus Torvalds if (sdebug_add_adapter()) { 34781da177e4SLinus Torvalds printk(KERN_ERR "scsi_debug_init: " 34791da177e4SLinus Torvalds "sdebug_add_adapter failed k=%d\n", k); 34801da177e4SLinus Torvalds break; 34811da177e4SLinus Torvalds } 34821da177e4SLinus Torvalds } 34831da177e4SLinus Torvalds 34841da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 34851da177e4SLinus Torvalds printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", 34861da177e4SLinus Torvalds scsi_debug_add_host); 34871da177e4SLinus Torvalds } 34881da177e4SLinus Torvalds return 0; 34896ecaff7fSRandy Dunlap 34906ecaff7fSRandy Dunlap del_files: 34916ecaff7fSRandy Dunlap do_remove_driverfs_files(); 34926ecaff7fSRandy Dunlap driver_unregister(&sdebug_driverfs_driver); 34936ecaff7fSRandy Dunlap bus_unreg: 34946ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 34956ecaff7fSRandy Dunlap dev_unreg: 34969b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 34976ecaff7fSRandy Dunlap free_vm: 349844d92694SMartin K. Petersen if (map_storep) 349944d92694SMartin K. Petersen vfree(map_storep); 3500c6a44287SMartin K. Petersen if (dif_storep) 3501c6a44287SMartin K. Petersen vfree(dif_storep); 35026ecaff7fSRandy Dunlap vfree(fake_storep); 35036ecaff7fSRandy Dunlap 35046ecaff7fSRandy Dunlap return ret; 35051da177e4SLinus Torvalds } 35061da177e4SLinus Torvalds 35071da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 35081da177e4SLinus Torvalds { 35091da177e4SLinus Torvalds int k = scsi_debug_add_host; 35101da177e4SLinus Torvalds 35111da177e4SLinus Torvalds stop_all_queued(); 35121da177e4SLinus Torvalds for (; k; k--) 35131da177e4SLinus Torvalds sdebug_remove_adapter(); 35141da177e4SLinus Torvalds do_remove_driverfs_files(); 35151da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 35161da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 35179b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 35181da177e4SLinus Torvalds 3519c6a44287SMartin K. Petersen if (dif_storep) 3520c6a44287SMartin K. Petersen vfree(dif_storep); 3521c6a44287SMartin K. Petersen 35221da177e4SLinus Torvalds vfree(fake_storep); 35231da177e4SLinus Torvalds } 35241da177e4SLinus Torvalds 35251da177e4SLinus Torvalds device_initcall(scsi_debug_init); 35261da177e4SLinus Torvalds module_exit(scsi_debug_exit); 35271da177e4SLinus Torvalds 35281da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 35291da177e4SLinus Torvalds { 35301da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 35311da177e4SLinus Torvalds 35321da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 35331da177e4SLinus Torvalds kfree(sdbg_host); 35341da177e4SLinus Torvalds } 35351da177e4SLinus Torvalds 35361da177e4SLinus Torvalds static int sdebug_add_adapter(void) 35371da177e4SLinus Torvalds { 35381da177e4SLinus Torvalds int k, devs_per_host; 35391da177e4SLinus Torvalds int error = 0; 35401da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 35418b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 35421da177e4SLinus Torvalds 354324669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 35441da177e4SLinus Torvalds if (NULL == sdbg_host) { 35451da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3546cadbd4a5SHarvey Harrison __func__, __LINE__); 35471da177e4SLinus Torvalds return -ENOMEM; 35481da177e4SLinus Torvalds } 35491da177e4SLinus Torvalds 35501da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 35511da177e4SLinus Torvalds 35521da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 35531da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 35545cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 35555cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 35561da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3557cadbd4a5SHarvey Harrison __func__, __LINE__); 35581da177e4SLinus Torvalds error = -ENOMEM; 35591da177e4SLinus Torvalds goto clean; 35601da177e4SLinus Torvalds } 35611da177e4SLinus Torvalds } 35621da177e4SLinus Torvalds 35631da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 35641da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 35651da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 35661da177e4SLinus Torvalds 35671da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 35689b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 35691da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 357071610f55SKay Sievers dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); 35711da177e4SLinus Torvalds 35721da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 35731da177e4SLinus Torvalds 35741da177e4SLinus Torvalds if (error) 35751da177e4SLinus Torvalds goto clean; 35761da177e4SLinus Torvalds 35771da177e4SLinus Torvalds ++scsi_debug_add_host; 35781da177e4SLinus Torvalds return error; 35791da177e4SLinus Torvalds 35801da177e4SLinus Torvalds clean: 35818b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 35828b40228fSFUJITA Tomonori dev_list) { 35831da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 35841da177e4SLinus Torvalds kfree(sdbg_devinfo); 35851da177e4SLinus Torvalds } 35861da177e4SLinus Torvalds 35871da177e4SLinus Torvalds kfree(sdbg_host); 35881da177e4SLinus Torvalds return error; 35891da177e4SLinus Torvalds } 35901da177e4SLinus Torvalds 35911da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 35921da177e4SLinus Torvalds { 35931da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 35941da177e4SLinus Torvalds 35951da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 35961da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 35971da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 35981da177e4SLinus Torvalds struct sdebug_host_info, host_list); 35991da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 36001da177e4SLinus Torvalds } 36011da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 36021da177e4SLinus Torvalds 36031da177e4SLinus Torvalds if (!sdbg_host) 36041da177e4SLinus Torvalds return; 36051da177e4SLinus Torvalds 36061da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 36071da177e4SLinus Torvalds --scsi_debug_add_host; 36081da177e4SLinus Torvalds } 36091da177e4SLinus Torvalds 3610639db475SFUJITA Tomonori static 3611f281233dSJeff Garzik int scsi_debug_queuecommand_lck(struct scsi_cmnd *SCpnt, done_funct_t done) 3612639db475SFUJITA Tomonori { 3613639db475SFUJITA Tomonori unsigned char *cmd = (unsigned char *) SCpnt->cmnd; 3614639db475SFUJITA Tomonori int len, k; 3615639db475SFUJITA Tomonori unsigned int num; 3616639db475SFUJITA Tomonori unsigned long long lba; 3617395cef03SMartin K. Petersen u32 ei_lba; 3618639db475SFUJITA Tomonori int errsts = 0; 3619639db475SFUJITA Tomonori int target = SCpnt->device->id; 3620639db475SFUJITA Tomonori struct sdebug_dev_info *devip = NULL; 3621639db475SFUJITA Tomonori int inj_recovered = 0; 3622639db475SFUJITA Tomonori int inj_transport = 0; 3623c6a44287SMartin K. Petersen int inj_dif = 0; 3624c6a44287SMartin K. Petersen int inj_dix = 0; 3625639db475SFUJITA Tomonori int delay_override = 0; 362644d92694SMartin K. Petersen int unmap = 0; 3627639db475SFUJITA Tomonori 3628639db475SFUJITA Tomonori scsi_set_resid(SCpnt, 0); 3629639db475SFUJITA Tomonori if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) { 3630639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: cmd "); 3631639db475SFUJITA Tomonori for (k = 0, len = SCpnt->cmd_len; k < len; ++k) 3632639db475SFUJITA Tomonori printk("%02x ", (int)cmd[k]); 3633639db475SFUJITA Tomonori printk("\n"); 3634639db475SFUJITA Tomonori } 3635639db475SFUJITA Tomonori 3636639db475SFUJITA Tomonori if (target == SCpnt->device->host->hostt->this_id) { 3637639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: initiator's id used as " 3638639db475SFUJITA Tomonori "target!\n"); 3639639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3640639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3641639db475SFUJITA Tomonori } 3642639db475SFUJITA Tomonori 3643639db475SFUJITA Tomonori if ((SCpnt->device->lun >= scsi_debug_max_luns) && 3644639db475SFUJITA Tomonori (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS)) 3645639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3646639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3647639db475SFUJITA Tomonori devip = devInfoReg(SCpnt->device); 3648639db475SFUJITA Tomonori if (NULL == devip) 3649639db475SFUJITA Tomonori return schedule_resp(SCpnt, NULL, done, 3650639db475SFUJITA Tomonori DID_NO_CONNECT << 16, 0); 3651639db475SFUJITA Tomonori 3652639db475SFUJITA Tomonori if ((scsi_debug_every_nth != 0) && 3653639db475SFUJITA Tomonori (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) { 3654639db475SFUJITA Tomonori scsi_debug_cmnd_count = 0; 3655639db475SFUJITA Tomonori if (scsi_debug_every_nth < -1) 3656639db475SFUJITA Tomonori scsi_debug_every_nth = -1; 3657639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 3658639db475SFUJITA Tomonori return 0; /* ignore command causing timeout */ 365918a4d0a2SMartin K. Petersen else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && 366018a4d0a2SMartin K. Petersen scsi_medium_access_command(SCpnt)) 366118a4d0a2SMartin K. Petersen return 0; /* time out reads and writes */ 3662639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts) 3663639db475SFUJITA Tomonori inj_recovered = 1; /* to reads and writes below */ 3664639db475SFUJITA Tomonori else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts) 3665639db475SFUJITA Tomonori inj_transport = 1; /* to reads and writes below */ 3666c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts) 3667c6a44287SMartin K. Petersen inj_dif = 1; /* to reads and writes below */ 3668c6a44287SMartin K. Petersen else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts) 3669c6a44287SMartin K. Petersen inj_dix = 1; /* to reads and writes below */ 3670639db475SFUJITA Tomonori } 3671639db475SFUJITA Tomonori 3672639db475SFUJITA Tomonori if (devip->wlun) { 3673639db475SFUJITA Tomonori switch (*cmd) { 3674639db475SFUJITA Tomonori case INQUIRY: 3675639db475SFUJITA Tomonori case REQUEST_SENSE: 3676639db475SFUJITA Tomonori case TEST_UNIT_READY: 3677639db475SFUJITA Tomonori case REPORT_LUNS: 3678639db475SFUJITA Tomonori break; /* only allowable wlun commands */ 3679639db475SFUJITA Tomonori default: 3680639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3681639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x " 3682639db475SFUJITA Tomonori "not supported for wlun\n", *cmd); 3683639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3684639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3685639db475SFUJITA Tomonori errsts = check_condition_result; 3686639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3687639db475SFUJITA Tomonori 0); 3688639db475SFUJITA Tomonori } 3689639db475SFUJITA Tomonori } 3690639db475SFUJITA Tomonori 3691639db475SFUJITA Tomonori switch (*cmd) { 3692639db475SFUJITA Tomonori case INQUIRY: /* mandatory, ignore unit attention */ 3693639db475SFUJITA Tomonori delay_override = 1; 3694639db475SFUJITA Tomonori errsts = resp_inquiry(SCpnt, target, devip); 3695639db475SFUJITA Tomonori break; 3696639db475SFUJITA Tomonori case REQUEST_SENSE: /* mandatory, ignore unit attention */ 3697639db475SFUJITA Tomonori delay_override = 1; 3698639db475SFUJITA Tomonori errsts = resp_requests(SCpnt, devip); 3699639db475SFUJITA Tomonori break; 3700639db475SFUJITA Tomonori case REZERO_UNIT: /* actually this is REWIND for SSC */ 3701639db475SFUJITA Tomonori case START_STOP: 3702639db475SFUJITA Tomonori errsts = resp_start_stop(SCpnt, devip); 3703639db475SFUJITA Tomonori break; 3704639db475SFUJITA Tomonori case ALLOW_MEDIUM_REMOVAL: 3705639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3706639db475SFUJITA Tomonori if (errsts) 3707639db475SFUJITA Tomonori break; 3708639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3709639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Medium removal %s\n", 3710639db475SFUJITA Tomonori cmd[4] ? "inhibited" : "enabled"); 3711639db475SFUJITA Tomonori break; 3712639db475SFUJITA Tomonori case SEND_DIAGNOSTIC: /* mandatory */ 3713639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3714639db475SFUJITA Tomonori break; 3715639db475SFUJITA Tomonori case TEST_UNIT_READY: /* mandatory */ 3716639db475SFUJITA Tomonori delay_override = 1; 3717639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3718639db475SFUJITA Tomonori break; 3719639db475SFUJITA Tomonori case RESERVE: 3720639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3721639db475SFUJITA Tomonori break; 3722639db475SFUJITA Tomonori case RESERVE_10: 3723639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3724639db475SFUJITA Tomonori break; 3725639db475SFUJITA Tomonori case RELEASE: 3726639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3727639db475SFUJITA Tomonori break; 3728639db475SFUJITA Tomonori case RELEASE_10: 3729639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3730639db475SFUJITA Tomonori break; 3731639db475SFUJITA Tomonori case READ_CAPACITY: 3732639db475SFUJITA Tomonori errsts = resp_readcap(SCpnt, devip); 3733639db475SFUJITA Tomonori break; 3734639db475SFUJITA Tomonori case SERVICE_ACTION_IN: 373544d92694SMartin K. Petersen if (cmd[1] == SAI_READ_CAPACITY_16) 373644d92694SMartin K. Petersen errsts = resp_readcap16(SCpnt, devip); 373744d92694SMartin K. Petersen else if (cmd[1] == SAI_GET_LBA_STATUS) { 373844d92694SMartin K. Petersen 37395b94e232SMartin K. Petersen if (scsi_debug_lbp() == 0) { 374044d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 374144d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 374244d92694SMartin K. Petersen errsts = check_condition_result; 374344d92694SMartin K. Petersen } else 374444d92694SMartin K. Petersen errsts = resp_get_lba_status(SCpnt, devip); 374544d92694SMartin K. Petersen } else { 3746639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3747639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3748639db475SFUJITA Tomonori errsts = check_condition_result; 3749639db475SFUJITA Tomonori } 3750639db475SFUJITA Tomonori break; 3751639db475SFUJITA Tomonori case MAINTENANCE_IN: 3752639db475SFUJITA Tomonori if (MI_REPORT_TARGET_PGS != cmd[1]) { 3753639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3754639db475SFUJITA Tomonori INVALID_OPCODE, 0); 3755639db475SFUJITA Tomonori errsts = check_condition_result; 3756639db475SFUJITA Tomonori break; 3757639db475SFUJITA Tomonori } 3758639db475SFUJITA Tomonori errsts = resp_report_tgtpgs(SCpnt, devip); 3759639db475SFUJITA Tomonori break; 3760639db475SFUJITA Tomonori case READ_16: 3761639db475SFUJITA Tomonori case READ_12: 3762639db475SFUJITA Tomonori case READ_10: 3763395cef03SMartin K. Petersen /* READ{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 READ_6: 3779395cef03SMartin K. Petersen read: 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_read(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; 3791639db475SFUJITA Tomonori } else if (inj_transport && (0 == errsts)) { 3792639db475SFUJITA Tomonori mk_sense_buffer(devip, ABORTED_COMMAND, 3793639db475SFUJITA Tomonori TRANSPORT_PROBLEM, ACK_NAK_TO); 3794639db475SFUJITA Tomonori errsts = check_condition_result; 3795c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3796c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3797c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3798c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3799c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3800c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3801639db475SFUJITA Tomonori } 3802639db475SFUJITA Tomonori break; 3803639db475SFUJITA Tomonori case REPORT_LUNS: /* mandatory, ignore unit attention */ 3804639db475SFUJITA Tomonori delay_override = 1; 3805639db475SFUJITA Tomonori errsts = resp_report_luns(SCpnt, devip); 3806639db475SFUJITA Tomonori break; 3807639db475SFUJITA Tomonori case VERIFY: /* 10 byte SBC-2 command */ 3808639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3809639db475SFUJITA Tomonori break; 3810639db475SFUJITA Tomonori case WRITE_16: 3811639db475SFUJITA Tomonori case WRITE_12: 3812639db475SFUJITA Tomonori case WRITE_10: 3813395cef03SMartin K. Petersen /* WRITE{10,12,16} and DIF Type 2 are natural enemies */ 3814395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 3815395cef03SMartin K. Petersen cmd[1] & 0xe0) { 3816395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3817395cef03SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 3818395cef03SMartin K. Petersen errsts = check_condition_result; 3819395cef03SMartin K. Petersen break; 3820395cef03SMartin K. Petersen } 3821395cef03SMartin K. Petersen 3822395cef03SMartin K. Petersen if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 3823395cef03SMartin K. Petersen scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 3824395cef03SMartin K. Petersen (cmd[1] & 0xe0) == 0) 3825395cef03SMartin K. Petersen printk(KERN_ERR "Unprotected RD/WR to DIF device\n"); 3826395cef03SMartin K. Petersen 3827395cef03SMartin K. Petersen /* fall through */ 3828639db475SFUJITA Tomonori case WRITE_6: 3829395cef03SMartin K. Petersen write: 3830639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3831639db475SFUJITA Tomonori if (errsts) 3832639db475SFUJITA Tomonori break; 3833639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3834639db475SFUJITA Tomonori break; 3835395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3836395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3837639db475SFUJITA Tomonori if (inj_recovered && (0 == errsts)) { 3838639db475SFUJITA Tomonori mk_sense_buffer(devip, RECOVERED_ERROR, 3839639db475SFUJITA Tomonori THRESHOLD_EXCEEDED, 0); 3840639db475SFUJITA Tomonori errsts = check_condition_result; 3841c6a44287SMartin K. Petersen } else if (inj_dif && (0 == errsts)) { 3842c6a44287SMartin K. Petersen mk_sense_buffer(devip, ABORTED_COMMAND, 0x10, 1); 3843c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3844c6a44287SMartin K. Petersen } else if (inj_dix && (0 == errsts)) { 3845c6a44287SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 0x10, 1); 3846c6a44287SMartin K. Petersen errsts = illegal_condition_result; 3847639db475SFUJITA Tomonori } 3848639db475SFUJITA Tomonori break; 384944d92694SMartin K. Petersen case WRITE_SAME_16: 38505b94e232SMartin K. Petersen case WRITE_SAME: 38516014759cSMartin K. Petersen if (cmd[1] & 0x8) { 38525b94e232SMartin K. Petersen if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) || 38535b94e232SMartin K. Petersen (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) { 38546014759cSMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 38556014759cSMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 38566014759cSMartin K. Petersen errsts = check_condition_result; 38576014759cSMartin K. Petersen } else 385844d92694SMartin K. Petersen unmap = 1; 38596014759cSMartin K. Petersen } 38606014759cSMartin K. Petersen if (errsts) 38616014759cSMartin K. Petersen break; 386244d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 386344d92694SMartin K. Petersen if (errsts) 386444d92694SMartin K. Petersen break; 386544d92694SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 386644d92694SMartin K. Petersen errsts = resp_write_same(SCpnt, lba, num, devip, ei_lba, unmap); 386744d92694SMartin K. Petersen break; 386844d92694SMartin K. Petersen case UNMAP: 386944d92694SMartin K. Petersen errsts = check_readiness(SCpnt, 0, devip); 387044d92694SMartin K. Petersen if (errsts) 387144d92694SMartin K. Petersen break; 387244d92694SMartin K. Petersen 38735b94e232SMartin K. Petersen if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) { 387444d92694SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 387544d92694SMartin K. Petersen INVALID_COMMAND_OPCODE, 0); 387644d92694SMartin K. Petersen errsts = check_condition_result; 387744d92694SMartin K. Petersen } else 387844d92694SMartin K. Petersen errsts = resp_unmap(SCpnt, devip); 387944d92694SMartin K. Petersen break; 3880639db475SFUJITA Tomonori case MODE_SENSE: 3881639db475SFUJITA Tomonori case MODE_SENSE_10: 3882639db475SFUJITA Tomonori errsts = resp_mode_sense(SCpnt, target, devip); 3883639db475SFUJITA Tomonori break; 3884639db475SFUJITA Tomonori case MODE_SELECT: 3885639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 1, devip); 3886639db475SFUJITA Tomonori break; 3887639db475SFUJITA Tomonori case MODE_SELECT_10: 3888639db475SFUJITA Tomonori errsts = resp_mode_select(SCpnt, 0, devip); 3889639db475SFUJITA Tomonori break; 3890639db475SFUJITA Tomonori case LOG_SENSE: 3891639db475SFUJITA Tomonori errsts = resp_log_sense(SCpnt, devip); 3892639db475SFUJITA Tomonori break; 3893639db475SFUJITA Tomonori case SYNCHRONIZE_CACHE: 3894639db475SFUJITA Tomonori delay_override = 1; 3895639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3896639db475SFUJITA Tomonori break; 3897639db475SFUJITA Tomonori case WRITE_BUFFER: 3898639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3899639db475SFUJITA Tomonori break; 3900639db475SFUJITA Tomonori case XDWRITEREAD_10: 3901639db475SFUJITA Tomonori if (!scsi_bidi_cmnd(SCpnt)) { 3902639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, 3903639db475SFUJITA Tomonori INVALID_FIELD_IN_CDB, 0); 3904639db475SFUJITA Tomonori errsts = check_condition_result; 3905639db475SFUJITA Tomonori break; 3906639db475SFUJITA Tomonori } 3907639db475SFUJITA Tomonori 3908639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 0, devip); 3909639db475SFUJITA Tomonori if (errsts) 3910639db475SFUJITA Tomonori break; 3911639db475SFUJITA Tomonori if (scsi_debug_fake_rw) 3912639db475SFUJITA Tomonori break; 3913395cef03SMartin K. Petersen get_data_transfer_info(cmd, &lba, &num, &ei_lba); 3914395cef03SMartin K. Petersen errsts = resp_read(SCpnt, lba, num, devip, ei_lba); 3915639db475SFUJITA Tomonori if (errsts) 3916639db475SFUJITA Tomonori break; 3917395cef03SMartin K. Petersen errsts = resp_write(SCpnt, lba, num, devip, ei_lba); 3918639db475SFUJITA Tomonori if (errsts) 3919639db475SFUJITA Tomonori break; 3920639db475SFUJITA Tomonori errsts = resp_xdwriteread(SCpnt, lba, num, devip); 3921639db475SFUJITA Tomonori break; 3922395cef03SMartin K. Petersen case VARIABLE_LENGTH_CMD: 3923395cef03SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) { 3924395cef03SMartin K. Petersen 3925395cef03SMartin K. Petersen if ((cmd[10] & 0xe0) == 0) 3926395cef03SMartin K. Petersen printk(KERN_ERR 3927395cef03SMartin K. Petersen "Unprotected RD/WR to DIF device\n"); 3928395cef03SMartin K. Petersen 3929395cef03SMartin K. Petersen if (cmd[9] == READ_32) { 3930395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3931395cef03SMartin K. Petersen goto read; 3932395cef03SMartin K. Petersen } 3933395cef03SMartin K. Petersen 3934395cef03SMartin K. Petersen if (cmd[9] == WRITE_32) { 3935395cef03SMartin K. Petersen BUG_ON(SCpnt->cmd_len < 32); 3936395cef03SMartin K. Petersen goto write; 3937395cef03SMartin K. Petersen } 3938395cef03SMartin K. Petersen } 3939395cef03SMartin K. Petersen 3940395cef03SMartin K. Petersen mk_sense_buffer(devip, ILLEGAL_REQUEST, 3941395cef03SMartin K. Petersen INVALID_FIELD_IN_CDB, 0); 3942395cef03SMartin K. Petersen errsts = check_condition_result; 3943395cef03SMartin K. Petersen break; 3944395cef03SMartin K. Petersen 3945639db475SFUJITA Tomonori default: 3946639db475SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3947639db475SFUJITA Tomonori printk(KERN_INFO "scsi_debug: Opcode: 0x%x not " 3948639db475SFUJITA Tomonori "supported\n", *cmd); 3949639db475SFUJITA Tomonori errsts = check_readiness(SCpnt, 1, devip); 3950639db475SFUJITA Tomonori if (errsts) 3951639db475SFUJITA Tomonori break; /* Unit attention takes precedence */ 3952639db475SFUJITA Tomonori mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 3953639db475SFUJITA Tomonori errsts = check_condition_result; 3954639db475SFUJITA Tomonori break; 3955639db475SFUJITA Tomonori } 3956639db475SFUJITA Tomonori return schedule_resp(SCpnt, devip, done, errsts, 3957639db475SFUJITA Tomonori (delay_override ? 0 : scsi_debug_delay)); 3958639db475SFUJITA Tomonori } 3959639db475SFUJITA Tomonori 3960f281233dSJeff Garzik static DEF_SCSI_QCMD(scsi_debug_queuecommand) 3961f281233dSJeff Garzik 39629e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 39639e603ca0SFUJITA Tomonori .proc_info = scsi_debug_proc_info, 39649e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 39659e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 39669e603ca0SFUJITA Tomonori .info = scsi_debug_info, 39679e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 39689e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 39699e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 39709e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 39719e603ca0SFUJITA Tomonori .queuecommand = scsi_debug_queuecommand, 39729e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 39739e603ca0SFUJITA Tomonori .eh_bus_reset_handler = scsi_debug_bus_reset, 39749e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 39759e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 39769e603ca0SFUJITA Tomonori .bios_param = scsi_debug_biosparam, 39779e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 39789e603ca0SFUJITA Tomonori .this_id = 7, 39799e603ca0SFUJITA Tomonori .sg_tablesize = 256, 39809e603ca0SFUJITA Tomonori .cmd_per_lun = 16, 39819e603ca0SFUJITA Tomonori .max_sectors = 0xffff, 39829e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 39839e603ca0SFUJITA Tomonori .module = THIS_MODULE, 39849e603ca0SFUJITA Tomonori }; 39859e603ca0SFUJITA Tomonori 39861da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 39871da177e4SLinus Torvalds { 39881da177e4SLinus Torvalds int error = 0; 39891da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 39901da177e4SLinus Torvalds struct Scsi_Host *hpnt; 3991c6a44287SMartin K. Petersen int host_prot; 39921da177e4SLinus Torvalds 39931da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 39941da177e4SLinus Torvalds 399578d4e5a0SDouglas Gilbert sdebug_driver_template.can_queue = scsi_debug_max_queue; 39961da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 39971da177e4SLinus Torvalds if (NULL == hpnt) { 3998cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_register failed\n", __func__); 39991da177e4SLinus Torvalds error = -ENODEV; 40001da177e4SLinus Torvalds return error; 40011da177e4SLinus Torvalds } 40021da177e4SLinus Torvalds 40031da177e4SLinus Torvalds sdbg_host->shost = hpnt; 40041da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 40051da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 40061da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 40071da177e4SLinus Torvalds else 40081da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 4009c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 40101da177e4SLinus Torvalds 4011c6a44287SMartin K. Petersen host_prot = 0; 4012c6a44287SMartin K. Petersen 4013c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 4014c6a44287SMartin K. Petersen 4015c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4016c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE1_PROTECTION; 4017c6a44287SMartin K. Petersen if (scsi_debug_dix) 4018c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE1_PROTECTION; 4019c6a44287SMartin K. Petersen break; 4020c6a44287SMartin K. Petersen 4021c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4022c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE2_PROTECTION; 4023c6a44287SMartin K. Petersen if (scsi_debug_dix) 4024c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE2_PROTECTION; 4025c6a44287SMartin K. Petersen break; 4026c6a44287SMartin K. Petersen 4027c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4028c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE3_PROTECTION; 4029c6a44287SMartin K. Petersen if (scsi_debug_dix) 4030c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE3_PROTECTION; 4031c6a44287SMartin K. Petersen break; 4032c6a44287SMartin K. Petersen 4033c6a44287SMartin K. Petersen default: 4034c6a44287SMartin K. Petersen if (scsi_debug_dix) 4035c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE0_PROTECTION; 4036c6a44287SMartin K. Petersen break; 4037c6a44287SMartin K. Petersen } 4038c6a44287SMartin K. Petersen 4039c6a44287SMartin K. Petersen scsi_host_set_prot(hpnt, host_prot); 4040c6a44287SMartin K. Petersen 4041c6a44287SMartin K. Petersen printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", 4042c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 4043c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 4044c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 4045c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 4046c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 4047c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 4048c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 4049c6a44287SMartin K. Petersen 4050c6a44287SMartin K. Petersen if (scsi_debug_guard == 1) 4051c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 4052c6a44287SMartin K. Petersen else 4053c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 4054c6a44287SMartin K. Petersen 40551da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 40561da177e4SLinus Torvalds if (error) { 4057cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); 40581da177e4SLinus Torvalds error = -ENODEV; 40591da177e4SLinus Torvalds scsi_host_put(hpnt); 40601da177e4SLinus Torvalds } else 40611da177e4SLinus Torvalds scsi_scan_host(hpnt); 40621da177e4SLinus Torvalds 40631da177e4SLinus Torvalds 40641da177e4SLinus Torvalds return error; 40651da177e4SLinus Torvalds } 40661da177e4SLinus Torvalds 40671da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 40681da177e4SLinus Torvalds { 40691da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 40708b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 40711da177e4SLinus Torvalds 40721da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 40731da177e4SLinus Torvalds 40741da177e4SLinus Torvalds if (!sdbg_host) { 40751da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 4076cadbd4a5SHarvey Harrison __func__); 40771da177e4SLinus Torvalds return -ENODEV; 40781da177e4SLinus Torvalds } 40791da177e4SLinus Torvalds 40801da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 40811da177e4SLinus Torvalds 40828b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 40838b40228fSFUJITA Tomonori dev_list) { 40841da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 40851da177e4SLinus Torvalds kfree(sdbg_devinfo); 40861da177e4SLinus Torvalds } 40871da177e4SLinus Torvalds 40881da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 40891da177e4SLinus Torvalds return 0; 40901da177e4SLinus Torvalds } 40911da177e4SLinus Torvalds 40928dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 40938dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 40941da177e4SLinus Torvalds { 40958dea0d02SFUJITA Tomonori return 1; 40968dea0d02SFUJITA Tomonori } 40971da177e4SLinus Torvalds 40988dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 40998dea0d02SFUJITA Tomonori .name = "pseudo", 41008dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 41018dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 41028dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 41038dea0d02SFUJITA Tomonori }; 4104