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 28c1287970STomas Winkler 29c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 30c1287970STomas Winkler 311da177e4SLinus Torvalds #include <linux/module.h> 321da177e4SLinus Torvalds 331da177e4SLinus Torvalds #include <linux/kernel.h> 341da177e4SLinus Torvalds #include <linux/errno.h> 351da177e4SLinus Torvalds #include <linux/timer.h> 365a0e3ad6STejun Heo #include <linux/slab.h> 371da177e4SLinus Torvalds #include <linux/types.h> 381da177e4SLinus Torvalds #include <linux/string.h> 391da177e4SLinus Torvalds #include <linux/genhd.h> 401da177e4SLinus Torvalds #include <linux/fs.h> 411da177e4SLinus Torvalds #include <linux/init.h> 421da177e4SLinus Torvalds #include <linux/proc_fs.h> 431da177e4SLinus Torvalds #include <linux/vmalloc.h> 441da177e4SLinus Torvalds #include <linux/moduleparam.h> 45852e034dSJens Axboe #include <linux/scatterlist.h> 461da177e4SLinus Torvalds #include <linux/blkdev.h> 47c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 48cbf67842SDouglas Gilbert #include <linux/spinlock.h> 49cbf67842SDouglas Gilbert #include <linux/interrupt.h> 50cbf67842SDouglas Gilbert #include <linux/atomic.h> 51cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 52c6a44287SMartin K. Petersen 53c6a44287SMartin K. Petersen #include <net/checksum.h> 549ff26eefSFUJITA Tomonori 5544d92694SMartin K. Petersen #include <asm/unaligned.h> 5644d92694SMartin K. Petersen 579ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 589ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 599ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 601da177e4SLinus Torvalds #include <scsi/scsi_host.h> 611da177e4SLinus Torvalds #include <scsi/scsicam.h> 62a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 63cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 64395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 651da177e4SLinus Torvalds 66c6a44287SMartin K. Petersen #include "sd.h" 671da177e4SLinus Torvalds #include "scsi_logging.h" 681da177e4SLinus Torvalds 6922017ed2SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.85" 7022017ed2SDouglas Gilbert static const char *scsi_debug_version_date = "20141022"; 71cbf67842SDouglas Gilbert 72cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 731da177e4SLinus Torvalds 746f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 75c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 76c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 77c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 781da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 79c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 801da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 8122017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 821da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 83c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 84cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 85cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8619c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8719c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8822017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8922017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 90cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 91cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 92cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 9322017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 941da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 956f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 96c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 97c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9822017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 99acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 100acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 1011da177e4SLinus Torvalds 1026f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 1036f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 1046f3cbf55SDouglas Gilbert 1051da177e4SLinus Torvalds 1061da177e4SLinus Torvalds /* Default values for driver parameters */ 1071da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1081da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1091da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1111da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1121da177e4SLinus Torvalds */ 1135b94e232SMartin K. Petersen #define DEF_ATO 1 114cbf67842SDouglas Gilbert #define DEF_DELAY 1 /* if > 0 unit is a jiffy */ 1151da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1165b94e232SMartin K. Petersen #define DEF_DIF 0 1175b94e232SMartin K. Petersen #define DEF_DIX 0 1185b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1191da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1205b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1215b94e232SMartin K. Petersen #define DEF_GUARD 0 122cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1235b94e232SMartin K. Petersen #define DEF_LBPU 0 1245b94e232SMartin K. Petersen #define DEF_LBPWS 0 1255b94e232SMartin K. Petersen #define DEF_LBPWS10 0 126be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1275b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 128cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1295b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1301da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1311da177e4SLinus Torvalds #define DEF_OPTS 0 132e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64 1335b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 1345b94e232SMartin K. Petersen #define DEF_PTYPE 0 135d986788bSMartin Pitt #define DEF_REMOVABLE false 136e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */ 1375b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1385b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1395b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1406014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1416014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1425b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1435b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1445b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 145c2248fc9SDouglas Gilbert #define DEF_STRICT 0 146cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999 1471da177e4SLinus Torvalds 1481da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1491da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1501da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1511da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1521da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1536f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 154c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR 32 155c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR 64 15618a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT 128 157cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_SHORT_TRANSFER 0x100 158cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_Q_NOISE 0x200 159cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_TSF 0x400 160cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RARE_TSF 0x800 161cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_N_WCE 0x1000 162cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RESET_NOISE 0x2000 163cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000 164cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000) 1651da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1661da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1671da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1681da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1696f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1706f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1711da177e4SLinus Torvalds * 1721da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 1731da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1741da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1751da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1766f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1776f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1781da177e4SLinus Torvalds * This will continue until some other action occurs (e.g. the user 1791da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1801da177e4SLinus Torvalds */ 1811da177e4SLinus Torvalds 182cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in 183cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 184cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 185cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 186cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 187cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 188cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1890d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 19019c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 191acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 192acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 193acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 194cbf67842SDouglas Gilbert 195cbf67842SDouglas Gilbert /* for check_readiness() */ 196c2248fc9SDouglas Gilbert #define UAS_ONLY 1 /* check for UAs only */ 197c2248fc9SDouglas Gilbert #define UAS_TUR 0 /* if no UAs then check if media access possible */ 198cbf67842SDouglas Gilbert 1991da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2001da177e4SLinus Torvalds * sector on read commands: */ 2011da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 20232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2051da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2061da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2071da177e4SLinus Torvalds 208cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued 209cbf67842SDouglas Gilbert * (for response) at one time. Can be reduced by max_queue option. Command 210cbf67842SDouglas Gilbert * responses are not queued when delay=0 and ndelay=0. The per-device 211cbf67842SDouglas Gilbert * DEF_CMD_PER_LUN can be changed via sysfs: 212cbf67842SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed 213cbf67842SDouglas Gilbert * SCSI_DEBUG_CANQUEUE. */ 214cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */ 215cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 216cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 217cbf67842SDouglas Gilbert 218cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE 219cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE" 220cbf67842SDouglas Gilbert #endif 22178d4e5a0SDouglas Gilbert 222c2248fc9SDouglas Gilbert /* SCSI opcodes (first byte of cdb) mapped onto these indexes */ 223c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 224c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 225c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 226c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 227c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 228c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 229c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 230c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 231c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 232c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 233c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 234c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 235c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 236c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 237c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 238c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 239c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 240c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 241c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 242c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 243c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 244c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 245c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 246c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 247c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 248c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 249c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 250c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 251c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 252c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 253c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 254c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 255c2248fc9SDouglas Gilbert }; 256c2248fc9SDouglas Gilbert 257c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 258c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 259c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 260c2248fc9SDouglas Gilbert 0, 0, 0, 0, 261c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 262c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 263c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 264c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 265c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 266c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 267c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 268c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 269c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 270c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 271c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 272c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 273c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 274c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 275c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 276c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 277c2248fc9SDouglas Gilbert /* 0x60; 0x60->0x7d are reserved */ 278c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 279c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 280c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 281c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 282c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 283c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 284c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 285c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 286c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 287c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 288c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 289c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 290c2248fc9SDouglas Gilbert 0, 0, 0, 0, 291c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 292c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 293c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 294c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 295c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 296c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 297c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 298c2248fc9SDouglas Gilbert }; 299c2248fc9SDouglas Gilbert 300c2248fc9SDouglas Gilbert #define F_D_IN 1 301c2248fc9SDouglas Gilbert #define F_D_OUT 2 302c2248fc9SDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 303c2248fc9SDouglas Gilbert #define F_D_UNKN 8 304c2248fc9SDouglas Gilbert #define F_RL_WLUN_OK 0x10 305c2248fc9SDouglas Gilbert #define F_SKIP_UA 0x20 306c2248fc9SDouglas Gilbert #define F_DELAY_OVERR 0x40 307c2248fc9SDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 308c2248fc9SDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 309c2248fc9SDouglas Gilbert #define F_INV_OP 0x200 310c2248fc9SDouglas Gilbert #define F_FAKE_RW 0x400 311c2248fc9SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 312c2248fc9SDouglas Gilbert 313c2248fc9SDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 314c2248fc9SDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 315c2248fc9SDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 316c2248fc9SDouglas Gilbert 317c2248fc9SDouglas Gilbert struct sdebug_dev_info; 318c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 319c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 320c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 321c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 322c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 323c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 324c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 325c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 326c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 327c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 328c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 329c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 330c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 331c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 33238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 33338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 334c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 335c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 336c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 33738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 338acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 339c2248fc9SDouglas Gilbert 340c2248fc9SDouglas Gilbert struct opcode_info_t { 341c2248fc9SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff 342c2248fc9SDouglas Gilbert * for terminating element */ 343c2248fc9SDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 344c2248fc9SDouglas Gilbert u16 sa; /* service action */ 345c2248fc9SDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 346c2248fc9SDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 347c2248fc9SDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 348c2248fc9SDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 349c2248fc9SDouglas Gilbert /* ignore cdb bytes after position 15 */ 350c2248fc9SDouglas Gilbert }; 351c2248fc9SDouglas Gilbert 352c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 353c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 354c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 355c2248fc9SDouglas Gilbert }; 356c2248fc9SDouglas Gilbert 357c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 358c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 359c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 360c2248fc9SDouglas Gilbert }; 361c2248fc9SDouglas Gilbert 362c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 363c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 364c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 365c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 366c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 367c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 368c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 369c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 370c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 371c2248fc9SDouglas Gilbert }; 372c2248fc9SDouglas Gilbert 373c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 374c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 375c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 376c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 377c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 378c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 379c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 380c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 381c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 382c2248fc9SDouglas Gilbert }; 383c2248fc9SDouglas Gilbert 384c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 385c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 386c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 387c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 388c2248fc9SDouglas Gilbert }; 389c2248fc9SDouglas Gilbert 390c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 391c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 392c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 393c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 394c2248fc9SDouglas Gilbert }; 395c2248fc9SDouglas Gilbert 396c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 39738d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 398c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 399c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 40038d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 401c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 402c2248fc9SDouglas Gilbert 0, 0} }, 403c2248fc9SDouglas Gilbert }; 404c2248fc9SDouglas Gilbert 405c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 406c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 407c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 408c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 409c2248fc9SDouglas Gilbert }; 410c2248fc9SDouglas Gilbert 411c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 412c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 413c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 414c2248fc9SDouglas Gilbert }; 415c2248fc9SDouglas Gilbert 416c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 417c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 418c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 419c2248fc9SDouglas Gilbert }; 420c2248fc9SDouglas Gilbert 421c2248fc9SDouglas Gilbert 422c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 423c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 424c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 425c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 426c2248fc9SDouglas Gilbert /* 0 */ 427c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 428c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 429c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 430c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 431c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 432c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 433c2248fc9SDouglas Gilbert 0, 0} }, 434c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 435c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 436c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 437c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 438c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 439c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 440c2248fc9SDouglas Gilbert 0} }, 441c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 442c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 443c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 444c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 445c2248fc9SDouglas Gilbert 0, 0, 0} }, 446c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 447c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 448c2248fc9SDouglas Gilbert 0, 0} }, 449c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 450c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 451c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 452c2248fc9SDouglas Gilbert /* 10 */ 453c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 454c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 455c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 456c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 457c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 458c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 459c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 460c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 461c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 462c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 463c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 464c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 465c2248fc9SDouglas Gilbert 0} }, 466c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 467c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 468c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */ 469c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 470c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 471c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 472c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 473c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 474c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 475c2248fc9SDouglas Gilbert 0} }, 476c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 477c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 478c2248fc9SDouglas Gilbert 0} }, 479c2248fc9SDouglas Gilbert /* 20 */ 480c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */ 481c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 482c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 483c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 484c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 485c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 486c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 487c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 488c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 489c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 490c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 491c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 492c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 493acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 494acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 495acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 496c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 497c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 498c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 499c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 500c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 501c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 50238d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 503c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 504c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 505c2248fc9SDouglas Gilbert 506c2248fc9SDouglas Gilbert /* 30 */ 507c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 508c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 509c2248fc9SDouglas Gilbert }; 510c2248fc9SDouglas Gilbert 511817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t { 512817fd66bSDouglas Gilbert bool inj_recovered; 513817fd66bSDouglas Gilbert bool inj_transport; 514817fd66bSDouglas Gilbert bool inj_dif; 515817fd66bSDouglas Gilbert bool inj_dix; 516817fd66bSDouglas Gilbert bool inj_short; 517817fd66bSDouglas Gilbert }; 518817fd66bSDouglas Gilbert 5191da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 5205b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO; 5211da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 5221da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 5235b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF; 5245b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX; 5255b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE; 5261da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 5275b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW; 52868aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD; 5295b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; 5301da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 53178d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; 532cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 533cbf67842SDouglas Gilbert static int scsi_debug_ndelay = DEF_NDELAY; 534c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 5355b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0; 5365b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS; 5375b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 538e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS; 5395b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS; 5405b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; 5415b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 5425b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 5435b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 5445b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 5455b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 5465b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU; 5475b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS; 5485b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; 549be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ; 5506014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 5515b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; 5525b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 5535b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 5545b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; 555d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE; 5560759c666SAkinobu Mita static bool scsi_debug_clustering; 557cbf67842SDouglas Gilbert static bool scsi_debug_host_lock = DEF_HOST_LOCK; 558c2248fc9SDouglas Gilbert static bool scsi_debug_strict = DEF_STRICT; 559817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 5601da177e4SLinus Torvalds 561cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count; 562cbf67842SDouglas Gilbert static atomic_t sdebug_completions; 563cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */ 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 5661da177e4SLinus Torvalds 567c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 5681da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 5691da177e4SLinus Torvalds 5701da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 5711da177e4SLinus Torvalds may still need them */ 5721da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 5731da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 5741da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 5751da177e4SLinus Torvalds 5761da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 5771da177e4SLinus Torvalds 578395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32 5799e603ca0SFUJITA Tomonori 5805b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void) 5815b94e232SMartin K. Petersen { 582cbf67842SDouglas Gilbert return ((0 == scsi_debug_fake_rw) && 583cbf67842SDouglas Gilbert (scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10)); 5845b94e232SMartin K. Petersen } 5855b94e232SMartin K. Petersen 5861da177e4SLinus Torvalds struct sdebug_dev_info { 5871da177e4SLinus Torvalds struct list_head dev_list; 5881da177e4SLinus Torvalds unsigned int channel; 5891da177e4SLinus Torvalds unsigned int target; 5909cb78c16SHannes Reinecke u64 lun; 5911da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 592cbf67842SDouglas Gilbert unsigned long uas_bm[1]; 593cbf67842SDouglas Gilbert atomic_t num_in_q; 594c2248fc9SDouglas Gilbert char stopped; /* TODO: should be atomic */ 595c2248fc9SDouglas Gilbert bool used; 5961da177e4SLinus Torvalds }; 5971da177e4SLinus Torvalds 5981da177e4SLinus Torvalds struct sdebug_host_info { 5991da177e4SLinus Torvalds struct list_head host_list; 6001da177e4SLinus Torvalds struct Scsi_Host *shost; 6011da177e4SLinus Torvalds struct device dev; 6021da177e4SLinus Torvalds struct list_head dev_info_list; 6031da177e4SLinus Torvalds }; 6041da177e4SLinus Torvalds 6051da177e4SLinus Torvalds #define to_sdebug_host(d) \ 6061da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 6071da177e4SLinus Torvalds 6081da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 6091da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 6101da177e4SLinus Torvalds 611cbf67842SDouglas Gilbert 612cbf67842SDouglas Gilbert struct sdebug_hrtimer { /* ... is derived from hrtimer */ 613cbf67842SDouglas Gilbert struct hrtimer hrt; /* must be first element */ 614cbf67842SDouglas Gilbert int qa_indx; 615cbf67842SDouglas Gilbert }; 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds struct sdebug_queued_cmd { 618cbf67842SDouglas Gilbert /* in_use flagged by a bit in queued_in_use_bm[] */ 619cbf67842SDouglas Gilbert struct timer_list *cmnd_timerp; 620cbf67842SDouglas Gilbert struct tasklet_struct *tletp; 621cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hrtp; 6221da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 6231da177e4SLinus Torvalds }; 6241da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 625cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS]; 626cbf67842SDouglas Gilbert 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 629e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep; /* protection info */ 63044d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6311da177e4SLinus Torvalds 63244d92694SMartin K. Petersen static unsigned long map_size; 633cbf67842SDouglas Gilbert static int num_aborts; 634cbf67842SDouglas Gilbert static int num_dev_resets; 635cbf67842SDouglas Gilbert static int num_target_resets; 636cbf67842SDouglas Gilbert static int num_bus_resets; 637cbf67842SDouglas Gilbert static int num_host_resets; 638c6a44287SMartin K. Petersen static int dix_writes; 639c6a44287SMartin K. Petersen static int dix_reads; 640c6a44287SMartin K. Petersen static int dif_errors; 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 6431da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6441da177e4SLinus Torvalds 645cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 646cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6471da177e4SLinus Torvalds 6481da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6511da177e4SLinus Torvalds .name = sdebug_proc_name, 6521da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6531da177e4SLinus Torvalds }; 6541da177e4SLinus Torvalds 6551da177e4SLinus Torvalds static const int check_condition_result = 6561da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6571da177e4SLinus Torvalds 658c6a44287SMartin K. Petersen static const int illegal_condition_result = 659c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 660c6a44287SMartin K. Petersen 661cbf67842SDouglas Gilbert static const int device_qfull_result = 662cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 663cbf67842SDouglas Gilbert 664cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 665cbf67842SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 666cbf67842SDouglas Gilbert 0, 0, 0, 0}; 667c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 668c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 669c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 670c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 671c65b1445SDouglas Gilbert 67214faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 67314faa944SAkinobu Mita { 67414faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 67514faa944SAkinobu Mita 67614faa944SAkinobu Mita return fake_storep + lba * scsi_debug_sector_size; 67714faa944SAkinobu Mita } 67814faa944SAkinobu Mita 67914faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector) 68014faa944SAkinobu Mita { 68149413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 68214faa944SAkinobu Mita 68314faa944SAkinobu Mita return dif_storep + sector; 68414faa944SAkinobu Mita } 68514faa944SAkinobu Mita 6861da177e4SLinus Torvalds static int sdebug_add_adapter(void); 6871da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 6881da177e4SLinus Torvalds 6898dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 6908dea0d02SFUJITA Tomonori { 6918dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 6928dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 6938dea0d02SFUJITA Tomonori 6948dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 6958dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 6968dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 6978dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 6988dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 6998dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 7008dea0d02SFUJITA Tomonori else 7018dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 7028dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 703f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 7048dea0d02SFUJITA Tomonori } 7058dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 7068dea0d02SFUJITA Tomonori } 7078dea0d02SFUJITA Tomonori 70822017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 70922017ed2SDouglas Gilbert 71022017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 71122017ed2SDouglas Gilbert static void 71222017ed2SDouglas Gilbert mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d, 71322017ed2SDouglas Gilbert int in_byte, int in_bit) 71422017ed2SDouglas Gilbert { 71522017ed2SDouglas Gilbert unsigned char *sbuff; 71622017ed2SDouglas Gilbert u8 sks[4]; 71722017ed2SDouglas Gilbert int sl, asc; 71822017ed2SDouglas Gilbert 71922017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 72022017ed2SDouglas Gilbert if (!sbuff) { 72122017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 72222017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 72322017ed2SDouglas Gilbert return; 72422017ed2SDouglas Gilbert } 72522017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 72622017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 72722017ed2SDouglas Gilbert scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST, 72822017ed2SDouglas Gilbert asc, 0); 72922017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 73022017ed2SDouglas Gilbert sks[0] = 0x80; 73122017ed2SDouglas Gilbert if (c_d) 73222017ed2SDouglas Gilbert sks[0] |= 0x40; 73322017ed2SDouglas Gilbert if (in_bit >= 0) { 73422017ed2SDouglas Gilbert sks[0] |= 0x8; 73522017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 73622017ed2SDouglas Gilbert } 73722017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 73822017ed2SDouglas Gilbert if (scsi_debug_dsense) { 73922017ed2SDouglas Gilbert sl = sbuff[7] + 8; 74022017ed2SDouglas Gilbert sbuff[7] = sl; 74122017ed2SDouglas Gilbert sbuff[sl] = 0x2; 74222017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 74322017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 74422017ed2SDouglas Gilbert } else 74522017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 74622017ed2SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 74722017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 74822017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 74922017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 75022017ed2SDouglas Gilbert } 75122017ed2SDouglas Gilbert 752cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7538dea0d02SFUJITA Tomonori { 7548dea0d02SFUJITA Tomonori unsigned char *sbuff; 7558dea0d02SFUJITA Tomonori 756cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 757cbf67842SDouglas Gilbert if (!sbuff) { 758cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 759cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 760cbf67842SDouglas Gilbert return; 761cbf67842SDouglas Gilbert } 762cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7638dea0d02SFUJITA Tomonori 7648dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 7658dea0d02SFUJITA Tomonori 7668dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 767cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 768cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 769cbf67842SDouglas Gilbert my_name, key, asc, asq); 7708dea0d02SFUJITA Tomonori } 7711da177e4SLinus Torvalds 77222017ed2SDouglas Gilbert static void 77322017ed2SDouglas Gilbert mk_sense_invalid_opcode(struct scsi_cmnd *scp) 77422017ed2SDouglas Gilbert { 77522017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 77622017ed2SDouglas Gilbert } 77722017ed2SDouglas Gilbert 7781da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7791da177e4SLinus Torvalds { 7801da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 781cbf67842SDouglas Gilbert if (0x1261 == cmd) 782cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 783cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 784cbf67842SDouglas Gilbert else if (0x5331 == cmd) 785cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 786cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 787cbf67842SDouglas Gilbert __func__); 788cbf67842SDouglas Gilbert else 789cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 790cbf67842SDouglas Gilbert __func__, cmd); 7911da177e4SLinus Torvalds } 7921da177e4SLinus Torvalds return -EINVAL; 7931da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 7941da177e4SLinus Torvalds } 7951da177e4SLinus Torvalds 79619c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 79719c8ead7SEwan D. Milne { 79819c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 79919c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 80019c8ead7SEwan D. Milne 80119c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 80219c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 80319c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 80419c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 80519c8ead7SEwan D. Milne (devip->target == dp->target)) 80619c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 80719c8ead7SEwan D. Milne } 80819c8ead7SEwan D. Milne } 80919c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 81019c8ead7SEwan D. Milne } 81119c8ead7SEwan D. Milne 812cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, 813c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 8141da177e4SLinus Torvalds { 815cbf67842SDouglas Gilbert int k; 816cbf67842SDouglas Gilbert bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts); 817cbf67842SDouglas Gilbert 818cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 819cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 820cbf67842SDouglas Gilbert const char *cp = NULL; 821cbf67842SDouglas Gilbert 822cbf67842SDouglas Gilbert switch (k) { 823cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 824cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 825cbf67842SDouglas Gilbert UA_RESET_ASC, POWER_ON_RESET_ASCQ); 826cbf67842SDouglas Gilbert if (debug) 827cbf67842SDouglas Gilbert cp = "power on reset"; 828cbf67842SDouglas Gilbert break; 829cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 830cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 831cbf67842SDouglas Gilbert UA_RESET_ASC, BUS_RESET_ASCQ); 832cbf67842SDouglas Gilbert if (debug) 833cbf67842SDouglas Gilbert cp = "bus reset"; 834cbf67842SDouglas Gilbert break; 835cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 836cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 837cbf67842SDouglas Gilbert UA_CHANGED_ASC, MODE_CHANGED_ASCQ); 838cbf67842SDouglas Gilbert if (debug) 839cbf67842SDouglas Gilbert cp = "mode parameters changed"; 840cbf67842SDouglas Gilbert break; 8410d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 8420d01c5dfSDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 8430d01c5dfSDouglas Gilbert UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ); 8440d01c5dfSDouglas Gilbert if (debug) 8450d01c5dfSDouglas Gilbert cp = "capacity data changed"; 846f49accf1SEwan D. Milne break; 847acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 848acafd0b9SEwan D. Milne mk_sense_buffer(SCpnt, UNIT_ATTENTION, 849acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ); 850acafd0b9SEwan D. Milne if (debug) 851acafd0b9SEwan D. Milne cp = "microcode has been changed"; 852acafd0b9SEwan D. Milne break; 853acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 854acafd0b9SEwan D. Milne mk_sense_buffer(SCpnt, UNIT_ATTENTION, 855acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 856acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 857acafd0b9SEwan D. Milne if (debug) 858acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 859acafd0b9SEwan D. Milne break; 86019c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 86119c8ead7SEwan D. Milne /* 86219c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 86319c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 86419c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 86519c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 86619c8ead7SEwan D. Milne * NOTE: scsi_debug_scsi_level does not use the same 86719c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 86819c8ead7SEwan D. Milne */ 86919c8ead7SEwan D. Milne if (scsi_debug_scsi_level >= 6) /* SPC-4 and above */ 87019c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 87119c8ead7SEwan D. Milne mk_sense_buffer(SCpnt, UNIT_ATTENTION, 87219c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 87319c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 87419c8ead7SEwan D. Milne if (debug) 87519c8ead7SEwan D. Milne cp = "reported luns data has changed"; 87619c8ead7SEwan D. Milne break; 877cbf67842SDouglas Gilbert default: 878cbf67842SDouglas Gilbert pr_warn("%s: unexpected unit attention code=%d\n", 879cbf67842SDouglas Gilbert __func__, k); 880cbf67842SDouglas Gilbert if (debug) 881cbf67842SDouglas Gilbert cp = "unknown"; 882cbf67842SDouglas Gilbert break; 883cbf67842SDouglas Gilbert } 884cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 885cbf67842SDouglas Gilbert if (debug) 886cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 887cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 888cbf67842SDouglas Gilbert my_name, cp); 8891da177e4SLinus Torvalds return check_condition_result; 8901da177e4SLinus Torvalds } 891cbf67842SDouglas Gilbert if ((UAS_TUR == uas_only) && devip->stopped) { 892cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY, 893c65b1445SDouglas Gilbert 0x2); 894cbf67842SDouglas Gilbert if (debug) 895cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 896cbf67842SDouglas Gilbert "%s reports: Not ready: %s\n", my_name, 897cbf67842SDouglas Gilbert "initializing command required"); 898c65b1445SDouglas Gilbert return check_condition_result; 899c65b1445SDouglas Gilbert } 9001da177e4SLinus Torvalds return 0; 9011da177e4SLinus Torvalds } 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 9041da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 9051da177e4SLinus Torvalds int arr_len) 9061da177e4SLinus Torvalds { 90721a61829SFUJITA Tomonori int act_len; 908072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 9091da177e4SLinus Torvalds 910072d0bb3SFUJITA Tomonori if (!sdb->length) 9111da177e4SLinus Torvalds return 0; 912072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 9131da177e4SLinus Torvalds return (DID_ERROR << 16); 91421a61829SFUJITA Tomonori 91521a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 91621a61829SFUJITA Tomonori arr, arr_len); 91721a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 91821a61829SFUJITA Tomonori 9191da177e4SLinus Torvalds return 0; 9201da177e4SLinus Torvalds } 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 9231da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 92421a61829SFUJITA Tomonori int arr_len) 9251da177e4SLinus Torvalds { 92621a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 9271da177e4SLinus Torvalds return 0; 928072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 9291da177e4SLinus Torvalds return -1; 93021a61829SFUJITA Tomonori 93121a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 9321da177e4SLinus Torvalds } 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds 9351da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 9361da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 937cbf67842SDouglas Gilbert static const char *inq_product_rev = "0184"; /* version less '.' */ 9381da177e4SLinus Torvalds 939cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 9405a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 9415a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 9425a09e398SHannes Reinecke const char * dev_id_str, 943c65b1445SDouglas Gilbert int dev_id_str_len) 9441da177e4SLinus Torvalds { 945c65b1445SDouglas Gilbert int num, port_a; 946c65b1445SDouglas Gilbert char b[32]; 9471da177e4SLinus Torvalds 948c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 9491da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 9501da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 9511da177e4SLinus Torvalds arr[1] = 0x1; 9521da177e4SLinus Torvalds arr[2] = 0x0; 9531da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 9541da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 9551da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 9561da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9571da177e4SLinus Torvalds arr[3] = num; 9581da177e4SLinus Torvalds num += 4; 959c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 960c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 961c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 962c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 963c65b1445SDouglas Gilbert arr[num++] = 0x0; 964c65b1445SDouglas Gilbert arr[num++] = 0x8; 965c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 966c65b1445SDouglas Gilbert arr[num++] = 0x33; 967c65b1445SDouglas Gilbert arr[num++] = 0x33; 968c65b1445SDouglas Gilbert arr[num++] = 0x30; 969c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 970c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 971c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 972c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 973c65b1445SDouglas Gilbert /* Target relative port number */ 974c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 975c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 976c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 977c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 978c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 979c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 980c65b1445SDouglas Gilbert arr[num++] = 0x0; 981c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 982c65b1445SDouglas Gilbert } 983c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 984c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 985c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 986c65b1445SDouglas Gilbert arr[num++] = 0x0; 987c65b1445SDouglas Gilbert arr[num++] = 0x8; 988c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 989c65b1445SDouglas Gilbert arr[num++] = 0x22; 990c65b1445SDouglas Gilbert arr[num++] = 0x22; 991c65b1445SDouglas Gilbert arr[num++] = 0x20; 992c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 993c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 994c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 995c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 9965a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 9975a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 9985a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 9995a09e398SHannes Reinecke arr[num++] = 0x0; 10005a09e398SHannes Reinecke arr[num++] = 0x4; 10015a09e398SHannes Reinecke arr[num++] = 0; 10025a09e398SHannes Reinecke arr[num++] = 0; 10035a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 10045a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 1005c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 1006c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1007c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1008c65b1445SDouglas Gilbert arr[num++] = 0x0; 1009c65b1445SDouglas Gilbert arr[num++] = 0x8; 1010c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 1011c65b1445SDouglas Gilbert arr[num++] = 0x22; 1012c65b1445SDouglas Gilbert arr[num++] = 0x22; 1013c65b1445SDouglas Gilbert arr[num++] = 0x20; 1014c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 1015c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 1016c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 1017c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 1018c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1019c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1020c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1021c65b1445SDouglas Gilbert arr[num++] = 0x0; 1022c65b1445SDouglas Gilbert arr[num++] = 24; 1023c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 1024c65b1445SDouglas Gilbert num += 12; 1025c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1026c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1027c65b1445SDouglas Gilbert num += 8; 1028c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1029c65b1445SDouglas Gilbert num += 4; 1030c65b1445SDouglas Gilbert return num; 1031c65b1445SDouglas Gilbert } 1032c65b1445SDouglas Gilbert 1033c65b1445SDouglas Gilbert 1034c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1035c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1036c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1037c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1038c65b1445SDouglas Gilbert }; 1039c65b1445SDouglas Gilbert 1040cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1041c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 1042c65b1445SDouglas Gilbert { 1043c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1044c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1045c65b1445SDouglas Gilbert } 1046c65b1445SDouglas Gilbert 1047cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1048c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 1049c65b1445SDouglas Gilbert { 1050c65b1445SDouglas Gilbert int num = 0; 1051c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1052c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1053c65b1445SDouglas Gilbert int plen, olen; 1054c65b1445SDouglas Gilbert 1055c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1056c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1057c65b1445SDouglas Gilbert arr[num++] = 0x0; 1058c65b1445SDouglas Gilbert olen = strlen(na1); 1059c65b1445SDouglas Gilbert plen = olen + 1; 1060c65b1445SDouglas Gilbert if (plen % 4) 1061c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1062c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1063c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1064c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1065c65b1445SDouglas Gilbert num += plen; 1066c65b1445SDouglas Gilbert 1067c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1068c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1069c65b1445SDouglas Gilbert arr[num++] = 0x0; 1070c65b1445SDouglas Gilbert olen = strlen(na2); 1071c65b1445SDouglas Gilbert plen = olen + 1; 1072c65b1445SDouglas Gilbert if (plen % 4) 1073c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1074c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1075c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1076c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1077c65b1445SDouglas Gilbert num += plen; 1078c65b1445SDouglas Gilbert 1079c65b1445SDouglas Gilbert return num; 1080c65b1445SDouglas Gilbert } 1081c65b1445SDouglas Gilbert 1082c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1083c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 1084c65b1445SDouglas Gilbert { 1085c65b1445SDouglas Gilbert int num = 0; 1086c65b1445SDouglas Gilbert int port_a, port_b; 1087c65b1445SDouglas Gilbert 1088c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1089c65b1445SDouglas Gilbert port_b = port_a + 1; 1090c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1091c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1092c65b1445SDouglas Gilbert arr[num++] = 0x0; 1093c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1094c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1095c65b1445SDouglas Gilbert num += 6; 1096c65b1445SDouglas Gilbert arr[num++] = 0x0; 1097c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1098c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1099c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1100c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1101c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1102c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1103c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 1104c65b1445SDouglas Gilbert arr[num++] = 0x22; 1105c65b1445SDouglas Gilbert arr[num++] = 0x22; 1106c65b1445SDouglas Gilbert arr[num++] = 0x20; 1107c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 1108c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 1109c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 1110c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 1111c65b1445SDouglas Gilbert 1112c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1113c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1114c65b1445SDouglas Gilbert arr[num++] = 0x0; 1115c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1116c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1117c65b1445SDouglas Gilbert num += 6; 1118c65b1445SDouglas Gilbert arr[num++] = 0x0; 1119c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1120c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1121c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1122c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1123c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1124c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1125c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 1126c65b1445SDouglas Gilbert arr[num++] = 0x22; 1127c65b1445SDouglas Gilbert arr[num++] = 0x22; 1128c65b1445SDouglas Gilbert arr[num++] = 0x20; 1129c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 1130c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 1131c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 1132c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 1133c65b1445SDouglas Gilbert 1134c65b1445SDouglas Gilbert return num; 1135c65b1445SDouglas Gilbert } 1136c65b1445SDouglas Gilbert 1137c65b1445SDouglas Gilbert 1138c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1139c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1140c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1141c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1142c65b1445SDouglas Gilbert '1','2','3','4', 1143c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1144c65b1445SDouglas Gilbert 0xec,0,0,0, 1145c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1146c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1147c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1148c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1149c65b1445SDouglas Gilbert 0x53,0x41, 1150c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1151c65b1445SDouglas Gilbert 0x20,0x20, 1152c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1153c65b1445SDouglas Gilbert 0x10,0x80, 1154c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1155c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1156c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1157c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1158c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1159c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1160c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1161c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1162c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1163c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1164c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1165c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1166c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1167c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1168c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1169c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1170c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1171c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1172c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1173c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1174c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1175c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1176c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1177c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1178c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1179c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1180c65b1445SDouglas Gilbert }; 1181c65b1445SDouglas Gilbert 1182cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1183c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 1184c65b1445SDouglas Gilbert { 1185c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1186c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1187c65b1445SDouglas Gilbert } 1188c65b1445SDouglas Gilbert 1189c65b1445SDouglas Gilbert 1190c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11911e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 11921e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11931e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11941e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1195c65b1445SDouglas Gilbert }; 1196c65b1445SDouglas Gilbert 1197cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1198c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 1199c65b1445SDouglas Gilbert { 1200ea61fca5SMartin K. Petersen unsigned int gran; 1201ea61fca5SMartin K. Petersen 1202c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1203e308b3d1SMartin K. Petersen 1204e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 1205ea61fca5SMartin K. Petersen gran = 1 << scsi_debug_physblk_exp; 1206ea61fca5SMartin K. Petersen arr[2] = (gran >> 8) & 0xff; 1207ea61fca5SMartin K. Petersen arr[3] = gran & 0xff; 1208e308b3d1SMartin K. Petersen 1209e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1210c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 1211c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 1212c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 1213c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 1214c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 1215c65b1445SDouglas Gilbert } 121644d92694SMartin K. Petersen 1217e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1218e308b3d1SMartin K. Petersen put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); 1219e308b3d1SMartin K. Petersen 12205b94e232SMartin K. Petersen if (scsi_debug_lbpu) { 1221e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 12226014759cSMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); 1223e308b3d1SMartin K. Petersen 1224e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 122544d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); 122644d92694SMartin K. Petersen } 122744d92694SMartin K. Petersen 1228e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 122944d92694SMartin K. Petersen if (scsi_debug_unmap_alignment) { 123044d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); 123144d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 123244d92694SMartin K. Petersen } 123344d92694SMartin K. Petersen 1234e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 123544d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); 12366014759cSMartin K. Petersen 12375b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 12385b94e232SMartin K. Petersen put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); 12395b94e232SMartin K. Petersen 12405b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 124144d92694SMartin K. Petersen 1242c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds 12451e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1246eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 1247eac6e8e4SMatthew Wilcox { 1248eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1249eac6e8e4SMatthew Wilcox arr[0] = 0; 12501e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 12511e49f785SDouglas Gilbert arr[2] = 0; 12521e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1253eac6e8e4SMatthew Wilcox 1254eac6e8e4SMatthew Wilcox return 0x3c; 1255eac6e8e4SMatthew Wilcox } 12561da177e4SLinus Torvalds 1257be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */ 12586014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 12596014759cSMartin K. Petersen { 12603f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 12616014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 12626014759cSMartin K. Petersen 12635b94e232SMartin K. Petersen if (scsi_debug_lbpu) 12646014759cSMartin K. Petersen arr[1] = 1 << 7; 12656014759cSMartin K. Petersen 12665b94e232SMartin K. Petersen if (scsi_debug_lbpws) 12676014759cSMartin K. Petersen arr[1] |= 1 << 6; 12686014759cSMartin K. Petersen 12695b94e232SMartin K. Petersen if (scsi_debug_lbpws10) 12705b94e232SMartin K. Petersen arr[1] |= 1 << 5; 12715b94e232SMartin K. Petersen 1272be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1273be1dd78dSEric Sandeen arr[1] |= 1 << 2; 1274be1dd78dSEric Sandeen 12753f0bc3b3SMartin K. Petersen return 0x4; 12766014759cSMartin K. Petersen } 12776014759cSMartin K. Petersen 12781da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1279c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12801da177e4SLinus Torvalds 1281c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12821da177e4SLinus Torvalds { 12831da177e4SLinus Torvalds unsigned char pq_pdt; 12845a09e398SHannes Reinecke unsigned char * arr; 128501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12865a09e398SHannes Reinecke int alloc_len, n, ret; 1287c2248fc9SDouglas Gilbert bool have_wlun; 12881da177e4SLinus Torvalds 12891da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 12906f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12916f3cbf55SDouglas Gilbert if (! arr) 12926f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 129334d55434STomas Winkler have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS); 1294c2248fc9SDouglas Gilbert if (have_wlun) 1295c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 1296c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 1297c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 1298c65b1445SDouglas Gilbert else 12991da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 13001da177e4SLinus Torvalds arr[0] = pq_pdt; 13011da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 130222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 13035a09e398SHannes Reinecke kfree(arr); 13041da177e4SLinus Torvalds return check_condition_result; 13051da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 13065a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1307c65b1445SDouglas Gilbert char lu_id_str[6]; 1308c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 13091da177e4SLinus Torvalds 13105a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 13115a09e398SHannes Reinecke (devip->channel & 0x7f); 131223183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 131323183910SDouglas Gilbert host_no = 0; 1314c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1315c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1316c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1317c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1318c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 13191da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1320c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1321c65b1445SDouglas Gilbert n = 4; 1322c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1323c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1324c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1325c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1326c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1327c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1328c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1329c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1330c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1331c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 1332eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 13335b94e232SMartin K. Petersen if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ 13345b94e232SMartin K. Petersen arr[n++] = 0xb2; 1335c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 13361da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1337c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 13381da177e4SLinus Torvalds arr[3] = len; 1339c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 13401da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1341c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 13425a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 13435a09e398SHannes Reinecke target_dev_id, lu_id_num, 13445a09e398SHannes Reinecke lu_id_str, len); 1345c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1346c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1347c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 1348c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1349c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1350c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 1351c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1352c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1353c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1354c6a44287SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) 1355c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1356c6a44287SMartin K. Petersen else if (scsi_debug_dif) 1357c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1358c6a44287SMartin K. Petersen else 1359c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1360c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1361c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1362c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1363c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1364c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1365c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1366c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1367c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1368c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1369c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1370c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 1371c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 1372c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1373c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 1374c65b1445SDouglas Gilbert arr[2] = (n >> 8); 1375c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 1376c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 1377c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1378c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 1379eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 1380eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1381eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 13825b94e232SMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ 13836014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 13846014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 13851da177e4SLinus Torvalds } else { 138622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13875a09e398SHannes Reinecke kfree(arr); 13881da177e4SLinus Torvalds return check_condition_result; 13891da177e4SLinus Torvalds } 1390c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 13915a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1392c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13935a09e398SHannes Reinecke kfree(arr); 13945a09e398SHannes Reinecke return ret; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1397d986788bSMartin Pitt arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */ 13981da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 13991da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 14001da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1401c6a44287SMartin K. Petersen arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ 14025a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 14035a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1404c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 14051da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1406c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 14071da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 14081da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 14091da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 14101da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1411e46b0344SDouglas Gilbert arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */ 1412e46b0344SDouglas Gilbert arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */ 1413c65b1445SDouglas Gilbert n = 62; 14141da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 1415e46b0344SDouglas Gilbert arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */ 14161da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 1417e46b0344SDouglas Gilbert arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */ 14181da177e4SLinus Torvalds } 1419e46b0344SDouglas Gilbert arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */ 14205a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 14211da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 14225a09e398SHannes Reinecke kfree(arr); 14235a09e398SHannes Reinecke return ret; 14241da177e4SLinus Torvalds } 14251da177e4SLinus Torvalds 14261da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 14271da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14281da177e4SLinus Torvalds { 14291da177e4SLinus Torvalds unsigned char * sbuff; 143001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1431cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 14322492fc09STomas Winkler bool dsense; 14331da177e4SLinus Torvalds int len = 18; 14341da177e4SLinus Torvalds 1435c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1436c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1437cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1438c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1439c2248fc9SDouglas Gilbert if (dsense) { 1440c65b1445SDouglas Gilbert arr[0] = 0x72; 1441c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1442c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1443c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1444c2248fc9SDouglas Gilbert len = 8; 1445c65b1445SDouglas Gilbert } else { 1446c65b1445SDouglas Gilbert arr[0] = 0x70; 1447c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1448c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1449c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1450c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1451c65b1445SDouglas Gilbert } 1452c65b1445SDouglas Gilbert } else { 1453cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1454c2248fc9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == scsi_debug_dsense) 1455c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1456c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1457c2248fc9SDouglas Gilbert if (dsense) { 1458c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1459c2248fc9SDouglas Gilbert arr[0] = 0x72; 1460c2248fc9SDouglas Gilbert len = 8; 1461c2248fc9SDouglas Gilbert } else { 1462c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1463c2248fc9SDouglas Gilbert arr[0] = 0x70; 1464c2248fc9SDouglas Gilbert arr[7] = 0xa; 1465c2248fc9SDouglas Gilbert } 1466c2248fc9SDouglas Gilbert } else if (dsense) { 1467c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14681da177e4SLinus Torvalds arr[0] = 0x72; 14691da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14701da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14711da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14721da177e4SLinus Torvalds len = 8; 1473c2248fc9SDouglas Gilbert } else { 1474c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1475c2248fc9SDouglas Gilbert arr[0] = 0x70; 1476c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1477c2248fc9SDouglas Gilbert arr[7] = 0xa; 1478c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1479c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1480c65b1445SDouglas Gilbert } 1481c2248fc9SDouglas Gilbert 1482c65b1445SDouglas Gilbert } 1483cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14841da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14851da177e4SLinus Torvalds } 14861da177e4SLinus Torvalds 1487c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1488c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1489c65b1445SDouglas Gilbert { 149001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1491c2248fc9SDouglas Gilbert int power_cond, start; 1492c65b1445SDouglas Gilbert 1493c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1494c65b1445SDouglas Gilbert if (power_cond) { 149522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1496c65b1445SDouglas Gilbert return check_condition_result; 1497c65b1445SDouglas Gilbert } 1498c65b1445SDouglas Gilbert start = cmd[4] & 1; 1499c65b1445SDouglas Gilbert if (start == devip->stopped) 1500c65b1445SDouglas Gilbert devip->stopped = !start; 1501c65b1445SDouglas Gilbert return 0; 1502c65b1445SDouglas Gilbert } 1503c65b1445SDouglas Gilbert 150428898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 150528898873SFUJITA Tomonori { 150628898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 15075447ed6cSDouglas Gilbert return (sector_t)scsi_debug_virtual_gb * 15085447ed6cSDouglas Gilbert (1073741824 / scsi_debug_sector_size); 150928898873SFUJITA Tomonori else 151028898873SFUJITA Tomonori return sdebug_store_sectors; 151128898873SFUJITA Tomonori } 151228898873SFUJITA Tomonori 15131da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 15141da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 15151da177e4SLinus Torvalds struct sdebug_dev_info * devip) 15161da177e4SLinus Torvalds { 15171da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1518c65b1445SDouglas Gilbert unsigned int capac; 15191da177e4SLinus Torvalds 1520c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 152128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 15221da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1523c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1524c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 15251da177e4SLinus Torvalds arr[0] = (capac >> 24); 15261da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 15271da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 15281da177e4SLinus Torvalds arr[3] = capac & 0xff; 1529c65b1445SDouglas Gilbert } else { 1530c65b1445SDouglas Gilbert arr[0] = 0xff; 1531c65b1445SDouglas Gilbert arr[1] = 0xff; 1532c65b1445SDouglas Gilbert arr[2] = 0xff; 1533c65b1445SDouglas Gilbert arr[3] = 0xff; 1534c65b1445SDouglas Gilbert } 1535597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 1536597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 15371da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 15381da177e4SLinus Torvalds } 15391da177e4SLinus Torvalds 1540c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1541c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1542c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1543c65b1445SDouglas Gilbert { 154401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1545c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1546c65b1445SDouglas Gilbert unsigned long long capac; 1547c2248fc9SDouglas Gilbert int k, alloc_len; 1548c65b1445SDouglas Gilbert 1549c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1550c65b1445SDouglas Gilbert + cmd[13]); 1551c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 155228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1553c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1554c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1555c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1556c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1557597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 1558597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 1559597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 1560597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 1561ea61fca5SMartin K. Petersen arr[13] = scsi_debug_physblk_exp & 0xf; 1562ea61fca5SMartin K. Petersen arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; 156344d92694SMartin K. Petersen 1564be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 15655b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1566be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1567be1dd78dSEric Sandeen arr[14] |= 0x40; /* LBPRZ */ 1568be1dd78dSEric Sandeen } 156944d92694SMartin K. Petersen 1570ea61fca5SMartin K. Petersen arr[15] = scsi_debug_lowest_aligned & 0xff; 1571c6a44287SMartin K. Petersen 1572c6a44287SMartin K. Petersen if (scsi_debug_dif) { 1573c6a44287SMartin K. Petersen arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ 1574c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1575c6a44287SMartin K. Petersen } 1576c6a44287SMartin K. Petersen 1577c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1578c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1579c65b1445SDouglas Gilbert } 1580c65b1445SDouglas Gilbert 15815a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15825a09e398SHannes Reinecke 15835a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15845a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15855a09e398SHannes Reinecke { 158601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15875a09e398SHannes Reinecke unsigned char * arr; 15885a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15895a09e398SHannes Reinecke int n, ret, alen, rlen; 15905a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15915a09e398SHannes Reinecke 15925a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 15935a09e398SHannes Reinecke + cmd[9]); 15945a09e398SHannes Reinecke 15956f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15966f3cbf55SDouglas Gilbert if (! arr) 15976f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15985a09e398SHannes Reinecke /* 15995a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 16005a09e398SHannes Reinecke * real and a fake port with no device connected. 16015a09e398SHannes Reinecke * So we create two port groups with one port each 16025a09e398SHannes Reinecke * and set the group with port B to unavailable. 16035a09e398SHannes Reinecke */ 16045a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 16055a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 16065a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 16075a09e398SHannes Reinecke (devip->channel & 0x7f); 16085a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 16095a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 16105a09e398SHannes Reinecke 16115a09e398SHannes Reinecke /* 16125a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 16135a09e398SHannes Reinecke */ 16145a09e398SHannes Reinecke n = 4; 16155a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 16165a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 16175a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 16185a09e398SHannes Reinecke } else { 16195a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 16205a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 16215a09e398SHannes Reinecke } 16225a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 16235a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 16245a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16255a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16265a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16275a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16285a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16295a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16305a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 16315a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 16325a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 16335a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 16345a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 16355a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 16365a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16375a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16385a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16395a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16405a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16415a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16425a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 16435a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 16445a09e398SHannes Reinecke 16455a09e398SHannes Reinecke rlen = n - 4; 16465a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 16475a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 16485a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 16495a09e398SHannes Reinecke arr[3] = rlen & 0xff; 16505a09e398SHannes Reinecke 16515a09e398SHannes Reinecke /* 16525a09e398SHannes Reinecke * Return the smallest value of either 16535a09e398SHannes Reinecke * - The allocated length 16545a09e398SHannes Reinecke * - The constructed command length 16555a09e398SHannes Reinecke * - The maximum array size 16565a09e398SHannes Reinecke */ 16575a09e398SHannes Reinecke rlen = min(alen,n); 16585a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 16595a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 16605a09e398SHannes Reinecke kfree(arr); 16615a09e398SHannes Reinecke return ret; 16625a09e398SHannes Reinecke } 16635a09e398SHannes Reinecke 166438d5c833SDouglas Gilbert static int 166538d5c833SDouglas Gilbert resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 166638d5c833SDouglas Gilbert { 166738d5c833SDouglas Gilbert bool rctd; 166838d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 166938d5c833SDouglas Gilbert u16 req_sa, u; 167038d5c833SDouglas Gilbert u32 alloc_len, a_len; 167138d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 167238d5c833SDouglas Gilbert const struct opcode_info_t *oip; 167338d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 167438d5c833SDouglas Gilbert u8 *arr; 167538d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 167638d5c833SDouglas Gilbert 167738d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 167838d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 167938d5c833SDouglas Gilbert req_opcode = cmd[3]; 168038d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 168138d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16826d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 168338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 168438d5c833SDouglas Gilbert return check_condition_result; 168538d5c833SDouglas Gilbert } 168638d5c833SDouglas Gilbert if (alloc_len > 8192) 168738d5c833SDouglas Gilbert a_len = 8192; 168838d5c833SDouglas Gilbert else 168938d5c833SDouglas Gilbert a_len = alloc_len; 169099531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 169138d5c833SDouglas Gilbert if (NULL == arr) { 169238d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 169338d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 169438d5c833SDouglas Gilbert return check_condition_result; 169538d5c833SDouglas Gilbert } 169638d5c833SDouglas Gilbert switch (reporting_opts) { 169738d5c833SDouglas Gilbert case 0: /* all commands */ 169838d5c833SDouglas Gilbert /* count number of commands */ 169938d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 170038d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 170138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 170238d5c833SDouglas Gilbert continue; 170338d5c833SDouglas Gilbert count += (oip->num_attached + 1); 170438d5c833SDouglas Gilbert } 170538d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 170638d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 170738d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 170838d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 170938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 171038d5c833SDouglas Gilbert continue; 171138d5c833SDouglas Gilbert na = oip->num_attached; 171238d5c833SDouglas Gilbert arr[offset] = oip->opcode; 171338d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 171438d5c833SDouglas Gilbert if (rctd) 171538d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 171638d5c833SDouglas Gilbert if (FF_SA & oip->flags) 171738d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 171838d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 171938d5c833SDouglas Gilbert if (rctd) 172038d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 172138d5c833SDouglas Gilbert r_oip = oip; 172238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 172338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 172438d5c833SDouglas Gilbert continue; 172538d5c833SDouglas Gilbert offset += bump; 172638d5c833SDouglas Gilbert arr[offset] = oip->opcode; 172738d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 172838d5c833SDouglas Gilbert if (rctd) 172938d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 173038d5c833SDouglas Gilbert if (FF_SA & oip->flags) 173138d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 173238d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 173338d5c833SDouglas Gilbert arr + offset + 6); 173438d5c833SDouglas Gilbert if (rctd) 173538d5c833SDouglas Gilbert put_unaligned_be16(0xa, 173638d5c833SDouglas Gilbert arr + offset + 8); 173738d5c833SDouglas Gilbert } 173838d5c833SDouglas Gilbert oip = r_oip; 173938d5c833SDouglas Gilbert offset += bump; 174038d5c833SDouglas Gilbert } 174138d5c833SDouglas Gilbert break; 174238d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 174338d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 174438d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 174538d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 174638d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 174738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 174838d5c833SDouglas Gilbert supp = 1; 174938d5c833SDouglas Gilbert offset = 4; 175038d5c833SDouglas Gilbert } else { 175138d5c833SDouglas Gilbert if (1 == reporting_opts) { 175238d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 175338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 175438d5c833SDouglas Gilbert 2, 2); 175538d5c833SDouglas Gilbert kfree(arr); 175638d5c833SDouglas Gilbert return check_condition_result; 175738d5c833SDouglas Gilbert } 175838d5c833SDouglas Gilbert req_sa = 0; 175938d5c833SDouglas Gilbert } else if (2 == reporting_opts && 176038d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 176138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 176238d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 176338d5c833SDouglas Gilbert return check_condition_result; 176438d5c833SDouglas Gilbert } 176538d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 176638d5c833SDouglas Gilbert req_opcode == oip->opcode) 176738d5c833SDouglas Gilbert supp = 3; 176838d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 176938d5c833SDouglas Gilbert na = oip->num_attached; 177038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 177138d5c833SDouglas Gilbert ++k, ++oip) { 177238d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 177338d5c833SDouglas Gilbert break; 177438d5c833SDouglas Gilbert } 177538d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 177638d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 177738d5c833SDouglas Gilbert na = oip->num_attached; 177838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 177938d5c833SDouglas Gilbert ++k, ++oip) { 178038d5c833SDouglas Gilbert if (req_sa == oip->sa) 178138d5c833SDouglas Gilbert break; 178238d5c833SDouglas Gilbert } 178338d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 178438d5c833SDouglas Gilbert } else 178538d5c833SDouglas Gilbert supp = 3; 178638d5c833SDouglas Gilbert if (3 == supp) { 178738d5c833SDouglas Gilbert u = oip->len_mask[0]; 178838d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 178938d5c833SDouglas Gilbert arr[4] = oip->opcode; 179038d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 179138d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 179238d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 179338d5c833SDouglas Gilbert offset = 4 + u; 179438d5c833SDouglas Gilbert } else 179538d5c833SDouglas Gilbert offset = 4; 179638d5c833SDouglas Gilbert } 179738d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 179838d5c833SDouglas Gilbert if (rctd) { 179938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 180038d5c833SDouglas Gilbert offset += 12; 180138d5c833SDouglas Gilbert } 180238d5c833SDouglas Gilbert break; 180338d5c833SDouglas Gilbert default: 180438d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 180538d5c833SDouglas Gilbert kfree(arr); 180638d5c833SDouglas Gilbert return check_condition_result; 180738d5c833SDouglas Gilbert } 180838d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 180938d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 181038d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 181138d5c833SDouglas Gilbert kfree(arr); 181238d5c833SDouglas Gilbert return errsts; 181338d5c833SDouglas Gilbert } 181438d5c833SDouglas Gilbert 181538d5c833SDouglas Gilbert static int 181638d5c833SDouglas Gilbert resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 181738d5c833SDouglas Gilbert { 181838d5c833SDouglas Gilbert bool repd; 181938d5c833SDouglas Gilbert u32 alloc_len, len; 182038d5c833SDouglas Gilbert u8 arr[16]; 182138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 182238d5c833SDouglas Gilbert 182338d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 182438d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 182538d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 182638d5c833SDouglas Gilbert if (alloc_len < 4) { 182738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 182838d5c833SDouglas Gilbert return check_condition_result; 182938d5c833SDouglas Gilbert } 183038d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 183138d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 183238d5c833SDouglas Gilbert if (repd) { 183338d5c833SDouglas Gilbert arr[3] = 0xc; 183438d5c833SDouglas Gilbert len = 16; 183538d5c833SDouglas Gilbert } else 183638d5c833SDouglas Gilbert len = 4; 183738d5c833SDouglas Gilbert 183838d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 183938d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 184038d5c833SDouglas Gilbert } 184138d5c833SDouglas Gilbert 18421da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 18431da177e4SLinus Torvalds 18441da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 18451da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 18461da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 18471da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 18501da177e4SLinus Torvalds if (1 == pcontrol) 18511da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 18521da177e4SLinus Torvalds return sizeof(err_recov_pg); 18531da177e4SLinus Torvalds } 18541da177e4SLinus Torvalds 18551da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 18561da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 18571da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 18581da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 18611da177e4SLinus Torvalds if (1 == pcontrol) 18621da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 18631da177e4SLinus Torvalds return sizeof(disconnect_pg); 18641da177e4SLinus Torvalds } 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 18671da177e4SLinus Torvalds { /* Format device page for mode_sense */ 18681da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 18691da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 18701da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 18711da177e4SLinus Torvalds 18721da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 18731da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 18741da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1875597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1876597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 1877d986788bSMartin Pitt if (scsi_debug_removable) 18781da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 18791da177e4SLinus Torvalds if (1 == pcontrol) 18801da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 18811da177e4SLinus Torvalds return sizeof(format_pg); 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds 18841da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18851da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1886cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1887cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1888cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18891da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18901da177e4SLinus Torvalds 1891cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts) 1892cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18931da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18941da177e4SLinus Torvalds if (1 == pcontrol) 1895cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1896cbf67842SDouglas Gilbert else if (2 == pcontrol) 1897cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18981da177e4SLinus Torvalds return sizeof(caching_pg); 18991da177e4SLinus Torvalds } 19001da177e4SLinus Torvalds 19011da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 19021da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1903c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1904c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1905c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 19061da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 19071da177e4SLinus Torvalds 19081da177e4SLinus Torvalds if (scsi_debug_dsense) 19091da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1910c65b1445SDouglas Gilbert else 1911c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1912c6a44287SMartin K. Petersen 1913c6a44287SMartin K. Petersen if (scsi_debug_ato) 1914c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1915c6a44287SMartin K. Petersen 19161da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 19171da177e4SLinus Torvalds if (1 == pcontrol) 1918c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1919c65b1445SDouglas Gilbert else if (2 == pcontrol) 1920c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 19211da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 19221da177e4SLinus Torvalds } 19231da177e4SLinus Torvalds 1924c65b1445SDouglas Gilbert 19251da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 19261da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1927c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 19281da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1929c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1930c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1931c65b1445SDouglas Gilbert 19321da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 19331da177e4SLinus Torvalds if (1 == pcontrol) 1934c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1935c65b1445SDouglas Gilbert else if (2 == pcontrol) 1936c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 19371da177e4SLinus Torvalds return sizeof(iec_m_pg); 19381da177e4SLinus Torvalds } 19391da177e4SLinus Torvalds 1940c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1941c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1942c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1943c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1944c65b1445SDouglas Gilbert 1945c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1946c65b1445SDouglas Gilbert if (1 == pcontrol) 1947c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1948c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1949c65b1445SDouglas Gilbert } 1950c65b1445SDouglas Gilbert 1951c65b1445SDouglas Gilbert 1952c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1953c65b1445SDouglas Gilbert int target_dev_id) 1954c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1955c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1956c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1957c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1958c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1959c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1960c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1961c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1962c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1963c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1964c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1965c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1966c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1967c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1968c65b1445SDouglas Gilbert }; 1969c65b1445SDouglas Gilbert int port_a, port_b; 1970c65b1445SDouglas Gilbert 1971c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1972c65b1445SDouglas Gilbert port_b = port_a + 1; 1973c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1974c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1975c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1976c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1977c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1978c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1979c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1980c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1981c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1982c65b1445SDouglas Gilbert if (1 == pcontrol) 1983c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1984c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1985c65b1445SDouglas Gilbert } 1986c65b1445SDouglas Gilbert 1987c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1988c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1989c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1990c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1991c65b1445SDouglas Gilbert }; 1992c65b1445SDouglas Gilbert 1993c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1994c65b1445SDouglas Gilbert if (1 == pcontrol) 1995c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1996c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1997c65b1445SDouglas Gilbert } 1998c65b1445SDouglas Gilbert 19991da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 20001da177e4SLinus Torvalds 2001c2248fc9SDouglas Gilbert static int 2002c2248fc9SDouglas Gilbert resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 20031da177e4SLinus Torvalds { 200423183910SDouglas Gilbert unsigned char dbd, llbaa; 200523183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 20061da177e4SLinus Torvalds unsigned char dev_spec; 2007c2248fc9SDouglas Gilbert int k, alloc_len, msense_6, offset, len, target_dev_id; 2008c2248fc9SDouglas Gilbert int target = scp->device->id; 20091da177e4SLinus Torvalds unsigned char * ap; 20101da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 201101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 20121da177e4SLinus Torvalds 201323183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 20141da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 20151da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 20161da177e4SLinus Torvalds subpcode = cmd[3]; 20171da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 201823183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 201923183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 202023183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 202123183910SDouglas Gilbert else 202223183910SDouglas Gilbert bd_len = 0; 20231da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 20241da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 20251da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2026cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 20271da177e4SLinus Torvalds return check_condition_result; 20281da177e4SLinus Torvalds } 2029c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2030c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 203123183910SDouglas Gilbert /* set DPOFUA bit for disks */ 203223183910SDouglas Gilbert if (0 == scsi_debug_ptype) 203323183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 203423183910SDouglas Gilbert else 203523183910SDouglas Gilbert dev_spec = 0x0; 20361da177e4SLinus Torvalds if (msense_6) { 20371da177e4SLinus Torvalds arr[2] = dev_spec; 203823183910SDouglas Gilbert arr[3] = bd_len; 20391da177e4SLinus Torvalds offset = 4; 20401da177e4SLinus Torvalds } else { 20411da177e4SLinus Torvalds arr[3] = dev_spec; 204223183910SDouglas Gilbert if (16 == bd_len) 204323183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 204423183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 20451da177e4SLinus Torvalds offset = 8; 20461da177e4SLinus Torvalds } 20471da177e4SLinus Torvalds ap = arr + offset; 204828898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 204928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 205028898873SFUJITA Tomonori 205123183910SDouglas Gilbert if (8 == bd_len) { 205223183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 205323183910SDouglas Gilbert ap[0] = 0xff; 205423183910SDouglas Gilbert ap[1] = 0xff; 205523183910SDouglas Gilbert ap[2] = 0xff; 205623183910SDouglas Gilbert ap[3] = 0xff; 205723183910SDouglas Gilbert } else { 205823183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 205923183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 206023183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 206123183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 206223183910SDouglas Gilbert } 2063597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 2064597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 206523183910SDouglas Gilbert offset += bd_len; 206623183910SDouglas Gilbert ap = arr + offset; 206723183910SDouglas Gilbert } else if (16 == bd_len) { 206823183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 206923183910SDouglas Gilbert 207023183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 207123183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 2072597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 2073597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 2074597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 2075597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 207623183910SDouglas Gilbert offset += bd_len; 207723183910SDouglas Gilbert ap = arr + offset; 207823183910SDouglas Gilbert } 20791da177e4SLinus Torvalds 2080c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2081c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 208222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 20831da177e4SLinus Torvalds return check_condition_result; 20841da177e4SLinus Torvalds } 20851da177e4SLinus Torvalds switch (pcode) { 20861da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 20871da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20881da177e4SLinus Torvalds offset += len; 20891da177e4SLinus Torvalds break; 20901da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 20911da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20921da177e4SLinus Torvalds offset += len; 20931da177e4SLinus Torvalds break; 20941da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 20951da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20961da177e4SLinus Torvalds offset += len; 20971da177e4SLinus Torvalds break; 20981da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 20991da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 21001da177e4SLinus Torvalds offset += len; 21011da177e4SLinus Torvalds break; 21021da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 21031da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 21041da177e4SLinus Torvalds offset += len; 21051da177e4SLinus Torvalds break; 2106c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2107c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 210822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2109c65b1445SDouglas Gilbert return check_condition_result; 2110c65b1445SDouglas Gilbert } 2111c65b1445SDouglas Gilbert len = 0; 2112c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2113c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2114c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2115c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2116c65b1445SDouglas Gilbert target_dev_id); 2117c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2118c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2119c65b1445SDouglas Gilbert offset += len; 2120c65b1445SDouglas Gilbert break; 21211da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 21221da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 21231da177e4SLinus Torvalds offset += len; 21241da177e4SLinus Torvalds break; 21251da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2126c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 21271da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 21281da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 21291da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 21301da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 21311da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2132c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2133c65b1445SDouglas Gilbert if (0xff == subpcode) { 2134c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2135c65b1445SDouglas Gilbert target, target_dev_id); 2136c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2137c65b1445SDouglas Gilbert } 21381da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2139c65b1445SDouglas Gilbert } else { 214022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2141c65b1445SDouglas Gilbert return check_condition_result; 2142c65b1445SDouglas Gilbert } 21431da177e4SLinus Torvalds offset += len; 21441da177e4SLinus Torvalds break; 21451da177e4SLinus Torvalds default: 214622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 21471da177e4SLinus Torvalds return check_condition_result; 21481da177e4SLinus Torvalds } 21491da177e4SLinus Torvalds if (msense_6) 21501da177e4SLinus Torvalds arr[0] = offset - 1; 21511da177e4SLinus Torvalds else { 21521da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 21531da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 21541da177e4SLinus Torvalds } 21551da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 21561da177e4SLinus Torvalds } 21571da177e4SLinus Torvalds 2158c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2159c65b1445SDouglas Gilbert 2160c2248fc9SDouglas Gilbert static int 2161c2248fc9SDouglas Gilbert resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 2162c65b1445SDouglas Gilbert { 2163c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2164c2248fc9SDouglas Gilbert int param_len, res, mpage; 2165c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 216601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2167c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2168c65b1445SDouglas Gilbert 2169c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2170c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2171c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2172c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 2173c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 217422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2175c65b1445SDouglas Gilbert return check_condition_result; 2176c65b1445SDouglas Gilbert } 2177c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2178c65b1445SDouglas Gilbert if (-1 == res) 2179c65b1445SDouglas Gilbert return (DID_ERROR << 16); 2180c65b1445SDouglas Gilbert else if ((res < param_len) && 2181c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2182cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2183cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2184cbf67842SDouglas Gilbert __func__, param_len, res); 2185c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 2186c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 218723183910SDouglas Gilbert if (md_len > 2) { 218822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2189c65b1445SDouglas Gilbert return check_condition_result; 2190c65b1445SDouglas Gilbert } 2191c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2192c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2193c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2194c65b1445SDouglas Gilbert if (ps) { 219522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2196c65b1445SDouglas Gilbert return check_condition_result; 2197c65b1445SDouglas Gilbert } 2198c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2199c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 2200c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2201c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2202cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2203c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2204c65b1445SDouglas Gilbert return check_condition_result; 2205c65b1445SDouglas Gilbert } 2206c65b1445SDouglas Gilbert switch (mpage) { 2207cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2208cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2209cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2210cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2211cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2212cbf67842SDouglas Gilbert } 2213cbf67842SDouglas Gilbert break; 2214c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2215c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2216c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2217c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2218c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 2219cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2220c65b1445SDouglas Gilbert } 2221c65b1445SDouglas Gilbert break; 2222c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2223c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2224c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2225c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2226cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2227c65b1445SDouglas Gilbert } 2228c65b1445SDouglas Gilbert break; 2229c65b1445SDouglas Gilbert default: 2230c65b1445SDouglas Gilbert break; 2231c65b1445SDouglas Gilbert } 223222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2233c65b1445SDouglas Gilbert return check_condition_result; 2234cbf67842SDouglas Gilbert set_mode_changed_ua: 2235cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2236cbf67842SDouglas Gilbert return 0; 2237c65b1445SDouglas Gilbert } 2238c65b1445SDouglas Gilbert 2239c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2240c65b1445SDouglas Gilbert { 2241c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2242c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2243c65b1445SDouglas Gilbert }; 2244c65b1445SDouglas Gilbert 2245c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2246c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2247c65b1445SDouglas Gilbert } 2248c65b1445SDouglas Gilbert 2249c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2250c65b1445SDouglas Gilbert { 2251c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2252c65b1445SDouglas Gilbert }; 2253c65b1445SDouglas Gilbert 2254c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2255c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2256c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2257c65b1445SDouglas Gilbert arr[5] = 0xff; 2258c65b1445SDouglas Gilbert } 2259c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2260c65b1445SDouglas Gilbert } 2261c65b1445SDouglas Gilbert 2262c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2263c65b1445SDouglas Gilbert 2264c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2265c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2266c65b1445SDouglas Gilbert { 2267c2248fc9SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n; 2268c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 226901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2270c65b1445SDouglas Gilbert 2271c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2272c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2273c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2274c65b1445SDouglas Gilbert if (ppc || sp) { 227522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2276c65b1445SDouglas Gilbert return check_condition_result; 2277c65b1445SDouglas Gilbert } 2278c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 2279c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 228023183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2281c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 2282c65b1445SDouglas Gilbert arr[0] = pcode; 228323183910SDouglas Gilbert if (0 == subpcode) { 2284c65b1445SDouglas Gilbert switch (pcode) { 2285c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2286c65b1445SDouglas Gilbert n = 4; 2287c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2288c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2289c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2290c65b1445SDouglas Gilbert arr[3] = n - 4; 2291c65b1445SDouglas Gilbert break; 2292c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2293c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2294c65b1445SDouglas Gilbert break; 2295c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2296c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2297c65b1445SDouglas Gilbert break; 2298c65b1445SDouglas Gilbert default: 229922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2300c65b1445SDouglas Gilbert return check_condition_result; 2301c65b1445SDouglas Gilbert } 230223183910SDouglas Gilbert } else if (0xff == subpcode) { 230323183910SDouglas Gilbert arr[0] |= 0x40; 230423183910SDouglas Gilbert arr[1] = subpcode; 230523183910SDouglas Gilbert switch (pcode) { 230623183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 230723183910SDouglas Gilbert n = 4; 230823183910SDouglas Gilbert arr[n++] = 0x0; 230923183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 231023183910SDouglas Gilbert arr[n++] = 0x0; 231123183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 231223183910SDouglas Gilbert arr[n++] = 0xd; 231323183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 231423183910SDouglas Gilbert arr[n++] = 0x2f; 231523183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 231623183910SDouglas Gilbert arr[3] = n - 4; 231723183910SDouglas Gilbert break; 231823183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 231923183910SDouglas Gilbert n = 4; 232023183910SDouglas Gilbert arr[n++] = 0xd; 232123183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 232223183910SDouglas Gilbert arr[3] = n - 4; 232323183910SDouglas Gilbert break; 232423183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 232523183910SDouglas Gilbert n = 4; 232623183910SDouglas Gilbert arr[n++] = 0x2f; 232723183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 232823183910SDouglas Gilbert arr[3] = n - 4; 232923183910SDouglas Gilbert break; 233023183910SDouglas Gilbert default: 233122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 233223183910SDouglas Gilbert return check_condition_result; 233323183910SDouglas Gilbert } 233423183910SDouglas Gilbert } else { 233522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 233623183910SDouglas Gilbert return check_condition_result; 233723183910SDouglas Gilbert } 2338c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 2339c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2340c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2341c65b1445SDouglas Gilbert } 2342c65b1445SDouglas Gilbert 2343cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 234419789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 23451da177e4SLinus Torvalds { 2346c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 234722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 23481da177e4SLinus Torvalds return check_condition_result; 23491da177e4SLinus Torvalds } 2350c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2351c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 235222017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2353cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2354c65b1445SDouglas Gilbert return check_condition_result; 2355c65b1445SDouglas Gilbert } 235619789100SFUJITA Tomonori return 0; 235719789100SFUJITA Tomonori } 235819789100SFUJITA Tomonori 2359a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2360c2248fc9SDouglas Gilbert static int 2361c2248fc9SDouglas Gilbert do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write) 236219789100SFUJITA Tomonori { 236319789100SFUJITA Tomonori int ret; 2364c2248fc9SDouglas Gilbert u64 block, rest = 0; 2365a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2366a4517511SAkinobu Mita enum dma_data_direction dir; 236719789100SFUJITA Tomonori 2368c2248fc9SDouglas Gilbert if (do_write) { 2369a4517511SAkinobu Mita sdb = scsi_out(scmd); 2370a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2371a4517511SAkinobu Mita } else { 2372a4517511SAkinobu Mita sdb = scsi_in(scmd); 2373a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2374a4517511SAkinobu Mita } 2375a4517511SAkinobu Mita 2376a4517511SAkinobu Mita if (!sdb->length) 2377a4517511SAkinobu Mita return 0; 2378a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2379a4517511SAkinobu Mita return -1; 238019789100SFUJITA Tomonori 238119789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 238219789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 238319789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 238419789100SFUJITA Tomonori 2385386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2386a4517511SAkinobu Mita fake_storep + (block * scsi_debug_sector_size), 2387386ecb12SDave Gordon (num - rest) * scsi_debug_sector_size, 0, do_write); 2388a4517511SAkinobu Mita if (ret != (num - rest) * scsi_debug_sector_size) 2389a4517511SAkinobu Mita return ret; 2390a4517511SAkinobu Mita 2391a4517511SAkinobu Mita if (rest) { 2392386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2393a4517511SAkinobu Mita fake_storep, rest * scsi_debug_sector_size, 2394386ecb12SDave Gordon (num - rest) * scsi_debug_sector_size, do_write); 2395a4517511SAkinobu Mita } 239619789100SFUJITA Tomonori 239719789100SFUJITA Tomonori return ret; 239819789100SFUJITA Tomonori } 239919789100SFUJITA Tomonori 240038d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 240138d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 240238d5c833SDouglas Gilbert * return false. */ 240338d5c833SDouglas Gilbert static bool 240438d5c833SDouglas Gilbert comp_write_worker(u64 lba, u32 num, const u8 *arr) 240538d5c833SDouglas Gilbert { 240638d5c833SDouglas Gilbert bool res; 240738d5c833SDouglas Gilbert u64 block, rest = 0; 240838d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 240938d5c833SDouglas Gilbert u32 lb_size = scsi_debug_sector_size; 241038d5c833SDouglas Gilbert 241138d5c833SDouglas Gilbert block = do_div(lba, store_blks); 241238d5c833SDouglas Gilbert if (block + num > store_blks) 241338d5c833SDouglas Gilbert rest = block + num - store_blks; 241438d5c833SDouglas Gilbert 241538d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 241638d5c833SDouglas Gilbert (num - rest) * lb_size); 241738d5c833SDouglas Gilbert if (!res) 241838d5c833SDouglas Gilbert return res; 241938d5c833SDouglas Gilbert if (rest) 242038d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 242138d5c833SDouglas Gilbert rest * lb_size); 242238d5c833SDouglas Gilbert if (!res) 242338d5c833SDouglas Gilbert return res; 242438d5c833SDouglas Gilbert arr += num * lb_size; 242538d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 242638d5c833SDouglas Gilbert if (rest) 242738d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 242838d5c833SDouglas Gilbert rest * lb_size); 242938d5c833SDouglas Gilbert return res; 243038d5c833SDouglas Gilbert } 243138d5c833SDouglas Gilbert 243251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2433beb40ea4SAkinobu Mita { 243451d648afSAkinobu Mita __be16 csum; 2435beb40ea4SAkinobu Mita 243651d648afSAkinobu Mita if (scsi_debug_guard) 243751d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 243851d648afSAkinobu Mita else 2439beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 244051d648afSAkinobu Mita 2441beb40ea4SAkinobu Mita return csum; 2442beb40ea4SAkinobu Mita } 2443beb40ea4SAkinobu Mita 2444beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 2445beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2446beb40ea4SAkinobu Mita { 244751d648afSAkinobu Mita __be16 csum = dif_compute_csum(data, scsi_debug_sector_size); 2448beb40ea4SAkinobu Mita 2449beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2450c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2451beb40ea4SAkinobu Mita (unsigned long)sector, 2452beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2453beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2454beb40ea4SAkinobu Mita return 0x01; 2455beb40ea4SAkinobu Mita } 2456beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 2457beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2458c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2459c1287970STomas Winkler (unsigned long)sector); 2460beb40ea4SAkinobu Mita return 0x03; 2461beb40ea4SAkinobu Mita } 2462beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2463beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2464c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2465c1287970STomas Winkler (unsigned long)sector); 2466beb40ea4SAkinobu Mita return 0x03; 2467beb40ea4SAkinobu Mita } 2468beb40ea4SAkinobu Mita return 0; 2469beb40ea4SAkinobu Mita } 2470beb40ea4SAkinobu Mita 2471bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 247265f72f2aSAkinobu Mita unsigned int sectors, bool read) 2473c6a44287SMartin K. Petersen { 2474be4e11beSAkinobu Mita size_t resid; 2475c6a44287SMartin K. Petersen void *paddr; 247614faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2477be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2478c6a44287SMartin K. Petersen 2479e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2480e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2481c6a44287SMartin K. Petersen 2482be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2483be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2484be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2485be4e11beSAkinobu Mita 2486be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2487be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 248814faa944SAkinobu Mita void *start = dif_store(sector); 2489be4e11beSAkinobu Mita size_t rest = 0; 249014faa944SAkinobu Mita 249114faa944SAkinobu Mita if (dif_store_end < start + len) 249214faa944SAkinobu Mita rest = start + len - dif_store_end; 2493c6a44287SMartin K. Petersen 2494be4e11beSAkinobu Mita paddr = miter.addr; 249514faa944SAkinobu Mita 249665f72f2aSAkinobu Mita if (read) 249765f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 249865f72f2aSAkinobu Mita else 249965f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 250065f72f2aSAkinobu Mita 250165f72f2aSAkinobu Mita if (rest) { 250265f72f2aSAkinobu Mita if (read) 250314faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 250465f72f2aSAkinobu Mita else 250565f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 250665f72f2aSAkinobu Mita } 2507c6a44287SMartin K. Petersen 2508e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2509c6a44287SMartin K. Petersen resid -= len; 2510c6a44287SMartin K. Petersen } 2511be4e11beSAkinobu Mita sg_miter_stop(&miter); 2512bb8c063cSAkinobu Mita } 2513c6a44287SMartin K. Petersen 2514bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2515bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2516bb8c063cSAkinobu Mita { 2517bb8c063cSAkinobu Mita unsigned int i; 2518bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 2519bb8c063cSAkinobu Mita sector_t sector; 2520bb8c063cSAkinobu Mita 2521c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2522bb8c063cSAkinobu Mita int ret; 2523bb8c063cSAkinobu Mita 2524bb8c063cSAkinobu Mita sector = start_sec + i; 2525bb8c063cSAkinobu Mita sdt = dif_store(sector); 2526bb8c063cSAkinobu Mita 252751d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2528bb8c063cSAkinobu Mita continue; 2529bb8c063cSAkinobu Mita 2530bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2531bb8c063cSAkinobu Mita if (ret) { 2532bb8c063cSAkinobu Mita dif_errors++; 2533bb8c063cSAkinobu Mita return ret; 2534bb8c063cSAkinobu Mita } 2535bb8c063cSAkinobu Mita } 2536bb8c063cSAkinobu Mita 253765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2538c6a44287SMartin K. Petersen dix_reads++; 2539c6a44287SMartin K. Petersen 2540c6a44287SMartin K. Petersen return 0; 2541c6a44287SMartin K. Petersen } 2542c6a44287SMartin K. Petersen 2543c2248fc9SDouglas Gilbert static int 2544c2248fc9SDouglas Gilbert resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 254519789100SFUJITA Tomonori { 2546c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2547c2248fc9SDouglas Gilbert u64 lba; 2548c2248fc9SDouglas Gilbert u32 num; 2549c2248fc9SDouglas Gilbert u32 ei_lba; 255019789100SFUJITA Tomonori unsigned long iflags; 255119789100SFUJITA Tomonori int ret; 2552c2248fc9SDouglas Gilbert bool check_prot; 255319789100SFUJITA Tomonori 2554c2248fc9SDouglas Gilbert switch (cmd[0]) { 2555c2248fc9SDouglas Gilbert case READ_16: 2556c2248fc9SDouglas Gilbert ei_lba = 0; 2557c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2558c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2559c2248fc9SDouglas Gilbert check_prot = true; 2560c2248fc9SDouglas Gilbert break; 2561c2248fc9SDouglas Gilbert case READ_10: 2562c2248fc9SDouglas Gilbert ei_lba = 0; 2563c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2564c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2565c2248fc9SDouglas Gilbert check_prot = true; 2566c2248fc9SDouglas Gilbert break; 2567c2248fc9SDouglas Gilbert case READ_6: 2568c2248fc9SDouglas Gilbert ei_lba = 0; 2569c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2570c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2571c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2572c2248fc9SDouglas Gilbert check_prot = true; 2573c2248fc9SDouglas Gilbert break; 2574c2248fc9SDouglas Gilbert case READ_12: 2575c2248fc9SDouglas Gilbert ei_lba = 0; 2576c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2577c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2578c2248fc9SDouglas Gilbert check_prot = true; 2579c2248fc9SDouglas Gilbert break; 2580c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2581c2248fc9SDouglas Gilbert ei_lba = 0; 2582c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2583c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2584c2248fc9SDouglas Gilbert check_prot = false; 2585c2248fc9SDouglas Gilbert break; 2586c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2587c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2588c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2589c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2590c2248fc9SDouglas Gilbert check_prot = false; 2591c2248fc9SDouglas Gilbert break; 2592c2248fc9SDouglas Gilbert } 2593c2248fc9SDouglas Gilbert if (check_prot) { 2594c2248fc9SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2595c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2596c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2597c2248fc9SDouglas Gilbert return check_condition_result; 2598c2248fc9SDouglas Gilbert } 2599c2248fc9SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 2600c2248fc9SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 2601c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2602c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2603c2248fc9SDouglas Gilbert "to DIF device\n"); 2604c2248fc9SDouglas Gilbert } 2605c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2606c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2607c2248fc9SDouglas Gilbert 2608c2248fc9SDouglas Gilbert if (ep->inj_short) 2609c2248fc9SDouglas Gilbert num /= 2; 2610c2248fc9SDouglas Gilbert } 2611c2248fc9SDouglas Gilbert 2612c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2613c2248fc9SDouglas Gilbert if (lba + num > sdebug_capacity) { 2614c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2615c2248fc9SDouglas Gilbert return check_condition_result; 2616c2248fc9SDouglas Gilbert } 2617c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2618c2248fc9SDouglas Gilbert if (num > sdebug_store_sectors) { 2619c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2620c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2621c2248fc9SDouglas Gilbert return check_condition_result; 2622c2248fc9SDouglas Gilbert } 262319789100SFUJITA Tomonori 26241da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 262532f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2626c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 2627c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2628c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2629c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2630c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2631c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 263232f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 263332f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2634c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2635c65b1445SDouglas Gilbert } 2636c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 26371da177e4SLinus Torvalds return check_condition_result; 26381da177e4SLinus Torvalds } 2639c6a44287SMartin K. Petersen 26406c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 26416c78cc06SAkinobu Mita 2642c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2643c2248fc9SDouglas Gilbert if (scsi_debug_dix && scsi_prot_sg_count(scp)) { 2644c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2645c6a44287SMartin K. Petersen 2646c6a44287SMartin K. Petersen if (prot_ret) { 26476c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2648c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2649c6a44287SMartin K. Petersen return illegal_condition_result; 2650c6a44287SMartin K. Petersen } 2651c6a44287SMartin K. Petersen } 2652c6a44287SMartin K. Petersen 2653c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 26541da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2655a4517511SAkinobu Mita if (ret == -1) 2656a4517511SAkinobu Mita return DID_ERROR << 16; 2657a4517511SAkinobu Mita 2658c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2659a4517511SAkinobu Mita 2660c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2661c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2662c2248fc9SDouglas Gilbert 2663c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2664c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2665c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2666c2248fc9SDouglas Gilbert return check_condition_result; 2667c2248fc9SDouglas Gilbert } else if (ep->inj_transport) { 2668c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2669c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2670c2248fc9SDouglas Gilbert return check_condition_result; 2671c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2672c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2673c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2674c2248fc9SDouglas Gilbert return illegal_condition_result; 2675c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2676c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2677c2248fc9SDouglas Gilbert return illegal_condition_result; 2678c2248fc9SDouglas Gilbert } 2679c2248fc9SDouglas Gilbert } 2680a4517511SAkinobu Mita return 0; 26811da177e4SLinus Torvalds } 26821da177e4SLinus Torvalds 268358a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2684c6a44287SMartin K. Petersen { 2685cbf67842SDouglas Gilbert int i, j, n; 2686c6a44287SMartin K. Petersen 2687cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2688c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2689cbf67842SDouglas Gilbert char b[128]; 2690c6a44287SMartin K. Petersen 2691cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2692c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2693c6a44287SMartin K. Petersen 2694cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2695cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2696cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2697cbf67842SDouglas Gilbert else 2698cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2699cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2700cbf67842SDouglas Gilbert } 2701cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2702c6a44287SMartin K. Petersen } 2703c6a44287SMartin K. Petersen } 2704c6a44287SMartin K. Petersen 2705c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2706395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2707c6a44287SMartin K. Petersen { 2708be4e11beSAkinobu Mita int ret; 2709c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 2710be4e11beSAkinobu Mita void *daddr; 271165f72f2aSAkinobu Mita sector_t sector = start_sec; 2712c6a44287SMartin K. Petersen int ppage_offset; 2713be4e11beSAkinobu Mita int dpage_offset; 2714be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2715be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2716c6a44287SMartin K. Petersen 2717c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2718c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2719c6a44287SMartin K. Petersen 2720be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2721be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2722be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2723be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2724be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2725c6a44287SMartin K. Petersen 2726be4e11beSAkinobu Mita /* For each protection page */ 2727be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2728be4e11beSAkinobu Mita dpage_offset = 0; 2729be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2730be4e11beSAkinobu Mita ret = 0x01; 2731be4e11beSAkinobu Mita goto out; 2732c6a44287SMartin K. Petersen } 2733c6a44287SMartin K. Petersen 2734be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 2735be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 2736be4e11beSAkinobu Mita /* If we're at the end of the current 2737be4e11beSAkinobu Mita * data page advance to the next one 2738be4e11beSAkinobu Mita */ 2739be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2740be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2741be4e11beSAkinobu Mita ret = 0x01; 2742be4e11beSAkinobu Mita goto out; 2743be4e11beSAkinobu Mita } 2744be4e11beSAkinobu Mita dpage_offset = 0; 2745be4e11beSAkinobu Mita } 2746c6a44287SMartin K. Petersen 2747be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2748be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2749be4e11beSAkinobu Mita 2750be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2751beb40ea4SAkinobu Mita if (ret) { 2752be4e11beSAkinobu Mita dump_sector(daddr, scsi_debug_sector_size); 2753395cef03SMartin K. Petersen goto out; 2754395cef03SMartin K. Petersen } 2755395cef03SMartin K. Petersen 2756c6a44287SMartin K. Petersen sector++; 2757395cef03SMartin K. Petersen ei_lba++; 2758be4e11beSAkinobu Mita dpage_offset += scsi_debug_sector_size; 2759c6a44287SMartin K. Petersen } 2760be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2761be4e11beSAkinobu Mita sg_miter_stop(&diter); 2762c6a44287SMartin K. Petersen } 2763be4e11beSAkinobu Mita sg_miter_stop(&piter); 2764c6a44287SMartin K. Petersen 276565f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2766c6a44287SMartin K. Petersen dix_writes++; 2767c6a44287SMartin K. Petersen 2768c6a44287SMartin K. Petersen return 0; 2769c6a44287SMartin K. Petersen 2770c6a44287SMartin K. Petersen out: 2771c6a44287SMartin K. Petersen dif_errors++; 2772be4e11beSAkinobu Mita sg_miter_stop(&diter); 2773be4e11beSAkinobu Mita sg_miter_stop(&piter); 2774c6a44287SMartin K. Petersen return ret; 2775c6a44287SMartin K. Petersen } 2776c6a44287SMartin K. Petersen 2777b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2778b90ebc3dSAkinobu Mita { 2779b90ebc3dSAkinobu Mita if (scsi_debug_unmap_alignment) { 2780b90ebc3dSAkinobu Mita lba += scsi_debug_unmap_granularity - 2781b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2782b90ebc3dSAkinobu Mita } 278349413112SArnd Bergmann sector_div(lba, scsi_debug_unmap_granularity); 2784b90ebc3dSAkinobu Mita 2785b90ebc3dSAkinobu Mita return lba; 2786b90ebc3dSAkinobu Mita } 2787b90ebc3dSAkinobu Mita 2788b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2789b90ebc3dSAkinobu Mita { 2790a027b5b9SAkinobu Mita sector_t lba = index * scsi_debug_unmap_granularity; 2791a027b5b9SAkinobu Mita 2792a027b5b9SAkinobu Mita if (scsi_debug_unmap_alignment) { 2793a027b5b9SAkinobu Mita lba -= scsi_debug_unmap_granularity - 2794b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2795b90ebc3dSAkinobu Mita } 2796b90ebc3dSAkinobu Mita 2797a027b5b9SAkinobu Mita return lba; 2798a027b5b9SAkinobu Mita } 2799a027b5b9SAkinobu Mita 280044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 280144d92694SMartin K. Petersen { 2802b90ebc3dSAkinobu Mita sector_t end; 2803b90ebc3dSAkinobu Mita unsigned int mapped; 2804b90ebc3dSAkinobu Mita unsigned long index; 2805b90ebc3dSAkinobu Mita unsigned long next; 280644d92694SMartin K. Petersen 2807b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2808b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 280944d92694SMartin K. Petersen 281044d92694SMartin K. Petersen if (mapped) 2811b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 281244d92694SMartin K. Petersen else 2813b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 281444d92694SMartin K. Petersen 2815b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 281644d92694SMartin K. Petersen *num = end - lba; 281744d92694SMartin K. Petersen 281844d92694SMartin K. Petersen return mapped; 281944d92694SMartin K. Petersen } 282044d92694SMartin K. Petersen 282144d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 282244d92694SMartin K. Petersen { 282344d92694SMartin K. Petersen sector_t end = lba + len; 282444d92694SMartin K. Petersen 282544d92694SMartin K. Petersen while (lba < end) { 2826b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 282744d92694SMartin K. Petersen 2828b90ebc3dSAkinobu Mita if (index < map_size) 2829b90ebc3dSAkinobu Mita set_bit(index, map_storep); 283044d92694SMartin K. Petersen 2831b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 283244d92694SMartin K. Petersen } 283344d92694SMartin K. Petersen } 283444d92694SMartin K. Petersen 283544d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 283644d92694SMartin K. Petersen { 283744d92694SMartin K. Petersen sector_t end = lba + len; 283844d92694SMartin K. Petersen 283944d92694SMartin K. Petersen while (lba < end) { 2840b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 284144d92694SMartin K. Petersen 2842b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2843b90ebc3dSAkinobu Mita lba + scsi_debug_unmap_granularity <= end && 2844b90ebc3dSAkinobu Mita index < map_size) { 2845b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2846b90ebc3dSAkinobu Mita if (scsi_debug_lbprz) { 2847be1dd78dSEric Sandeen memset(fake_storep + 2848cc34a8e6SAkinobu Mita lba * scsi_debug_sector_size, 0, 2849cc34a8e6SAkinobu Mita scsi_debug_sector_size * 2850cc34a8e6SAkinobu Mita scsi_debug_unmap_granularity); 2851be1dd78dSEric Sandeen } 2852e9926b43SAkinobu Mita if (dif_storep) { 2853e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2854e9926b43SAkinobu Mita sizeof(*dif_storep) * 2855e9926b43SAkinobu Mita scsi_debug_unmap_granularity); 2856e9926b43SAkinobu Mita } 2857b90ebc3dSAkinobu Mita } 2858b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 285944d92694SMartin K. Petersen } 286044d92694SMartin K. Petersen } 286144d92694SMartin K. Petersen 2862c2248fc9SDouglas Gilbert static int 2863c2248fc9SDouglas Gilbert resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 28641da177e4SLinus Torvalds { 2865c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2866c2248fc9SDouglas Gilbert u64 lba; 2867c2248fc9SDouglas Gilbert u32 num; 2868c2248fc9SDouglas Gilbert u32 ei_lba; 28691da177e4SLinus Torvalds unsigned long iflags; 287019789100SFUJITA Tomonori int ret; 2871c2248fc9SDouglas Gilbert bool check_prot; 28721da177e4SLinus Torvalds 2873c2248fc9SDouglas Gilbert switch (cmd[0]) { 2874c2248fc9SDouglas Gilbert case WRITE_16: 2875c2248fc9SDouglas Gilbert ei_lba = 0; 2876c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2877c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2878c2248fc9SDouglas Gilbert check_prot = true; 2879c2248fc9SDouglas Gilbert break; 2880c2248fc9SDouglas Gilbert case WRITE_10: 2881c2248fc9SDouglas Gilbert ei_lba = 0; 2882c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2883c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2884c2248fc9SDouglas Gilbert check_prot = true; 2885c2248fc9SDouglas Gilbert break; 2886c2248fc9SDouglas Gilbert case WRITE_6: 2887c2248fc9SDouglas Gilbert ei_lba = 0; 2888c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2889c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2890c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2891c2248fc9SDouglas Gilbert check_prot = true; 2892c2248fc9SDouglas Gilbert break; 2893c2248fc9SDouglas Gilbert case WRITE_12: 2894c2248fc9SDouglas Gilbert ei_lba = 0; 2895c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2896c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2897c2248fc9SDouglas Gilbert check_prot = true; 2898c2248fc9SDouglas Gilbert break; 2899c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2900c2248fc9SDouglas Gilbert ei_lba = 0; 2901c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2902c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2903c2248fc9SDouglas Gilbert check_prot = false; 2904c2248fc9SDouglas Gilbert break; 2905c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2906c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2907c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2908c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2909c2248fc9SDouglas Gilbert check_prot = false; 2910c2248fc9SDouglas Gilbert break; 2911c2248fc9SDouglas Gilbert } 2912c2248fc9SDouglas Gilbert if (check_prot) { 2913c2248fc9SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2914c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2915c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2916c2248fc9SDouglas Gilbert return check_condition_result; 2917c2248fc9SDouglas Gilbert } 2918c2248fc9SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 2919c2248fc9SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 2920c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2921c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2922c2248fc9SDouglas Gilbert "to DIF device\n"); 2923c2248fc9SDouglas Gilbert } 2924c2248fc9SDouglas Gilbert 2925c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2926c2248fc9SDouglas Gilbert if (lba + num > sdebug_capacity) { 2927c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2928c2248fc9SDouglas Gilbert return check_condition_result; 2929c2248fc9SDouglas Gilbert } 2930c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2931c2248fc9SDouglas Gilbert if (num > sdebug_store_sectors) { 2932c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2933c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2934c2248fc9SDouglas Gilbert return check_condition_result; 2935c2248fc9SDouglas Gilbert } 29361da177e4SLinus Torvalds 29376c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 29386c78cc06SAkinobu Mita 2939c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2940c2248fc9SDouglas Gilbert if (scsi_debug_dix && scsi_prot_sg_count(scp)) { 2941c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2942c6a44287SMartin K. Petersen 2943c6a44287SMartin K. Petersen if (prot_ret) { 29446c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2945c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2946c6a44287SMartin K. Petersen return illegal_condition_result; 2947c6a44287SMartin K. Petersen } 2948c6a44287SMartin K. Petersen } 2949c6a44287SMartin K. Petersen 2950c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 29519ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 295244d92694SMartin K. Petersen map_region(lba, num); 29531da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 295419789100SFUJITA Tomonori if (-1 == ret) 29551da177e4SLinus Torvalds return (DID_ERROR << 16); 2956597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 29571da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2958c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2959cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2960cbf67842SDouglas Gilbert my_name, num * scsi_debug_sector_size, ret); 296144d92694SMartin K. Petersen 2962c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2963c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2964c2248fc9SDouglas Gilbert 2965c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2966c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2967c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2968c2248fc9SDouglas Gilbert return check_condition_result; 2969c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2970c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2971c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2972c2248fc9SDouglas Gilbert return illegal_condition_result; 2973c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2974c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2975c2248fc9SDouglas Gilbert return illegal_condition_result; 2976c2248fc9SDouglas Gilbert } 2977c2248fc9SDouglas Gilbert } 29781da177e4SLinus Torvalds return 0; 29791da177e4SLinus Torvalds } 29801da177e4SLinus Torvalds 2981c2248fc9SDouglas Gilbert static int 2982c2248fc9SDouglas Gilbert resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba, 2983c2248fc9SDouglas Gilbert bool unmap, bool ndob) 298444d92694SMartin K. Petersen { 298544d92694SMartin K. Petersen unsigned long iflags; 298644d92694SMartin K. Petersen unsigned long long i; 298744d92694SMartin K. Petersen int ret; 298844d92694SMartin K. Petersen 2989c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 299044d92694SMartin K. Petersen if (ret) 299144d92694SMartin K. Petersen return ret; 299244d92694SMartin K. Petersen 299344d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 299444d92694SMartin K. Petersen 29959ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 299644d92694SMartin K. Petersen unmap_region(lba, num); 299744d92694SMartin K. Petersen goto out; 299844d92694SMartin K. Petersen } 299944d92694SMartin K. Petersen 3000c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 3001c2248fc9SDouglas Gilbert if (ndob) { 3002c2248fc9SDouglas Gilbert memset(fake_storep + (lba * scsi_debug_sector_size), 0, 3003c2248fc9SDouglas Gilbert scsi_debug_sector_size); 3004c2248fc9SDouglas Gilbert ret = 0; 3005c2248fc9SDouglas Gilbert } else 3006c2248fc9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + 3007c2248fc9SDouglas Gilbert (lba * scsi_debug_sector_size), 300844d92694SMartin K. Petersen scsi_debug_sector_size); 300944d92694SMartin K. Petersen 301044d92694SMartin K. Petersen if (-1 == ret) { 301144d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 301244d92694SMartin K. Petersen return (DID_ERROR << 16); 301344d92694SMartin K. Petersen } else if ((ret < (num * scsi_debug_sector_size)) && 301444d92694SMartin K. Petersen (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 3015c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3016cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 3017cbf67842SDouglas Gilbert my_name, "write same", 3018cbf67842SDouglas Gilbert num * scsi_debug_sector_size, ret); 301944d92694SMartin K. Petersen 302044d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 302144d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 302244d92694SMartin K. Petersen memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), 302344d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 302444d92694SMartin K. Petersen scsi_debug_sector_size); 302544d92694SMartin K. Petersen 30269ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 302744d92694SMartin K. Petersen map_region(lba, num); 302844d92694SMartin K. Petersen out: 302944d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 303044d92694SMartin K. Petersen 303144d92694SMartin K. Petersen return 0; 303244d92694SMartin K. Petersen } 303344d92694SMartin K. Petersen 3034c2248fc9SDouglas Gilbert static int 3035c2248fc9SDouglas Gilbert resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3036c2248fc9SDouglas Gilbert { 3037c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3038c2248fc9SDouglas Gilbert u32 lba; 3039c2248fc9SDouglas Gilbert u16 num; 3040c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3041c2248fc9SDouglas Gilbert bool unmap = false; 3042c2248fc9SDouglas Gilbert 3043c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3044c2248fc9SDouglas Gilbert if (scsi_debug_lbpws10 == 0) { 3045c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3046c2248fc9SDouglas Gilbert return check_condition_result; 3047c2248fc9SDouglas Gilbert } else 3048c2248fc9SDouglas Gilbert unmap = true; 3049c2248fc9SDouglas Gilbert } 3050c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3051c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3052c2248fc9SDouglas Gilbert if (num > scsi_debug_write_same_length) { 3053c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3054c2248fc9SDouglas Gilbert return check_condition_result; 3055c2248fc9SDouglas Gilbert } 3056c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3057c2248fc9SDouglas Gilbert } 3058c2248fc9SDouglas Gilbert 3059c2248fc9SDouglas Gilbert static int 3060c2248fc9SDouglas Gilbert resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3061c2248fc9SDouglas Gilbert { 3062c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3063c2248fc9SDouglas Gilbert u64 lba; 3064c2248fc9SDouglas Gilbert u32 num; 3065c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3066c2248fc9SDouglas Gilbert bool unmap = false; 3067c2248fc9SDouglas Gilbert bool ndob = false; 3068c2248fc9SDouglas Gilbert 3069c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3070c2248fc9SDouglas Gilbert if (scsi_debug_lbpws == 0) { 3071c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3072c2248fc9SDouglas Gilbert return check_condition_result; 3073c2248fc9SDouglas Gilbert } else 3074c2248fc9SDouglas Gilbert unmap = true; 3075c2248fc9SDouglas Gilbert } 3076c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3077c2248fc9SDouglas Gilbert ndob = true; 3078c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3079c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3080c2248fc9SDouglas Gilbert if (num > scsi_debug_write_same_length) { 3081c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3082c2248fc9SDouglas Gilbert return check_condition_result; 3083c2248fc9SDouglas Gilbert } 3084c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3085c2248fc9SDouglas Gilbert } 3086c2248fc9SDouglas Gilbert 3087acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3088acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3089acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3090acafd0b9SEwan D. Milne static int 3091acafd0b9SEwan D. Milne resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3092acafd0b9SEwan D. Milne { 3093acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3094acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3095acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3096acafd0b9SEwan D. Milne u8 mode; 3097acafd0b9SEwan D. Milne 3098acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3099acafd0b9SEwan D. Milne switch (mode) { 3100acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3101acafd0b9SEwan D. Milne /* set UAs on this device only */ 3102acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3103acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3104acafd0b9SEwan D. Milne break; 3105acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3106acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3107acafd0b9SEwan D. Milne break; 3108acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3109acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3110acafd0b9SEwan D. Milne list_for_each_entry(dp, 3111acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3112acafd0b9SEwan D. Milne dev_list) 3113acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3114acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3115acafd0b9SEwan D. Milne if (devip != dp) 3116acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3117acafd0b9SEwan D. Milne dp->uas_bm); 3118acafd0b9SEwan D. Milne } 3119acafd0b9SEwan D. Milne break; 3120acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3121acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3122acafd0b9SEwan D. Milne list_for_each_entry(dp, 3123acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3124acafd0b9SEwan D. Milne dev_list) 3125acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3126acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3127acafd0b9SEwan D. Milne dp->uas_bm); 3128acafd0b9SEwan D. Milne break; 3129acafd0b9SEwan D. Milne default: 3130acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3131acafd0b9SEwan D. Milne break; 3132acafd0b9SEwan D. Milne } 3133acafd0b9SEwan D. Milne return 0; 3134acafd0b9SEwan D. Milne } 3135acafd0b9SEwan D. Milne 313638d5c833SDouglas Gilbert static int 313738d5c833SDouglas Gilbert resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 313838d5c833SDouglas Gilbert { 313938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 314038d5c833SDouglas Gilbert u8 *arr; 314138d5c833SDouglas Gilbert u8 *fake_storep_hold; 314238d5c833SDouglas Gilbert u64 lba; 314338d5c833SDouglas Gilbert u32 dnum; 314438d5c833SDouglas Gilbert u32 lb_size = scsi_debug_sector_size; 314538d5c833SDouglas Gilbert u8 num; 314638d5c833SDouglas Gilbert unsigned long iflags; 314738d5c833SDouglas Gilbert int ret; 3148d467d31fSDouglas Gilbert int retval = 0; 314938d5c833SDouglas Gilbert 3150d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 315138d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 315238d5c833SDouglas Gilbert if (0 == num) 315338d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 315438d5c833SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 315538d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 315638d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 315738d5c833SDouglas Gilbert return check_condition_result; 315838d5c833SDouglas Gilbert } 315938d5c833SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 316038d5c833SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 316138d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 316238d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 316338d5c833SDouglas Gilbert "to DIF device\n"); 316438d5c833SDouglas Gilbert 316538d5c833SDouglas Gilbert /* inline check_device_access_params() */ 316638d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 316738d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 316838d5c833SDouglas Gilbert return check_condition_result; 316938d5c833SDouglas Gilbert } 317038d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 317138d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 317238d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 317338d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 317438d5c833SDouglas Gilbert return check_condition_result; 317538d5c833SDouglas Gilbert } 3176d467d31fSDouglas Gilbert dnum = 2 * num; 3177d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3178d467d31fSDouglas Gilbert if (NULL == arr) { 3179d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3180d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3181d467d31fSDouglas Gilbert return check_condition_result; 3182d467d31fSDouglas Gilbert } 318338d5c833SDouglas Gilbert 318438d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 318538d5c833SDouglas Gilbert 318638d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 318738d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 318838d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 318938d5c833SDouglas Gilbert fake_storep = arr; 319038d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 319138d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 319238d5c833SDouglas Gilbert if (ret == -1) { 3193d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3194d467d31fSDouglas Gilbert goto cleanup; 319538d5c833SDouglas Gilbert } else if ((ret < (dnum * lb_size)) && 319638d5c833SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 319738d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 319838d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 319938d5c833SDouglas Gilbert dnum * lb_size, ret); 320038d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 320138d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3202d467d31fSDouglas Gilbert retval = check_condition_result; 3203d467d31fSDouglas Gilbert goto cleanup; 320438d5c833SDouglas Gilbert } 320538d5c833SDouglas Gilbert if (scsi_debug_lbp()) 320638d5c833SDouglas Gilbert map_region(lba, num); 3207d467d31fSDouglas Gilbert cleanup: 320838d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3209d467d31fSDouglas Gilbert kfree(arr); 3210d467d31fSDouglas Gilbert return retval; 321138d5c833SDouglas Gilbert } 321238d5c833SDouglas Gilbert 321344d92694SMartin K. Petersen struct unmap_block_desc { 321444d92694SMartin K. Petersen __be64 lba; 321544d92694SMartin K. Petersen __be32 blocks; 321644d92694SMartin K. Petersen __be32 __reserved; 321744d92694SMartin K. Petersen }; 321844d92694SMartin K. Petersen 3219c2248fc9SDouglas Gilbert static int 3220c2248fc9SDouglas Gilbert resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 322144d92694SMartin K. Petersen { 322244d92694SMartin K. Petersen unsigned char *buf; 322344d92694SMartin K. Petersen struct unmap_block_desc *desc; 322444d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 322544d92694SMartin K. Petersen int ret; 32266c78cc06SAkinobu Mita unsigned long iflags; 322744d92694SMartin K. Petersen 322844d92694SMartin K. Petersen 3229c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3230c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3231c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3232c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 323344d92694SMartin K. Petersen 323444d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3235c2248fc9SDouglas Gilbert if (descriptors > scsi_debug_unmap_max_desc) { 3236c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 323744d92694SMartin K. Petersen return check_condition_result; 3238c2248fc9SDouglas Gilbert } 323944d92694SMartin K. Petersen 3240c2248fc9SDouglas Gilbert buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 3241c2248fc9SDouglas Gilbert if (!buf) { 3242c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3243c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3244c2248fc9SDouglas Gilbert return check_condition_result; 3245c2248fc9SDouglas Gilbert } 3246c2248fc9SDouglas Gilbert 3247c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 324844d92694SMartin K. Petersen 324944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 325044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 325144d92694SMartin K. Petersen 325244d92694SMartin K. Petersen desc = (void *)&buf[8]; 325344d92694SMartin K. Petersen 32546c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 32556c78cc06SAkinobu Mita 325644d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 325744d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 325844d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 325944d92694SMartin K. Petersen 3260c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 326144d92694SMartin K. Petersen if (ret) 326244d92694SMartin K. Petersen goto out; 326344d92694SMartin K. Petersen 326444d92694SMartin K. Petersen unmap_region(lba, num); 326544d92694SMartin K. Petersen } 326644d92694SMartin K. Petersen 326744d92694SMartin K. Petersen ret = 0; 326844d92694SMartin K. Petersen 326944d92694SMartin K. Petersen out: 32706c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 327144d92694SMartin K. Petersen kfree(buf); 327244d92694SMartin K. Petersen 327344d92694SMartin K. Petersen return ret; 327444d92694SMartin K. Petersen } 327544d92694SMartin K. Petersen 327644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 327744d92694SMartin K. Petersen 3278c2248fc9SDouglas Gilbert static int 3279c2248fc9SDouglas Gilbert resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 328044d92694SMartin K. Petersen { 3281c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3282c2248fc9SDouglas Gilbert u64 lba; 3283c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3284c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 328544d92694SMartin K. Petersen int ret; 328644d92694SMartin K. Petersen 3287c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3288c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 328944d92694SMartin K. Petersen 329044d92694SMartin K. Petersen if (alloc_len < 24) 329144d92694SMartin K. Petersen return 0; 329244d92694SMartin K. Petersen 3293c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 329444d92694SMartin K. Petersen if (ret) 329544d92694SMartin K. Petersen return ret; 329644d92694SMartin K. Petersen 3297c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 329844d92694SMartin K. Petersen mapped = map_state(lba, &num); 3299c2248fc9SDouglas Gilbert else { 3300c2248fc9SDouglas Gilbert mapped = 1; 3301c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3302c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3303c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3304c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3305c2248fc9SDouglas Gilbert else 3306c2248fc9SDouglas Gilbert num = 0xffffffff; 3307c2248fc9SDouglas Gilbert } 330844d92694SMartin K. Petersen 330944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3310c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3311c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3312c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3313c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 331444d92694SMartin K. Petersen 3315c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 331644d92694SMartin K. Petersen } 331744d92694SMartin K. Petersen 3318c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 33191da177e4SLinus Torvalds 33201da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 33211da177e4SLinus Torvalds struct sdebug_dev_info * devip) 33221da177e4SLinus Torvalds { 33231da177e4SLinus Torvalds unsigned int alloc_len; 332422017ed2SDouglas Gilbert int lun_cnt, i, upper, num, n, want_wlun, shortish; 332522017ed2SDouglas Gilbert u64 lun; 332601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 33271da177e4SLinus Torvalds int select_report = (int)cmd[2]; 33281da177e4SLinus Torvalds struct scsi_lun *one_lun; 33291da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 3330c65b1445SDouglas Gilbert unsigned char * max_addr; 33311da177e4SLinus Torvalds 333219c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 33331da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 333422017ed2SDouglas Gilbert shortish = (alloc_len < 4); 333522017ed2SDouglas Gilbert if (shortish || (select_report > 2)) { 333622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1); 33371da177e4SLinus Torvalds return check_condition_result; 33381da177e4SLinus Torvalds } 33391da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 33401da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 33411da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 3342c65b1445SDouglas Gilbert if (1 == select_report) 3343c65b1445SDouglas Gilbert lun_cnt = 0; 3344c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 3345c65b1445SDouglas Gilbert --lun_cnt; 334622017ed2SDouglas Gilbert want_wlun = (select_report > 0) ? 1 : 0; 334722017ed2SDouglas Gilbert num = lun_cnt + want_wlun; 3348c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 3349c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 3350c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 3351c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 3352c65b1445SDouglas Gilbert if (n < num) { 335322017ed2SDouglas Gilbert want_wlun = 0; 3354c65b1445SDouglas Gilbert lun_cnt = n; 3355c65b1445SDouglas Gilbert } 33561da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 3357c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 3358c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 3359c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 3360c65b1445SDouglas Gilbert i++, lun++) { 3361c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 33621da177e4SLinus Torvalds if (upper) 33631da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 33641da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 3365c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 33661da177e4SLinus Torvalds } 336722017ed2SDouglas Gilbert if (want_wlun) { 336834d55434STomas Winkler one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff; 336934d55434STomas Winkler one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff; 3370c65b1445SDouglas Gilbert i++; 3371c65b1445SDouglas Gilbert } 3372c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 33731da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 33741da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 33751da177e4SLinus Torvalds } 33761da177e4SLinus Torvalds 3377c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3378c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3379c639d14eSFUJITA Tomonori { 3380be4e11beSAkinobu Mita int j; 3381c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3382c639d14eSFUJITA Tomonori unsigned int offset; 3383c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3384be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3385c639d14eSFUJITA Tomonori 3386c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3387c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 3388c5af0db9SAkinobu Mita if (!buf) { 338922017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 339022017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3391c5af0db9SAkinobu Mita return check_condition_result; 3392c5af0db9SAkinobu Mita } 3393c639d14eSFUJITA Tomonori 339421a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3395c639d14eSFUJITA Tomonori 3396c639d14eSFUJITA Tomonori offset = 0; 3397be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3398be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3399c639d14eSFUJITA Tomonori 3400be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3401be4e11beSAkinobu Mita kaddr = miter.addr; 3402be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3403be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3404c639d14eSFUJITA Tomonori 3405be4e11beSAkinobu Mita offset += miter.length; 3406c639d14eSFUJITA Tomonori } 3407be4e11beSAkinobu Mita sg_miter_stop(&miter); 3408c639d14eSFUJITA Tomonori kfree(buf); 3409c639d14eSFUJITA Tomonori 3410be4e11beSAkinobu Mita return 0; 3411c639d14eSFUJITA Tomonori } 3412c639d14eSFUJITA Tomonori 3413c2248fc9SDouglas Gilbert static int 3414c2248fc9SDouglas Gilbert resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3415c2248fc9SDouglas Gilbert { 3416c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3417c2248fc9SDouglas Gilbert u64 lba; 3418c2248fc9SDouglas Gilbert u32 num; 3419c2248fc9SDouglas Gilbert int errsts; 3420c2248fc9SDouglas Gilbert 3421c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3422c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3423c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3424c2248fc9SDouglas Gilbert return check_condition_result; 3425c2248fc9SDouglas Gilbert } 3426c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3427c2248fc9SDouglas Gilbert if (errsts) 3428c2248fc9SDouglas Gilbert return errsts; 3429c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3430c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3431c2248fc9SDouglas Gilbert if (errsts) 3432c2248fc9SDouglas Gilbert return errsts; 3433c2248fc9SDouglas Gilbert } 3434c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3435c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3436c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3437c2248fc9SDouglas Gilbert } 3438c2248fc9SDouglas Gilbert 3439cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */ 3440cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx) 34411da177e4SLinus Torvalds { 3442cbf67842SDouglas Gilbert int qa_indx; 3443cbf67842SDouglas Gilbert int retiring = 0; 34441da177e4SLinus Torvalds unsigned long iflags; 3445cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3446cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3447cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 34481da177e4SLinus Torvalds 3449cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3450cbf67842SDouglas Gilbert qa_indx = indx; 3451cbf67842SDouglas Gilbert if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { 3452c1287970STomas Winkler pr_err("wild qa_indx=%d\n", qa_indx); 34531da177e4SLinus Torvalds return; 34541da177e4SLinus Torvalds } 34551da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3456cbf67842SDouglas Gilbert sqcp = &queued_arr[qa_indx]; 3457cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3458cbf67842SDouglas Gilbert if (NULL == scp) { 34591da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3460c1287970STomas Winkler pr_err("scp is NULL\n"); 34611da177e4SLinus Torvalds return; 34621da177e4SLinus Torvalds } 3463cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3464cbf67842SDouglas Gilbert if (devip) 3465cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3466cbf67842SDouglas Gilbert else 3467c1287970STomas Winkler pr_err("devip=NULL\n"); 3468cbf67842SDouglas Gilbert if (atomic_read(&retired_max_queue) > 0) 3469cbf67842SDouglas Gilbert retiring = 1; 3470cbf67842SDouglas Gilbert 3471cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3472cbf67842SDouglas Gilbert if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { 34731da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3474c1287970STomas Winkler pr_err("Unexpected completion\n"); 3475cbf67842SDouglas Gilbert return; 34761da177e4SLinus Torvalds } 34771da177e4SLinus Torvalds 3478cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3479cbf67842SDouglas Gilbert int k, retval; 3480cbf67842SDouglas Gilbert 3481cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3482cbf67842SDouglas Gilbert if (qa_indx >= retval) { 3483cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3484c1287970STomas Winkler pr_err("index %d too large\n", retval); 3485cbf67842SDouglas Gilbert return; 3486cbf67842SDouglas Gilbert } 3487cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, retval); 3488cbf67842SDouglas Gilbert if ((k < scsi_debug_max_queue) || (k == retval)) 3489cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3490cbf67842SDouglas Gilbert else 3491cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3492cbf67842SDouglas Gilbert } 3493cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3494cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3495cbf67842SDouglas Gilbert } 3496cbf67842SDouglas Gilbert 3497cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3498cbf67842SDouglas Gilbert static enum hrtimer_restart 3499cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3500cbf67842SDouglas Gilbert { 3501cbf67842SDouglas Gilbert int qa_indx; 3502cbf67842SDouglas Gilbert int retiring = 0; 3503cbf67842SDouglas Gilbert unsigned long iflags; 3504cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer; 3505cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3506cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3507cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3508cbf67842SDouglas Gilbert 3509cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3510cbf67842SDouglas Gilbert qa_indx = sd_hrtp->qa_indx; 3511cbf67842SDouglas Gilbert if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { 3512c1287970STomas Winkler pr_err("wild qa_indx=%d\n", qa_indx); 3513cbf67842SDouglas Gilbert goto the_end; 3514cbf67842SDouglas Gilbert } 3515cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 3516cbf67842SDouglas Gilbert sqcp = &queued_arr[qa_indx]; 3517cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3518cbf67842SDouglas Gilbert if (NULL == scp) { 3519cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3520c1287970STomas Winkler pr_err("scp is NULL\n"); 3521cbf67842SDouglas Gilbert goto the_end; 3522cbf67842SDouglas Gilbert } 3523cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3524cbf67842SDouglas Gilbert if (devip) 3525cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3526cbf67842SDouglas Gilbert else 3527c1287970STomas Winkler pr_err("devip=NULL\n"); 3528cbf67842SDouglas Gilbert if (atomic_read(&retired_max_queue) > 0) 3529cbf67842SDouglas Gilbert retiring = 1; 3530cbf67842SDouglas Gilbert 3531cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3532cbf67842SDouglas Gilbert if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { 3533cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3534c1287970STomas Winkler pr_err("Unexpected completion\n"); 3535cbf67842SDouglas Gilbert goto the_end; 3536cbf67842SDouglas Gilbert } 3537cbf67842SDouglas Gilbert 3538cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3539cbf67842SDouglas Gilbert int k, retval; 3540cbf67842SDouglas Gilbert 3541cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3542cbf67842SDouglas Gilbert if (qa_indx >= retval) { 3543cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3544c1287970STomas Winkler pr_err("index %d too large\n", retval); 3545cbf67842SDouglas Gilbert goto the_end; 3546cbf67842SDouglas Gilbert } 3547cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, retval); 3548cbf67842SDouglas Gilbert if ((k < scsi_debug_max_queue) || (k == retval)) 3549cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3550cbf67842SDouglas Gilbert else 3551cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3552cbf67842SDouglas Gilbert } 3553cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3554cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3555cbf67842SDouglas Gilbert the_end: 3556cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3557cbf67842SDouglas Gilbert } 35581da177e4SLinus Torvalds 35598dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 35608dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 35615cb2fc06SFUJITA Tomonori { 35625cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 35635cb2fc06SFUJITA Tomonori 35645cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 35655cb2fc06SFUJITA Tomonori if (devip) { 35665cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 35675cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 35685cb2fc06SFUJITA Tomonori } 35695cb2fc06SFUJITA Tomonori return devip; 35705cb2fc06SFUJITA Tomonori } 35715cb2fc06SFUJITA Tomonori 35721da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 35731da177e4SLinus Torvalds { 35741da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 35751da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 35761da177e4SLinus Torvalds struct sdebug_dev_info * devip = 35771da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 35781da177e4SLinus Torvalds 35791da177e4SLinus Torvalds if (devip) 35801da177e4SLinus Torvalds return devip; 3581d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 35821da177e4SLinus Torvalds if (!sdbg_host) { 3583c1287970STomas Winkler pr_err("Host info NULL\n"); 35841da177e4SLinus Torvalds return NULL; 35851da177e4SLinus Torvalds } 35861da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 35871da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 35881da177e4SLinus Torvalds (devip->target == sdev->id) && 35891da177e4SLinus Torvalds (devip->lun == sdev->lun)) 35901da177e4SLinus Torvalds return devip; 35911da177e4SLinus Torvalds else { 35921da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 35931da177e4SLinus Torvalds open_devip = devip; 35941da177e4SLinus Torvalds } 35951da177e4SLinus Torvalds } 35965cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 35975cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 35985cb2fc06SFUJITA Tomonori if (!open_devip) { 3599c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 36001da177e4SLinus Torvalds return NULL; 36011da177e4SLinus Torvalds } 36021da177e4SLinus Torvalds } 3603a75869d1SFUJITA Tomonori 36041da177e4SLinus Torvalds open_devip->channel = sdev->channel; 36051da177e4SLinus Torvalds open_devip->target = sdev->id; 36061da177e4SLinus Torvalds open_devip->lun = sdev->lun; 36071da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3608cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3609cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3610c2248fc9SDouglas Gilbert open_devip->used = true; 36111da177e4SLinus Torvalds return open_devip; 36121da177e4SLinus Torvalds } 36131da177e4SLinus Torvalds 36148dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 36151da177e4SLinus Torvalds { 36168dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3617c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 36188dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 361975ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 36208dea0d02SFUJITA Tomonori return 0; 36218dea0d02SFUJITA Tomonori } 36221da177e4SLinus Torvalds 36238dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 36248dea0d02SFUJITA Tomonori { 36258dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 3626a34c4e98SFUJITA Tomonori 36271da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3628c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 36298dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 36308dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 36318dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 36328dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 36338dea0d02SFUJITA Tomonori if (NULL == devip) 36348dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3635c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 36366bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 363778d4e5a0SDouglas Gilbert if (scsi_debug_no_uld) 363878d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 36398dea0d02SFUJITA Tomonori return 0; 36408dea0d02SFUJITA Tomonori } 36418dea0d02SFUJITA Tomonori 36428dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 36438dea0d02SFUJITA Tomonori { 36448dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 36458dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 36468dea0d02SFUJITA Tomonori 36478dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 3648c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 36498dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 36508dea0d02SFUJITA Tomonori if (devip) { 365125985edcSLucas De Marchi /* make this slot available for re-use */ 3652c2248fc9SDouglas Gilbert devip->used = false; 36538dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 36548dea0d02SFUJITA Tomonori } 36558dea0d02SFUJITA Tomonori } 36568dea0d02SFUJITA Tomonori 3657cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */ 36588dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 36598dea0d02SFUJITA Tomonori { 36608dea0d02SFUJITA Tomonori unsigned long iflags; 3661cbf67842SDouglas Gilbert int k, qmax, r_qmax; 36628dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3663cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 36648dea0d02SFUJITA Tomonori 36658dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3666cbf67842SDouglas Gilbert qmax = scsi_debug_max_queue; 3667cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3668cbf67842SDouglas Gilbert if (r_qmax > qmax) 3669cbf67842SDouglas Gilbert qmax = r_qmax; 3670cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3671cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 36728dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3673cbf67842SDouglas Gilbert if (cmnd == sqcp->a_cmnd) { 3674db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3675db525fceSDouglas Gilbert cmnd->device->hostdata; 3676db525fceSDouglas Gilbert if (devip) 3677db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3678db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3679db525fceSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, 3680db525fceSDouglas Gilbert iflags); 3681cbf67842SDouglas Gilbert if (scsi_debug_ndelay > 0) { 3682cbf67842SDouglas Gilbert if (sqcp->sd_hrtp) 3683cbf67842SDouglas Gilbert hrtimer_cancel( 3684cbf67842SDouglas Gilbert &sqcp->sd_hrtp->hrt); 3685cbf67842SDouglas Gilbert } else if (scsi_debug_delay > 0) { 3686cbf67842SDouglas Gilbert if (sqcp->cmnd_timerp) 3687cbf67842SDouglas Gilbert del_timer_sync( 3688cbf67842SDouglas Gilbert sqcp->cmnd_timerp); 3689cbf67842SDouglas Gilbert } else if (scsi_debug_delay < 0) { 3690cbf67842SDouglas Gilbert if (sqcp->tletp) 3691cbf67842SDouglas Gilbert tasklet_kill(sqcp->tletp); 3692cbf67842SDouglas Gilbert } 3693db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3694db525fceSDouglas Gilbert return 1; 36958dea0d02SFUJITA Tomonori } 36968dea0d02SFUJITA Tomonori } 3697cbf67842SDouglas Gilbert } 36988dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 3699db525fceSDouglas Gilbert return 0; 37008dea0d02SFUJITA Tomonori } 37018dea0d02SFUJITA Tomonori 3702cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */ 37038dea0d02SFUJITA Tomonori static void stop_all_queued(void) 37048dea0d02SFUJITA Tomonori { 37058dea0d02SFUJITA Tomonori unsigned long iflags; 37068dea0d02SFUJITA Tomonori int k; 37078dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3708cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 37098dea0d02SFUJITA Tomonori 37108dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3711cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3712cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 37138dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3714cbf67842SDouglas Gilbert if (sqcp->a_cmnd) { 3715db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3716db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3717db525fceSDouglas Gilbert if (devip) 3718db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3719db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3720db525fceSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, 3721db525fceSDouglas Gilbert iflags); 3722cbf67842SDouglas Gilbert if (scsi_debug_ndelay > 0) { 3723cbf67842SDouglas Gilbert if (sqcp->sd_hrtp) 3724cbf67842SDouglas Gilbert hrtimer_cancel( 3725cbf67842SDouglas Gilbert &sqcp->sd_hrtp->hrt); 3726cbf67842SDouglas Gilbert } else if (scsi_debug_delay > 0) { 3727cbf67842SDouglas Gilbert if (sqcp->cmnd_timerp) 3728cbf67842SDouglas Gilbert del_timer_sync( 3729cbf67842SDouglas Gilbert sqcp->cmnd_timerp); 3730cbf67842SDouglas Gilbert } else if (scsi_debug_delay < 0) { 3731cbf67842SDouglas Gilbert if (sqcp->tletp) 3732cbf67842SDouglas Gilbert tasklet_kill(sqcp->tletp); 3733cbf67842SDouglas Gilbert } 3734db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3735db525fceSDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 37368dea0d02SFUJITA Tomonori } 37378dea0d02SFUJITA Tomonori } 3738cbf67842SDouglas Gilbert } 3739cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3740cbf67842SDouglas Gilbert } 3741cbf67842SDouglas Gilbert 3742cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3743cbf67842SDouglas Gilbert static void free_all_queued(void) 3744cbf67842SDouglas Gilbert { 3745cbf67842SDouglas Gilbert unsigned long iflags; 3746cbf67842SDouglas Gilbert int k; 3747cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3748cbf67842SDouglas Gilbert 3749cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 3750cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3751cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 3752cbf67842SDouglas Gilbert kfree(sqcp->cmnd_timerp); 3753cbf67842SDouglas Gilbert sqcp->cmnd_timerp = NULL; 3754cbf67842SDouglas Gilbert kfree(sqcp->tletp); 3755cbf67842SDouglas Gilbert sqcp->tletp = NULL; 3756cbf67842SDouglas Gilbert kfree(sqcp->sd_hrtp); 3757cbf67842SDouglas Gilbert sqcp->sd_hrtp = NULL; 3758cbf67842SDouglas Gilbert } 37598dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 37601da177e4SLinus Torvalds } 37611da177e4SLinus Torvalds 37621da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 37631da177e4SLinus Torvalds { 37641da177e4SLinus Torvalds ++num_aborts; 3765cbf67842SDouglas Gilbert if (SCpnt) { 3766cbf67842SDouglas Gilbert if (SCpnt->device && 3767cbf67842SDouglas Gilbert (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)) 3768cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", 3769cbf67842SDouglas Gilbert __func__); 37701da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 3771cbf67842SDouglas Gilbert } 37721da177e4SLinus Torvalds return SUCCESS; 37731da177e4SLinus Torvalds } 37741da177e4SLinus Torvalds 37751da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 37761da177e4SLinus Torvalds { 37771da177e4SLinus Torvalds struct sdebug_dev_info * devip; 37781da177e4SLinus Torvalds 37791da177e4SLinus Torvalds ++num_dev_resets; 3780cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3781cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3782cbf67842SDouglas Gilbert 3783cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3784cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3785cbf67842SDouglas Gilbert devip = devInfoReg(sdp); 37861da177e4SLinus Torvalds if (devip) 3787cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 37881da177e4SLinus Torvalds } 37891da177e4SLinus Torvalds return SUCCESS; 37901da177e4SLinus Torvalds } 37911da177e4SLinus Torvalds 3792cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3793cbf67842SDouglas Gilbert { 3794cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3795cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3796cbf67842SDouglas Gilbert struct scsi_device *sdp; 3797cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3798cbf67842SDouglas Gilbert int k = 0; 3799cbf67842SDouglas Gilbert 3800cbf67842SDouglas Gilbert ++num_target_resets; 3801cbf67842SDouglas Gilbert if (!SCpnt) 3802cbf67842SDouglas Gilbert goto lie; 3803cbf67842SDouglas Gilbert sdp = SCpnt->device; 3804cbf67842SDouglas Gilbert if (!sdp) 3805cbf67842SDouglas Gilbert goto lie; 3806cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3807cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3808cbf67842SDouglas Gilbert hp = sdp->host; 3809cbf67842SDouglas Gilbert if (!hp) 3810cbf67842SDouglas Gilbert goto lie; 3811cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3812cbf67842SDouglas Gilbert if (sdbg_host) { 3813cbf67842SDouglas Gilbert list_for_each_entry(devip, 3814cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3815cbf67842SDouglas Gilbert dev_list) 3816cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3817cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3818cbf67842SDouglas Gilbert ++k; 3819cbf67842SDouglas Gilbert } 3820cbf67842SDouglas Gilbert } 3821cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3822cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3823cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3824cbf67842SDouglas Gilbert lie: 3825cbf67842SDouglas Gilbert return SUCCESS; 3826cbf67842SDouglas Gilbert } 3827cbf67842SDouglas Gilbert 38281da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 38291da177e4SLinus Torvalds { 38301da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3831cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 38321da177e4SLinus Torvalds struct scsi_device * sdp; 38331da177e4SLinus Torvalds struct Scsi_Host * hp; 3834cbf67842SDouglas Gilbert int k = 0; 38351da177e4SLinus Torvalds 38361da177e4SLinus Torvalds ++num_bus_resets; 3837cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3838cbf67842SDouglas Gilbert goto lie; 3839cbf67842SDouglas Gilbert sdp = SCpnt->device; 3840cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3841cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3842cbf67842SDouglas Gilbert hp = sdp->host; 3843cbf67842SDouglas Gilbert if (hp) { 3844d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 38451da177e4SLinus Torvalds if (sdbg_host) { 3846cbf67842SDouglas Gilbert list_for_each_entry(devip, 38471da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3848cbf67842SDouglas Gilbert dev_list) { 3849cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3850cbf67842SDouglas Gilbert ++k; 38511da177e4SLinus Torvalds } 38521da177e4SLinus Torvalds } 3853cbf67842SDouglas Gilbert } 3854cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3855cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3856cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3857cbf67842SDouglas Gilbert lie: 38581da177e4SLinus Torvalds return SUCCESS; 38591da177e4SLinus Torvalds } 38601da177e4SLinus Torvalds 38611da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 38621da177e4SLinus Torvalds { 38631da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3864cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3865cbf67842SDouglas Gilbert int k = 0; 38661da177e4SLinus Torvalds 38671da177e4SLinus Torvalds ++num_host_resets; 3868cbf67842SDouglas Gilbert if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)) 3869cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 38701da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 38711da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3872cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3873cbf67842SDouglas Gilbert dev_list) { 3874cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3875cbf67842SDouglas Gilbert ++k; 3876cbf67842SDouglas Gilbert } 38771da177e4SLinus Torvalds } 38781da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 38791da177e4SLinus Torvalds stop_all_queued(); 3880cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3881cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3882cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 38831da177e4SLinus Torvalds return SUCCESS; 38841da177e4SLinus Torvalds } 38851da177e4SLinus Torvalds 3886f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 38875f2578e5SFUJITA Tomonori unsigned long store_size) 38881da177e4SLinus Torvalds { 38891da177e4SLinus Torvalds struct partition * pp; 38901da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 38911da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 38921da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 38931da177e4SLinus Torvalds 38941da177e4SLinus Torvalds /* assume partition table already zeroed */ 3895f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 38961da177e4SLinus Torvalds return; 38971da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 38981da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 3899c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 39001da177e4SLinus Torvalds } 3901c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 39021da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 39031da177e4SLinus Torvalds / scsi_debug_num_parts; 39041da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 39051da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 39061da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 39071da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 39081da177e4SLinus Torvalds * heads_by_sects; 39091da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 39101da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 39111da177e4SLinus Torvalds 39121da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 39131da177e4SLinus Torvalds ramp[511] = 0xAA; 39141da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 39151da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 39161da177e4SLinus Torvalds start_sec = starts[k]; 39171da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 39181da177e4SLinus Torvalds pp->boot_ind = 0; 39191da177e4SLinus Torvalds 39201da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 39211da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 39221da177e4SLinus Torvalds / sdebug_sectors_per; 39231da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 39241da177e4SLinus Torvalds 39251da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 39261da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 39271da177e4SLinus Torvalds / sdebug_sectors_per; 39281da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 39291da177e4SLinus Torvalds 3930150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3931150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 39321da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 39331da177e4SLinus Torvalds } 39341da177e4SLinus Torvalds } 39351da177e4SLinus Torvalds 3936cbf67842SDouglas Gilbert static int 3937cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 3938cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 39391da177e4SLinus Torvalds { 3940cbf67842SDouglas Gilbert unsigned long iflags; 3941cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 3942cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp = NULL; 3943299b6c07STomas Winkler struct scsi_device *sdp; 39441da177e4SLinus Torvalds 3945299b6c07STomas Winkler /* this should never happen */ 3946299b6c07STomas Winkler if (WARN_ON(!cmnd)) 3947299b6c07STomas Winkler return SCSI_MLQUEUE_HOST_BUSY; 3948299b6c07STomas Winkler 3949299b6c07STomas Winkler if (NULL == devip) { 3950299b6c07STomas Winkler pr_warn("called devip == NULL\n"); 3951cbf67842SDouglas Gilbert /* no particularly good error to report back */ 3952cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 39531da177e4SLinus Torvalds } 3954299b6c07STomas Winkler 3955299b6c07STomas Winkler sdp = cmnd->device; 3956299b6c07STomas Winkler 3957cbf67842SDouglas Gilbert if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 3958cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 3959cbf67842SDouglas Gilbert __func__, scsi_result); 3960cd62b7daSDouglas Gilbert if (delta_jiff == 0) 3961cd62b7daSDouglas Gilbert goto respond_in_thread; 39621da177e4SLinus Torvalds 3963cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 39641da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3965cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 3966cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 3967cbf67842SDouglas Gilbert inject = 0; 3968cd62b7daSDouglas Gilbert if ((qdepth > 0) && (num_in_q >= qdepth)) { 3969cd62b7daSDouglas Gilbert if (scsi_result) { 3970cd62b7daSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3971cd62b7daSDouglas Gilbert goto respond_in_thread; 3972cd62b7daSDouglas Gilbert } else 3973cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3974cd62b7daSDouglas Gilbert } else if ((scsi_debug_every_nth != 0) && 3975cd62b7daSDouglas Gilbert (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) && 3976cd62b7daSDouglas Gilbert (scsi_result == 0)) { 3977cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 3978cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 3979cbf67842SDouglas Gilbert abs(scsi_debug_every_nth))) { 3980cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3981cbf67842SDouglas Gilbert inject = 1; 3982cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 39831da177e4SLinus Torvalds } 3984cbf67842SDouglas Gilbert } 3985cbf67842SDouglas Gilbert 3986cd62b7daSDouglas Gilbert k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue); 398778d4e5a0SDouglas Gilbert if (k >= scsi_debug_max_queue) { 39881da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3989cd62b7daSDouglas Gilbert if (scsi_result) 3990cd62b7daSDouglas Gilbert goto respond_in_thread; 3991cd62b7daSDouglas Gilbert else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts) 3992cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3993cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) 3994cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3995cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 3996cd62b7daSDouglas Gilbert __func__, scsi_debug_max_queue, 3997cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 3998cbf67842SDouglas Gilbert "report: host busy")); 3999cd62b7daSDouglas Gilbert if (scsi_result) 4000cd62b7daSDouglas Gilbert goto respond_in_thread; 4001cd62b7daSDouglas Gilbert else 4002cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 40031da177e4SLinus Torvalds } 4004cbf67842SDouglas Gilbert __set_bit(k, queued_in_use_bm); 4005cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4006cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 40071da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4008cbf67842SDouglas Gilbert cmnd->result = scsi_result; 40091da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 4010cbf67842SDouglas Gilbert if (delta_jiff > 0) { 4011cbf67842SDouglas Gilbert if (NULL == sqcp->cmnd_timerp) { 4012cbf67842SDouglas Gilbert sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list), 4013cbf67842SDouglas Gilbert GFP_ATOMIC); 4014cbf67842SDouglas Gilbert if (NULL == sqcp->cmnd_timerp) 4015cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4016cbf67842SDouglas Gilbert init_timer(sqcp->cmnd_timerp); 4017cbf67842SDouglas Gilbert } 4018cbf67842SDouglas Gilbert sqcp->cmnd_timerp->function = sdebug_q_cmd_complete; 4019cbf67842SDouglas Gilbert sqcp->cmnd_timerp->data = k; 4020cbf67842SDouglas Gilbert sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff; 4021cbf67842SDouglas Gilbert add_timer(sqcp->cmnd_timerp); 4022cbf67842SDouglas Gilbert } else if (scsi_debug_ndelay > 0) { 4023cbf67842SDouglas Gilbert ktime_t kt = ktime_set(0, scsi_debug_ndelay); 4024cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp; 4025cbf67842SDouglas Gilbert 4026cbf67842SDouglas Gilbert if (NULL == sd_hp) { 4027cbf67842SDouglas Gilbert sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC); 4028cbf67842SDouglas Gilbert if (NULL == sd_hp) 4029cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4030cbf67842SDouglas Gilbert sqcp->sd_hrtp = sd_hp; 4031cbf67842SDouglas Gilbert hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC, 4032cbf67842SDouglas Gilbert HRTIMER_MODE_REL); 4033cbf67842SDouglas Gilbert sd_hp->hrt.function = sdebug_q_cmd_hrt_complete; 4034cbf67842SDouglas Gilbert sd_hp->qa_indx = k; 4035cbf67842SDouglas Gilbert } 4036cbf67842SDouglas Gilbert hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL); 4037cbf67842SDouglas Gilbert } else { /* delay < 0 */ 4038cbf67842SDouglas Gilbert if (NULL == sqcp->tletp) { 4039cbf67842SDouglas Gilbert sqcp->tletp = kmalloc(sizeof(*sqcp->tletp), 4040cbf67842SDouglas Gilbert GFP_ATOMIC); 4041cbf67842SDouglas Gilbert if (NULL == sqcp->tletp) 4042cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4043cbf67842SDouglas Gilbert tasklet_init(sqcp->tletp, 4044cbf67842SDouglas Gilbert sdebug_q_cmd_complete, k); 4045cbf67842SDouglas Gilbert } 4046cbf67842SDouglas Gilbert if (-1 == delta_jiff) 4047cbf67842SDouglas Gilbert tasklet_hi_schedule(sqcp->tletp); 4048cbf67842SDouglas Gilbert else 4049cbf67842SDouglas Gilbert tasklet_schedule(sqcp->tletp); 4050cbf67842SDouglas Gilbert } 4051cd62b7daSDouglas Gilbert if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) && 4052cd62b7daSDouglas Gilbert (scsi_result == device_qfull_result)) 4053cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4054cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4055cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4056cbf67842SDouglas Gilbert "status: TASK SET FULL"); 40571da177e4SLinus Torvalds return 0; 4058cd62b7daSDouglas Gilbert 4059cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4060cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4061cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4062cd62b7daSDouglas Gilbert return 0; 40631da177e4SLinus Torvalds } 4064cbf67842SDouglas Gilbert 406523183910SDouglas Gilbert /* Note: The following macros create attribute files in the 406623183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 406723183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 406823183910SDouglas Gilbert as it can when the corresponding attribute in the 406923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 407023183910SDouglas Gilbert */ 4071c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 40725b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO); 40730759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR); 4074c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 4075c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 40765b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO); 40775b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO); 4078c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 4079c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 408023183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 408168aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO); 4082cbf67842SDouglas Gilbert module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR); 40835b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); 40845b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); 40855b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); 4086be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); 40875b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); 4088c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 408978d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); 4090cbf67842SDouglas Gilbert module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR); 4091c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 409278d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); 4093c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 4094c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 40955b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); 4096c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 40975b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); 4098c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 4099d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR); 4100c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 41015b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 4102c2248fc9SDouglas Gilbert module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR); 41035b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); 41045b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); 41055b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); 41065b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); 4107c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 410823183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 410923183910SDouglas Gilbert S_IRUGO | S_IWUSR); 41105b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int, 41115b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 41121da177e4SLinus Torvalds 41131da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 41141da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 41151da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 41161da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 41171da177e4SLinus Torvalds 41181da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 41195b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 41200759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4121cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4122c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 41235b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 41245b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4125c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4126beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 412723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 41285b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4129cbf67842SDouglas Gilbert MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)"); 41305b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 41315b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 41325b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4133be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); 41345b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4135c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4136cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4137cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4138c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 413978d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 41401da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4141c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 41425b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); 41436f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 41445b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 41451da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4146d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4147e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])"); 4148ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4149c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 41505b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 41515b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 41526014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 41536014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 4154c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 41555b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 41565b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 41571da177e4SLinus Torvalds 41581da177e4SLinus Torvalds static char sdebug_info[256]; 41591da177e4SLinus Torvalds 41601da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 41611da177e4SLinus Torvalds { 41621da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 41631da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 41641da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 41651da177e4SLinus Torvalds scsi_debug_opts); 41661da177e4SLinus Torvalds return sdebug_info; 41671da177e4SLinus Torvalds } 41681da177e4SLinus Torvalds 4169cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4170c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length) 41711da177e4SLinus Torvalds { 41721da177e4SLinus Torvalds char arr[16]; 4173c8ed555aSAl Viro int opts; 41741da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 41751da177e4SLinus Torvalds 41761da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 41771da177e4SLinus Torvalds return -EACCES; 41781da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 41791da177e4SLinus Torvalds arr[minLen] = '\0'; 4180c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 41811da177e4SLinus Torvalds return -EINVAL; 4182c8ed555aSAl Viro scsi_debug_opts = opts; 41831da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 4184cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 41851da177e4SLinus Torvalds return length; 41861da177e4SLinus Torvalds } 4187c8ed555aSAl Viro 4188cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4189cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4190cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4191c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4192c8ed555aSAl Viro { 4193cbf67842SDouglas Gilbert int f, l; 4194cbf67842SDouglas Gilbert char b[32]; 4195cbf67842SDouglas Gilbert 4196cbf67842SDouglas Gilbert if (scsi_debug_every_nth > 0) 4197cbf67842SDouglas Gilbert snprintf(b, sizeof(b), " (curr:%d)", 4198cbf67842SDouglas Gilbert ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ? 4199cbf67842SDouglas Gilbert atomic_read(&sdebug_a_tsf) : 4200cbf67842SDouglas Gilbert atomic_read(&sdebug_cmnd_count))); 4201cbf67842SDouglas Gilbert else 4202cbf67842SDouglas Gilbert b[0] = '\0'; 4203cbf67842SDouglas Gilbert 4204cbf67842SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n" 42051da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 4206cbf67842SDouglas Gilbert "every_nth=%d%s\n" 4207cbf67842SDouglas Gilbert "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n" 42081da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 4209cbf67842SDouglas Gilbert "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, " 4210cbf67842SDouglas Gilbert "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d " 4211cbf67842SDouglas Gilbert "usec_in_jiffy=%lu\n", 4212cbf67842SDouglas Gilbert SCSI_DEBUG_VERSION, scsi_debug_version_date, 4213cbf67842SDouglas Gilbert scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts, 4214cbf67842SDouglas Gilbert scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay, 4215cbf67842SDouglas Gilbert scsi_debug_max_luns, atomic_read(&sdebug_completions), 4216597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 4217cbf67842SDouglas Gilbert sdebug_sectors_per, num_aborts, num_dev_resets, 4218cbf67842SDouglas Gilbert num_target_resets, num_bus_resets, num_host_resets, 4219cbf67842SDouglas Gilbert dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000); 4220cbf67842SDouglas Gilbert 4221cbf67842SDouglas Gilbert f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue); 4222cbf67842SDouglas Gilbert if (f != scsi_debug_max_queue) { 4223cbf67842SDouglas Gilbert l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue); 4224cbf67842SDouglas Gilbert seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n", 4225cbf67842SDouglas Gilbert "queued_in_use_bm", f, l); 4226cbf67842SDouglas Gilbert } 4227c8ed555aSAl Viro return 0; 42281da177e4SLinus Torvalds } 42291da177e4SLinus Torvalds 423082069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 42311da177e4SLinus Torvalds { 42321da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 42331da177e4SLinus Torvalds } 4234cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */ 423582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 423682069379SAkinobu Mita size_t count) 42371da177e4SLinus Torvalds { 4238cbf67842SDouglas Gilbert int delay, res; 42391da177e4SLinus Torvalds 4240cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) { 4241cbf67842SDouglas Gilbert res = count; 4242cbf67842SDouglas Gilbert if (scsi_debug_delay != delay) { 4243cbf67842SDouglas Gilbert unsigned long iflags; 4244cbf67842SDouglas Gilbert int k; 4245cbf67842SDouglas Gilbert 4246cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4247cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4248cbf67842SDouglas Gilbert scsi_debug_max_queue); 4249cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4250cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4251cbf67842SDouglas Gilbert else { 42521da177e4SLinus Torvalds scsi_debug_delay = delay; 4253cbf67842SDouglas Gilbert scsi_debug_ndelay = 0; 42541da177e4SLinus Torvalds } 4255cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4256cbf67842SDouglas Gilbert } 4257cbf67842SDouglas Gilbert return res; 42581da177e4SLinus Torvalds } 42591da177e4SLinus Torvalds return -EINVAL; 42601da177e4SLinus Torvalds } 426182069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 42621da177e4SLinus Torvalds 4263cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4264cbf67842SDouglas Gilbert { 4265cbf67842SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay); 4266cbf67842SDouglas Gilbert } 4267cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4268cbf67842SDouglas Gilbert /* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */ 4269cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4270cbf67842SDouglas Gilbert size_t count) 4271cbf67842SDouglas Gilbert { 4272cbf67842SDouglas Gilbert unsigned long iflags; 4273cbf67842SDouglas Gilbert int ndelay, res, k; 4274cbf67842SDouglas Gilbert 4275cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4276cbf67842SDouglas Gilbert (ndelay >= 0) && (ndelay < 1000000000)) { 4277cbf67842SDouglas Gilbert res = count; 4278cbf67842SDouglas Gilbert if (scsi_debug_ndelay != ndelay) { 4279cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4280cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4281cbf67842SDouglas Gilbert scsi_debug_max_queue); 4282cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4283cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4284cbf67842SDouglas Gilbert else { 4285cbf67842SDouglas Gilbert scsi_debug_ndelay = ndelay; 4286cbf67842SDouglas Gilbert scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN 4287cbf67842SDouglas Gilbert : DEF_DELAY; 4288cbf67842SDouglas Gilbert } 4289cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4290cbf67842SDouglas Gilbert } 4291cbf67842SDouglas Gilbert return res; 4292cbf67842SDouglas Gilbert } 4293cbf67842SDouglas Gilbert return -EINVAL; 4294cbf67842SDouglas Gilbert } 4295cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4296cbf67842SDouglas Gilbert 429782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 42981da177e4SLinus Torvalds { 42991da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 43001da177e4SLinus Torvalds } 43011da177e4SLinus Torvalds 430282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 430382069379SAkinobu Mita size_t count) 43041da177e4SLinus Torvalds { 43051da177e4SLinus Torvalds int opts; 43061da177e4SLinus Torvalds char work[20]; 43071da177e4SLinus Torvalds 43081da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 430948a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 43101da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 43111da177e4SLinus Torvalds goto opts_done; 43121da177e4SLinus Torvalds } else { 43131da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 43141da177e4SLinus Torvalds goto opts_done; 43151da177e4SLinus Torvalds } 43161da177e4SLinus Torvalds } 43171da177e4SLinus Torvalds return -EINVAL; 43181da177e4SLinus Torvalds opts_done: 43191da177e4SLinus Torvalds scsi_debug_opts = opts; 4320817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 4321817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4322817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 4323817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4324817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 4325817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4326817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 4327817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4328817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 4329817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4330cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4331cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 43321da177e4SLinus Torvalds return count; 43331da177e4SLinus Torvalds } 433482069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 43351da177e4SLinus Torvalds 433682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 43371da177e4SLinus Torvalds { 43381da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 43391da177e4SLinus Torvalds } 434082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 434182069379SAkinobu Mita size_t count) 43421da177e4SLinus Torvalds { 43431da177e4SLinus Torvalds int n; 43441da177e4SLinus Torvalds 43451da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 43461da177e4SLinus Torvalds scsi_debug_ptype = n; 43471da177e4SLinus Torvalds return count; 43481da177e4SLinus Torvalds } 43491da177e4SLinus Torvalds return -EINVAL; 43501da177e4SLinus Torvalds } 435182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 43521da177e4SLinus Torvalds 435382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 43541da177e4SLinus Torvalds { 43551da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 43561da177e4SLinus Torvalds } 435782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 435882069379SAkinobu Mita size_t count) 43591da177e4SLinus Torvalds { 43601da177e4SLinus Torvalds int n; 43611da177e4SLinus Torvalds 43621da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 43631da177e4SLinus Torvalds scsi_debug_dsense = n; 43641da177e4SLinus Torvalds return count; 43651da177e4SLinus Torvalds } 43661da177e4SLinus Torvalds return -EINVAL; 43671da177e4SLinus Torvalds } 436882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 43691da177e4SLinus Torvalds 437082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 437123183910SDouglas Gilbert { 437223183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 437323183910SDouglas Gilbert } 437482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 437582069379SAkinobu Mita size_t count) 437623183910SDouglas Gilbert { 437723183910SDouglas Gilbert int n; 437823183910SDouglas Gilbert 437923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4380cbf67842SDouglas Gilbert n = (n > 0); 4381cbf67842SDouglas Gilbert scsi_debug_fake_rw = (scsi_debug_fake_rw > 0); 4382cbf67842SDouglas Gilbert if (scsi_debug_fake_rw != n) { 4383cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4384cbf67842SDouglas Gilbert unsigned long sz = 4385cbf67842SDouglas Gilbert (unsigned long)scsi_debug_dev_size_mb * 4386cbf67842SDouglas Gilbert 1048576; 4387cbf67842SDouglas Gilbert 4388cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4389cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4390c1287970STomas Winkler pr_err("out of memory, 9\n"); 4391cbf67842SDouglas Gilbert return -ENOMEM; 4392cbf67842SDouglas Gilbert } 4393cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4394cbf67842SDouglas Gilbert } 439523183910SDouglas Gilbert scsi_debug_fake_rw = n; 4396cbf67842SDouglas Gilbert } 439723183910SDouglas Gilbert return count; 439823183910SDouglas Gilbert } 439923183910SDouglas Gilbert return -EINVAL; 440023183910SDouglas Gilbert } 440182069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 440223183910SDouglas Gilbert 440382069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4404c65b1445SDouglas Gilbert { 4405c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 4406c65b1445SDouglas Gilbert } 440782069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 440882069379SAkinobu Mita size_t count) 4409c65b1445SDouglas Gilbert { 4410c65b1445SDouglas Gilbert int n; 4411c65b1445SDouglas Gilbert 4412c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4413c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 4414c65b1445SDouglas Gilbert return count; 4415c65b1445SDouglas Gilbert } 4416c65b1445SDouglas Gilbert return -EINVAL; 4417c65b1445SDouglas Gilbert } 441882069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4419c65b1445SDouglas Gilbert 442082069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 44211da177e4SLinus Torvalds { 44221da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 44231da177e4SLinus Torvalds } 442482069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 442582069379SAkinobu Mita size_t count) 44261da177e4SLinus Torvalds { 44271da177e4SLinus Torvalds int n; 44281da177e4SLinus Torvalds 44291da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 44301da177e4SLinus Torvalds scsi_debug_num_tgts = n; 44311da177e4SLinus Torvalds sdebug_max_tgts_luns(); 44321da177e4SLinus Torvalds return count; 44331da177e4SLinus Torvalds } 44341da177e4SLinus Torvalds return -EINVAL; 44351da177e4SLinus Torvalds } 443682069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 44371da177e4SLinus Torvalds 443882069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 44391da177e4SLinus Torvalds { 44401da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 44411da177e4SLinus Torvalds } 444282069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 44431da177e4SLinus Torvalds 444482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 44451da177e4SLinus Torvalds { 44461da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 44471da177e4SLinus Torvalds } 444882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 44491da177e4SLinus Torvalds 445082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 44511da177e4SLinus Torvalds { 44521da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 44531da177e4SLinus Torvalds } 445482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 445582069379SAkinobu Mita size_t count) 44561da177e4SLinus Torvalds { 44571da177e4SLinus Torvalds int nth; 44581da177e4SLinus Torvalds 44591da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 44601da177e4SLinus Torvalds scsi_debug_every_nth = nth; 4461cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 44621da177e4SLinus Torvalds return count; 44631da177e4SLinus Torvalds } 44641da177e4SLinus Torvalds return -EINVAL; 44651da177e4SLinus Torvalds } 446682069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 44671da177e4SLinus Torvalds 446882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 44691da177e4SLinus Torvalds { 44701da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 44711da177e4SLinus Torvalds } 447282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 447382069379SAkinobu Mita size_t count) 44741da177e4SLinus Torvalds { 44751da177e4SLinus Torvalds int n; 447619c8ead7SEwan D. Milne bool changed; 44771da177e4SLinus Torvalds 44781da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 447919c8ead7SEwan D. Milne changed = (scsi_debug_max_luns != n); 44801da177e4SLinus Torvalds scsi_debug_max_luns = n; 44811da177e4SLinus Torvalds sdebug_max_tgts_luns(); 448219c8ead7SEwan D. Milne if (changed && (scsi_debug_scsi_level >= 5)) { /* >= SPC-3 */ 448319c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 448419c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 448519c8ead7SEwan D. Milne 448619c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 448719c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 448819c8ead7SEwan D. Milne host_list) { 448919c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 449019c8ead7SEwan D. Milne dev_list) { 449119c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 449219c8ead7SEwan D. Milne dp->uas_bm); 449319c8ead7SEwan D. Milne } 449419c8ead7SEwan D. Milne } 449519c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 449619c8ead7SEwan D. Milne } 44971da177e4SLinus Torvalds return count; 44981da177e4SLinus Torvalds } 44991da177e4SLinus Torvalds return -EINVAL; 45001da177e4SLinus Torvalds } 450182069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 45021da177e4SLinus Torvalds 450382069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 450478d4e5a0SDouglas Gilbert { 450578d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); 450678d4e5a0SDouglas Gilbert } 4507cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4508cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 450982069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 451082069379SAkinobu Mita size_t count) 451178d4e5a0SDouglas Gilbert { 4512cbf67842SDouglas Gilbert unsigned long iflags; 4513cbf67842SDouglas Gilbert int n, k; 451478d4e5a0SDouglas Gilbert 451578d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 451678d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 4517cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4518cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE); 451978d4e5a0SDouglas Gilbert scsi_debug_max_queue = n; 4520cbf67842SDouglas Gilbert if (SCSI_DEBUG_CANQUEUE == k) 4521cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4522cbf67842SDouglas Gilbert else if (k >= n) 4523cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4524cbf67842SDouglas Gilbert else 4525cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4526cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 452778d4e5a0SDouglas Gilbert return count; 452878d4e5a0SDouglas Gilbert } 452978d4e5a0SDouglas Gilbert return -EINVAL; 453078d4e5a0SDouglas Gilbert } 453182069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 453278d4e5a0SDouglas Gilbert 453382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 453478d4e5a0SDouglas Gilbert { 453578d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); 453678d4e5a0SDouglas Gilbert } 453782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 453878d4e5a0SDouglas Gilbert 453982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 45401da177e4SLinus Torvalds { 45411da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 45421da177e4SLinus Torvalds } 454382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 45441da177e4SLinus Torvalds 454582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4546c65b1445SDouglas Gilbert { 4547c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 4548c65b1445SDouglas Gilbert } 454982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 455082069379SAkinobu Mita size_t count) 4551c65b1445SDouglas Gilbert { 4552c65b1445SDouglas Gilbert int n; 45530d01c5dfSDouglas Gilbert bool changed; 4554c65b1445SDouglas Gilbert 4555c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 45560d01c5dfSDouglas Gilbert changed = (scsi_debug_virtual_gb != n); 4557c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 455828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 45590d01c5dfSDouglas Gilbert if (changed) { 45600d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 45610d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 456228898873SFUJITA Tomonori 45634bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 45640d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 45650d01c5dfSDouglas Gilbert host_list) { 45660d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 45670d01c5dfSDouglas Gilbert dev_list) { 45680d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 45690d01c5dfSDouglas Gilbert dp->uas_bm); 45700d01c5dfSDouglas Gilbert } 45710d01c5dfSDouglas Gilbert } 45724bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 45730d01c5dfSDouglas Gilbert } 4574c65b1445SDouglas Gilbert return count; 4575c65b1445SDouglas Gilbert } 4576c65b1445SDouglas Gilbert return -EINVAL; 4577c65b1445SDouglas Gilbert } 457882069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4579c65b1445SDouglas Gilbert 458082069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 45811da177e4SLinus Torvalds { 45821da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 45831da177e4SLinus Torvalds } 45841da177e4SLinus Torvalds 458582069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 458682069379SAkinobu Mita size_t count) 45871da177e4SLinus Torvalds { 45881da177e4SLinus Torvalds int delta_hosts; 45891da177e4SLinus Torvalds 4590f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 45911da177e4SLinus Torvalds return -EINVAL; 45921da177e4SLinus Torvalds if (delta_hosts > 0) { 45931da177e4SLinus Torvalds do { 45941da177e4SLinus Torvalds sdebug_add_adapter(); 45951da177e4SLinus Torvalds } while (--delta_hosts); 45961da177e4SLinus Torvalds } else if (delta_hosts < 0) { 45971da177e4SLinus Torvalds do { 45981da177e4SLinus Torvalds sdebug_remove_adapter(); 45991da177e4SLinus Torvalds } while (++delta_hosts); 46001da177e4SLinus Torvalds } 46011da177e4SLinus Torvalds return count; 46021da177e4SLinus Torvalds } 460382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 46041da177e4SLinus Torvalds 460582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 460623183910SDouglas Gilbert { 460723183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 460823183910SDouglas Gilbert } 460982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 461082069379SAkinobu Mita size_t count) 461123183910SDouglas Gilbert { 461223183910SDouglas Gilbert int n; 461323183910SDouglas Gilbert 461423183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 461523183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 461623183910SDouglas Gilbert return count; 461723183910SDouglas Gilbert } 461823183910SDouglas Gilbert return -EINVAL; 461923183910SDouglas Gilbert } 462082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 462123183910SDouglas Gilbert 462282069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4623597136abSMartin K. Petersen { 4624597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 4625597136abSMartin K. Petersen } 462682069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4627597136abSMartin K. Petersen 462882069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4629c6a44287SMartin K. Petersen { 4630c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); 4631c6a44287SMartin K. Petersen } 463282069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4633c6a44287SMartin K. Petersen 463482069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4635c6a44287SMartin K. Petersen { 4636c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); 4637c6a44287SMartin K. Petersen } 463882069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4639c6a44287SMartin K. Petersen 464082069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4641c6a44287SMartin K. Petersen { 464268aee7baSAkinobu Mita return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard); 4643c6a44287SMartin K. Petersen } 464482069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4645c6a44287SMartin K. Petersen 464682069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4647c6a44287SMartin K. Petersen { 4648c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); 4649c6a44287SMartin K. Petersen } 465082069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4651c6a44287SMartin K. Petersen 465282069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 465344d92694SMartin K. Petersen { 465444d92694SMartin K. Petersen ssize_t count; 465544d92694SMartin K. Petersen 46565b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 465744d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 465844d92694SMartin K. Petersen sdebug_store_sectors); 465944d92694SMartin K. Petersen 4660c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4661c7badc90STejun Heo (int)map_size, map_storep); 466244d92694SMartin K. Petersen buf[count++] = '\n'; 4663c7badc90STejun Heo buf[count] = '\0'; 466444d92694SMartin K. Petersen 466544d92694SMartin K. Petersen return count; 466644d92694SMartin K. Petersen } 466782069379SAkinobu Mita static DRIVER_ATTR_RO(map); 466844d92694SMartin K. Petersen 466982069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4670d986788bSMartin Pitt { 4671d986788bSMartin Pitt return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0); 4672d986788bSMartin Pitt } 467382069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 467482069379SAkinobu Mita size_t count) 4675d986788bSMartin Pitt { 4676d986788bSMartin Pitt int n; 4677d986788bSMartin Pitt 4678d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4679d986788bSMartin Pitt scsi_debug_removable = (n > 0); 4680d986788bSMartin Pitt return count; 4681d986788bSMartin Pitt } 4682d986788bSMartin Pitt return -EINVAL; 4683d986788bSMartin Pitt } 468482069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4685d986788bSMartin Pitt 4686cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4687cbf67842SDouglas Gilbert { 4688cbf67842SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock); 4689cbf67842SDouglas Gilbert } 4690cbf67842SDouglas Gilbert /* Returns -EBUSY if host_lock is being changed and commands are queued */ 4691cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4692cbf67842SDouglas Gilbert size_t count) 4693cbf67842SDouglas Gilbert { 4694cbf67842SDouglas Gilbert int n, res; 4695cbf67842SDouglas Gilbert 4696cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4697cbf67842SDouglas Gilbert bool new_host_lock = (n > 0); 4698cbf67842SDouglas Gilbert 4699cbf67842SDouglas Gilbert res = count; 4700cbf67842SDouglas Gilbert if (new_host_lock != scsi_debug_host_lock) { 4701cbf67842SDouglas Gilbert unsigned long iflags; 4702cbf67842SDouglas Gilbert int k; 4703cbf67842SDouglas Gilbert 4704cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4705cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4706cbf67842SDouglas Gilbert scsi_debug_max_queue); 4707cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4708cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4709cbf67842SDouglas Gilbert else 4710cbf67842SDouglas Gilbert scsi_debug_host_lock = new_host_lock; 4711cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4712cbf67842SDouglas Gilbert } 4713cbf67842SDouglas Gilbert return res; 4714cbf67842SDouglas Gilbert } 4715cbf67842SDouglas Gilbert return -EINVAL; 4716cbf67842SDouglas Gilbert } 4717cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4718cbf67842SDouglas Gilbert 4719c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4720c2248fc9SDouglas Gilbert { 4721c2248fc9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict); 4722c2248fc9SDouglas Gilbert } 4723c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4724c2248fc9SDouglas Gilbert size_t count) 4725c2248fc9SDouglas Gilbert { 4726c2248fc9SDouglas Gilbert int n; 4727c2248fc9SDouglas Gilbert 4728c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4729c2248fc9SDouglas Gilbert scsi_debug_strict = (n > 0); 4730c2248fc9SDouglas Gilbert return count; 4731c2248fc9SDouglas Gilbert } 4732c2248fc9SDouglas Gilbert return -EINVAL; 4733c2248fc9SDouglas Gilbert } 4734c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4735c2248fc9SDouglas Gilbert 4736cbf67842SDouglas Gilbert 473782069379SAkinobu Mita /* Note: The following array creates attribute files in the 473823183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 473923183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 474023183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 474123183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 474223183910SDouglas Gilbert */ 47436ecaff7fSRandy Dunlap 474482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 474582069379SAkinobu Mita &driver_attr_delay.attr, 474682069379SAkinobu Mita &driver_attr_opts.attr, 474782069379SAkinobu Mita &driver_attr_ptype.attr, 474882069379SAkinobu Mita &driver_attr_dsense.attr, 474982069379SAkinobu Mita &driver_attr_fake_rw.attr, 475082069379SAkinobu Mita &driver_attr_no_lun_0.attr, 475182069379SAkinobu Mita &driver_attr_num_tgts.attr, 475282069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 475382069379SAkinobu Mita &driver_attr_num_parts.attr, 475482069379SAkinobu Mita &driver_attr_every_nth.attr, 475582069379SAkinobu Mita &driver_attr_max_luns.attr, 475682069379SAkinobu Mita &driver_attr_max_queue.attr, 475782069379SAkinobu Mita &driver_attr_no_uld.attr, 475882069379SAkinobu Mita &driver_attr_scsi_level.attr, 475982069379SAkinobu Mita &driver_attr_virtual_gb.attr, 476082069379SAkinobu Mita &driver_attr_add_host.attr, 476182069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 476282069379SAkinobu Mita &driver_attr_sector_size.attr, 476382069379SAkinobu Mita &driver_attr_dix.attr, 476482069379SAkinobu Mita &driver_attr_dif.attr, 476582069379SAkinobu Mita &driver_attr_guard.attr, 476682069379SAkinobu Mita &driver_attr_ato.attr, 476782069379SAkinobu Mita &driver_attr_map.attr, 476882069379SAkinobu Mita &driver_attr_removable.attr, 4769cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4770cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4771c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 477282069379SAkinobu Mita NULL, 477382069379SAkinobu Mita }; 477482069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 47751da177e4SLinus Torvalds 477611ddcecaSAkinobu Mita static struct device *pseudo_primary; 47778dea0d02SFUJITA Tomonori 47781da177e4SLinus Torvalds static int __init scsi_debug_init(void) 47791da177e4SLinus Torvalds { 47805f2578e5SFUJITA Tomonori unsigned long sz; 47811da177e4SLinus Torvalds int host_to_add; 47821da177e4SLinus Torvalds int k; 47836ecaff7fSRandy Dunlap int ret; 47841da177e4SLinus Torvalds 4785cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4786cbf67842SDouglas Gilbert atomic_set(&sdebug_completions, 0); 4787cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4788cbf67842SDouglas Gilbert 4789cbf67842SDouglas Gilbert if (scsi_debug_ndelay >= 1000000000) { 4790c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 4791cbf67842SDouglas Gilbert scsi_debug_ndelay = 0; 4792cbf67842SDouglas Gilbert } else if (scsi_debug_ndelay > 0) 4793cbf67842SDouglas Gilbert scsi_debug_delay = DELAY_OVERRIDDEN; 4794cbf67842SDouglas Gilbert 4795597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 4796597136abSMartin K. Petersen case 512: 4797597136abSMartin K. Petersen case 1024: 4798597136abSMartin K. Petersen case 2048: 4799597136abSMartin K. Petersen case 4096: 4800597136abSMartin K. Petersen break; 4801597136abSMartin K. Petersen default: 4802c1287970STomas Winkler pr_err("invalid sector_size %d\n", scsi_debug_sector_size); 4803597136abSMartin K. Petersen return -EINVAL; 4804597136abSMartin K. Petersen } 4805597136abSMartin K. Petersen 4806c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 4807c6a44287SMartin K. Petersen 4808c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 4809c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4810395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4811c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4812c6a44287SMartin K. Petersen break; 4813c6a44287SMartin K. Petersen 4814c6a44287SMartin K. Petersen default: 4815c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 4816c6a44287SMartin K. Petersen return -EINVAL; 4817c6a44287SMartin K. Petersen } 4818c6a44287SMartin K. Petersen 4819c6a44287SMartin K. Petersen if (scsi_debug_guard > 1) { 4820c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 4821c6a44287SMartin K. Petersen return -EINVAL; 4822c6a44287SMartin K. Petersen } 4823c6a44287SMartin K. Petersen 4824c6a44287SMartin K. Petersen if (scsi_debug_ato > 1) { 4825c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 4826c6a44287SMartin K. Petersen return -EINVAL; 4827c6a44287SMartin K. Petersen } 4828c6a44287SMartin K. Petersen 4829ea61fca5SMartin K. Petersen if (scsi_debug_physblk_exp > 15) { 4830c1287970STomas Winkler pr_err("invalid physblk_exp %u\n", scsi_debug_physblk_exp); 4831ea61fca5SMartin K. Petersen return -EINVAL; 4832ea61fca5SMartin K. Petersen } 4833ea61fca5SMartin K. Petersen 4834ea61fca5SMartin K. Petersen if (scsi_debug_lowest_aligned > 0x3fff) { 4835c1287970STomas Winkler pr_err("lowest_aligned too big: %u\n", 4836ea61fca5SMartin K. Petersen scsi_debug_lowest_aligned); 4837ea61fca5SMartin K. Petersen return -EINVAL; 4838ea61fca5SMartin K. Petersen } 4839ea61fca5SMartin K. Petersen 48401da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 48411da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 48425f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 4843597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 484428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 48451da177e4SLinus Torvalds 48461da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 48471da177e4SLinus Torvalds sdebug_heads = 8; 48481da177e4SLinus Torvalds sdebug_sectors_per = 32; 4849fa785f0aSAndy Shevchenko if (scsi_debug_dev_size_mb >= 256) 48501da177e4SLinus Torvalds sdebug_heads = 64; 4851fa785f0aSAndy Shevchenko else if (scsi_debug_dev_size_mb >= 16) 4852fa785f0aSAndy Shevchenko sdebug_heads = 32; 48531da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 48541da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 48551da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 48561da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 48571da177e4SLinus Torvalds sdebug_heads = 255; 48581da177e4SLinus Torvalds sdebug_sectors_per = 63; 48591da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 48601da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 48611da177e4SLinus Torvalds } 48621da177e4SLinus Torvalds 4863cbf67842SDouglas Gilbert if (0 == scsi_debug_fake_rw) { 48641da177e4SLinus Torvalds fake_storep = vmalloc(sz); 48651da177e4SLinus Torvalds if (NULL == fake_storep) { 4866c1287970STomas Winkler pr_err("out of memory, 1\n"); 48671da177e4SLinus Torvalds return -ENOMEM; 48681da177e4SLinus Torvalds } 48691da177e4SLinus Torvalds memset(fake_storep, 0, sz); 48701da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 4871f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 4872cbf67842SDouglas Gilbert } 48731da177e4SLinus Torvalds 48747cb69d03SAkinobu Mita if (scsi_debug_dix) { 4875c6a44287SMartin K. Petersen int dif_size; 4876c6a44287SMartin K. Petersen 4877c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 4878c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 4879c6a44287SMartin K. Petersen 4880c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 4881c6a44287SMartin K. Petersen 4882c6a44287SMartin K. Petersen if (dif_storep == NULL) { 4883c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 4884c6a44287SMartin K. Petersen ret = -ENOMEM; 4885c6a44287SMartin K. Petersen goto free_vm; 4886c6a44287SMartin K. Petersen } 4887c6a44287SMartin K. Petersen 4888c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 4889c6a44287SMartin K. Petersen } 4890c6a44287SMartin K. Petersen 48915b94e232SMartin K. Petersen /* Logical Block Provisioning */ 48925b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 48936014759cSMartin K. Petersen scsi_debug_unmap_max_blocks = 48946014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); 48956014759cSMartin K. Petersen 48966014759cSMartin K. Petersen scsi_debug_unmap_max_desc = 48976014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_desc, 0U, 256U); 48986014759cSMartin K. Petersen 48996014759cSMartin K. Petersen scsi_debug_unmap_granularity = 49006014759cSMartin K. Petersen clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); 49016014759cSMartin K. Petersen 49026014759cSMartin K. Petersen if (scsi_debug_unmap_alignment && 4903ac17078aSAkinobu Mita scsi_debug_unmap_granularity <= 4904ac17078aSAkinobu Mita scsi_debug_unmap_alignment) { 4905c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 490644d92694SMartin K. Petersen return -EINVAL; 490744d92694SMartin K. Petersen } 490844d92694SMartin K. Petersen 4909b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 4910b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 491144d92694SMartin K. Petersen 4912c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 491344d92694SMartin K. Petersen 491444d92694SMartin K. Petersen if (map_storep == NULL) { 4915c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 491644d92694SMartin K. Petersen ret = -ENOMEM; 491744d92694SMartin K. Petersen goto free_vm; 491844d92694SMartin K. Petersen } 491944d92694SMartin K. Petersen 4920b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 492144d92694SMartin K. Petersen 492244d92694SMartin K. Petersen /* Map first 1KB for partition table */ 492344d92694SMartin K. Petersen if (scsi_debug_num_parts) 492444d92694SMartin K. Petersen map_region(0, 2); 492544d92694SMartin K. Petersen } 492644d92694SMartin K. Petersen 49279b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 49289b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 4929c1287970STomas Winkler pr_warn("root_device_register() error\n"); 49309b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 49316ecaff7fSRandy Dunlap goto free_vm; 49326ecaff7fSRandy Dunlap } 49336ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 49346ecaff7fSRandy Dunlap if (ret < 0) { 4935c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 49366ecaff7fSRandy Dunlap goto dev_unreg; 49376ecaff7fSRandy Dunlap } 49386ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 49396ecaff7fSRandy Dunlap if (ret < 0) { 4940c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 49416ecaff7fSRandy Dunlap goto bus_unreg; 49426ecaff7fSRandy Dunlap } 49431da177e4SLinus Torvalds 49441da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 49451da177e4SLinus Torvalds scsi_debug_add_host = 0; 49461da177e4SLinus Torvalds 49471da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 49481da177e4SLinus Torvalds if (sdebug_add_adapter()) { 4949c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 49501da177e4SLinus Torvalds break; 49511da177e4SLinus Torvalds } 49521da177e4SLinus Torvalds } 49531da177e4SLinus Torvalds 4954c1287970STomas Winkler if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 4955c1287970STomas Winkler pr_info("built %d host(s)\n", scsi_debug_add_host); 4956c1287970STomas Winkler 49571da177e4SLinus Torvalds return 0; 49586ecaff7fSRandy Dunlap 49596ecaff7fSRandy Dunlap bus_unreg: 49606ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 49616ecaff7fSRandy Dunlap dev_unreg: 49629b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 49636ecaff7fSRandy Dunlap free_vm: 496444d92694SMartin K. Petersen vfree(map_storep); 4965c6a44287SMartin K. Petersen vfree(dif_storep); 49666ecaff7fSRandy Dunlap vfree(fake_storep); 49676ecaff7fSRandy Dunlap 49686ecaff7fSRandy Dunlap return ret; 49691da177e4SLinus Torvalds } 49701da177e4SLinus Torvalds 49711da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 49721da177e4SLinus Torvalds { 49731da177e4SLinus Torvalds int k = scsi_debug_add_host; 49741da177e4SLinus Torvalds 49751da177e4SLinus Torvalds stop_all_queued(); 4976cbf67842SDouglas Gilbert free_all_queued(); 49771da177e4SLinus Torvalds for (; k; k--) 49781da177e4SLinus Torvalds sdebug_remove_adapter(); 49791da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 49801da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 49819b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 49821da177e4SLinus Torvalds 4983c6a44287SMartin K. Petersen vfree(dif_storep); 49841da177e4SLinus Torvalds vfree(fake_storep); 49851da177e4SLinus Torvalds } 49861da177e4SLinus Torvalds 49871da177e4SLinus Torvalds device_initcall(scsi_debug_init); 49881da177e4SLinus Torvalds module_exit(scsi_debug_exit); 49891da177e4SLinus Torvalds 49901da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 49911da177e4SLinus Torvalds { 49921da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 49931da177e4SLinus Torvalds 49941da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 49951da177e4SLinus Torvalds kfree(sdbg_host); 49961da177e4SLinus Torvalds } 49971da177e4SLinus Torvalds 49981da177e4SLinus Torvalds static int sdebug_add_adapter(void) 49991da177e4SLinus Torvalds { 50001da177e4SLinus Torvalds int k, devs_per_host; 50011da177e4SLinus Torvalds int error = 0; 50021da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 50038b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 50041da177e4SLinus Torvalds 500524669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 50061da177e4SLinus Torvalds if (NULL == sdbg_host) { 5007c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 50081da177e4SLinus Torvalds return -ENOMEM; 50091da177e4SLinus Torvalds } 50101da177e4SLinus Torvalds 50111da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 50121da177e4SLinus Torvalds 50131da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 50141da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 50155cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 50165cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 5017c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 50181da177e4SLinus Torvalds error = -ENOMEM; 50191da177e4SLinus Torvalds goto clean; 50201da177e4SLinus Torvalds } 50211da177e4SLinus Torvalds } 50221da177e4SLinus Torvalds 50231da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 50241da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 50251da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 50261da177e4SLinus Torvalds 50271da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 50289b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 50291da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 503071610f55SKay Sievers dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); 50311da177e4SLinus Torvalds 50321da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 50331da177e4SLinus Torvalds 50341da177e4SLinus Torvalds if (error) 50351da177e4SLinus Torvalds goto clean; 50361da177e4SLinus Torvalds 50371da177e4SLinus Torvalds ++scsi_debug_add_host; 50381da177e4SLinus Torvalds return error; 50391da177e4SLinus Torvalds 50401da177e4SLinus Torvalds clean: 50418b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 50428b40228fSFUJITA Tomonori dev_list) { 50431da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 50441da177e4SLinus Torvalds kfree(sdbg_devinfo); 50451da177e4SLinus Torvalds } 50461da177e4SLinus Torvalds 50471da177e4SLinus Torvalds kfree(sdbg_host); 50481da177e4SLinus Torvalds return error; 50491da177e4SLinus Torvalds } 50501da177e4SLinus Torvalds 50511da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 50521da177e4SLinus Torvalds { 50531da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 50541da177e4SLinus Torvalds 50551da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 50561da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 50571da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 50581da177e4SLinus Torvalds struct sdebug_host_info, host_list); 50591da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 50601da177e4SLinus Torvalds } 50611da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 50621da177e4SLinus Torvalds 50631da177e4SLinus Torvalds if (!sdbg_host) 50641da177e4SLinus Torvalds return; 50651da177e4SLinus Torvalds 50661da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 50671da177e4SLinus Torvalds --scsi_debug_add_host; 50681da177e4SLinus Torvalds } 50691da177e4SLinus Torvalds 5070cbf67842SDouglas Gilbert static int 5071db5ed4dfSChristoph Hellwig sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 5072cbf67842SDouglas Gilbert { 5073cbf67842SDouglas Gilbert int num_in_q = 0; 5074cbf67842SDouglas Gilbert unsigned long iflags; 5075cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5076cbf67842SDouglas Gilbert 5077cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 5078cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 5079cbf67842SDouglas Gilbert if (NULL == devip) { 5080cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 5081cbf67842SDouglas Gilbert return -ENODEV; 5082cbf67842SDouglas Gilbert } 5083cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5084cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 5085c40ecc12SChristoph Hellwig 5086cbf67842SDouglas Gilbert if (qdepth < 1) 5087cbf67842SDouglas Gilbert qdepth = 1; 5088cbf67842SDouglas Gilbert /* allow to exceed max host queued_arr elements for testing */ 5089cbf67842SDouglas Gilbert if (qdepth > SCSI_DEBUG_CANQUEUE + 10) 5090cbf67842SDouglas Gilbert qdepth = SCSI_DEBUG_CANQUEUE + 10; 5091db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 5092cbf67842SDouglas Gilbert 5093c40ecc12SChristoph Hellwig if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) { 5094cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdev, 5095c40ecc12SChristoph Hellwig "%s: qdepth=%d, num_in_q=%d\n", 5096c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 5097cbf67842SDouglas Gilbert } 5098cbf67842SDouglas Gilbert return sdev->queue_depth; 5099cbf67842SDouglas Gilbert } 5100cbf67842SDouglas Gilbert 5101cbf67842SDouglas Gilbert static int 5102817fd66bSDouglas Gilbert check_inject(struct scsi_cmnd *scp) 5103817fd66bSDouglas Gilbert { 5104817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 5105817fd66bSDouglas Gilbert 5106817fd66bSDouglas Gilbert memset(ep, 0, sizeof(struct sdebug_scmd_extra_t)); 5107817fd66bSDouglas Gilbert 5108817fd66bSDouglas Gilbert if (atomic_inc_return(&sdebug_cmnd_count) >= 5109817fd66bSDouglas Gilbert abs(scsi_debug_every_nth)) { 5110817fd66bSDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5111817fd66bSDouglas Gilbert if (scsi_debug_every_nth < -1) 5112817fd66bSDouglas Gilbert scsi_debug_every_nth = -1; 5113817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 5114817fd66bSDouglas Gilbert return 1; /* ignore command causing timeout */ 5115817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && 5116817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5117817fd66bSDouglas Gilbert return 1; /* time out reads and writes */ 5118817fd66bSDouglas Gilbert if (sdebug_any_injecting_opt) { 5119817fd66bSDouglas Gilbert int opts = scsi_debug_opts; 5120817fd66bSDouglas Gilbert 5121817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 5122817fd66bSDouglas Gilbert ep->inj_recovered = true; 5123817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 5124817fd66bSDouglas Gilbert ep->inj_transport = true; 5125817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 5126817fd66bSDouglas Gilbert ep->inj_dif = true; 5127817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 5128817fd66bSDouglas Gilbert ep->inj_dix = true; 5129817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 5130817fd66bSDouglas Gilbert ep->inj_short = true; 5131817fd66bSDouglas Gilbert } 5132817fd66bSDouglas Gilbert } 5133817fd66bSDouglas Gilbert return 0; 5134817fd66bSDouglas Gilbert } 5135817fd66bSDouglas Gilbert 5136c2248fc9SDouglas Gilbert static int 5137c2248fc9SDouglas Gilbert scsi_debug_queuecommand(struct scsi_cmnd *scp) 5138c2248fc9SDouglas Gilbert { 5139c2248fc9SDouglas Gilbert u8 sdeb_i; 5140c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5141c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5142c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5143c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5144c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5145c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5146c2248fc9SDouglas Gilbert int k, na; 5147c2248fc9SDouglas Gilbert int errsts = 0; 5148c2248fc9SDouglas Gilbert int errsts_no_connect = DID_NO_CONNECT << 16; 5149c2248fc9SDouglas Gilbert u32 flags; 5150c2248fc9SDouglas Gilbert u16 sa; 5151c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5152c2248fc9SDouglas Gilbert bool has_wlun_rl; 5153c2248fc9SDouglas Gilbert bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts); 5154c2248fc9SDouglas Gilbert 5155c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5156c2248fc9SDouglas Gilbert if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) { 5157c2248fc9SDouglas Gilbert char b[120]; 5158c2248fc9SDouglas Gilbert int n, len, sb; 5159c2248fc9SDouglas Gilbert 5160c2248fc9SDouglas Gilbert len = scp->cmd_len; 5161c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5162c2248fc9SDouglas Gilbert if (len > 32) 5163c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5164c2248fc9SDouglas Gilbert else { 5165c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5166c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5167c2248fc9SDouglas Gilbert (u32)cmd[k]); 5168c2248fc9SDouglas Gilbert } 5169c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b); 5170c2248fc9SDouglas Gilbert } 517134d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 5172c2248fc9SDouglas Gilbert if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl) 5173c2248fc9SDouglas Gilbert return schedule_resp(scp, NULL, errsts_no_connect, 0); 5174c2248fc9SDouglas Gilbert 5175c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5176c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5177c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5178c2248fc9SDouglas Gilbert if (!devip) { 5179c2248fc9SDouglas Gilbert devip = devInfoReg(sdp); 5180c2248fc9SDouglas Gilbert if (NULL == devip) 5181c2248fc9SDouglas Gilbert return schedule_resp(scp, NULL, errsts_no_connect, 0); 5182c2248fc9SDouglas Gilbert } 5183c2248fc9SDouglas Gilbert na = oip->num_attached; 5184c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5185c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5186c2248fc9SDouglas Gilbert r_oip = oip; 5187c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5188c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5189c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5190c2248fc9SDouglas Gilbert else 5191c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5192c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5193c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5194c2248fc9SDouglas Gilbert break; 5195c2248fc9SDouglas Gilbert } 5196c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5197c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5198c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5199c2248fc9SDouglas Gilbert break; 5200c2248fc9SDouglas Gilbert } 5201c2248fc9SDouglas Gilbert } 5202c2248fc9SDouglas Gilbert if (k > na) { 5203c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5204c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5205c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5206c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5207c2248fc9SDouglas Gilbert else 5208c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5209c2248fc9SDouglas Gilbert goto check_cond; 5210c2248fc9SDouglas Gilbert } 5211c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5212c2248fc9SDouglas Gilbert flags = oip->flags; 5213c2248fc9SDouglas Gilbert if (F_INV_OP & flags) { 5214c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5215c2248fc9SDouglas Gilbert goto check_cond; 5216c2248fc9SDouglas Gilbert } 5217c2248fc9SDouglas Gilbert if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) { 5218c2248fc9SDouglas Gilbert if (debug) 5219c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: " 5220c2248fc9SDouglas Gilbert "0x%x not supported for wlun\n", opcode); 5221c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5222c2248fc9SDouglas Gilbert goto check_cond; 5223c2248fc9SDouglas Gilbert } 5224c2248fc9SDouglas Gilbert if (scsi_debug_strict) { /* check cdb against mask */ 5225c2248fc9SDouglas Gilbert u8 rem; 5226c2248fc9SDouglas Gilbert int j; 5227c2248fc9SDouglas Gilbert 5228c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5229c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5230c2248fc9SDouglas Gilbert if (rem) { 5231c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5232c2248fc9SDouglas Gilbert if (0x80 & rem) 5233c2248fc9SDouglas Gilbert break; 5234c2248fc9SDouglas Gilbert } 5235c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5236c2248fc9SDouglas Gilbert goto check_cond; 5237c2248fc9SDouglas Gilbert } 5238c2248fc9SDouglas Gilbert } 5239c2248fc9SDouglas Gilbert } 5240c2248fc9SDouglas Gilbert if (!(F_SKIP_UA & flags) && 5241c2248fc9SDouglas Gilbert SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) { 5242c2248fc9SDouglas Gilbert errsts = check_readiness(scp, UAS_ONLY, devip); 5243c2248fc9SDouglas Gilbert if (errsts) 5244c2248fc9SDouglas Gilbert goto check_cond; 5245c2248fc9SDouglas Gilbert } 5246c2248fc9SDouglas Gilbert if ((F_M_ACCESS & flags) && devip->stopped) { 5247c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5248c2248fc9SDouglas Gilbert if (debug) 5249c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5250c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5251c2248fc9SDouglas Gilbert "required"); 5252c2248fc9SDouglas Gilbert errsts = check_condition_result; 5253c2248fc9SDouglas Gilbert goto fini; 5254c2248fc9SDouglas Gilbert } 5255c2248fc9SDouglas Gilbert if (scsi_debug_fake_rw && (F_FAKE_RW & flags)) 5256c2248fc9SDouglas Gilbert goto fini; 5257c2248fc9SDouglas Gilbert if (scsi_debug_every_nth) { 5258c2248fc9SDouglas Gilbert if (check_inject(scp)) 5259c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5260c2248fc9SDouglas Gilbert } 5261c2248fc9SDouglas Gilbert if (oip->pfp) /* if this command has a resp_* function, call it */ 5262c2248fc9SDouglas Gilbert errsts = oip->pfp(scp, devip); 5263c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5264c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5265c2248fc9SDouglas Gilbert 5266c2248fc9SDouglas Gilbert fini: 5267c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5268c2248fc9SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay)); 5269c2248fc9SDouglas Gilbert check_cond: 5270c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5271c2248fc9SDouglas Gilbert } 5272c2248fc9SDouglas Gilbert 527338d5c833SDouglas Gilbert static int 527438d5c833SDouglas Gilbert sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 527538d5c833SDouglas Gilbert { 527638d5c833SDouglas Gilbert if (scsi_debug_host_lock) { 527738d5c833SDouglas Gilbert unsigned long iflags; 527838d5c833SDouglas Gilbert int rc; 527938d5c833SDouglas Gilbert 528038d5c833SDouglas Gilbert spin_lock_irqsave(shost->host_lock, iflags); 528138d5c833SDouglas Gilbert rc = scsi_debug_queuecommand(cmd); 528238d5c833SDouglas Gilbert spin_unlock_irqrestore(shost->host_lock, iflags); 528338d5c833SDouglas Gilbert return rc; 528438d5c833SDouglas Gilbert } else 528538d5c833SDouglas Gilbert return scsi_debug_queuecommand(cmd); 528638d5c833SDouglas Gilbert } 528738d5c833SDouglas Gilbert 52889e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5289c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5290c8ed555aSAl Viro .write_info = scsi_debug_write_info, 52919e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 52929e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 52939e603ca0SFUJITA Tomonori .info = scsi_debug_info, 52949e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 52959e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 52969e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 52979e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5298cbf67842SDouglas Gilbert .queuecommand = sdebug_queuecommand_lock_or_not, 5299cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 53009e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 53019e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5302cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5303cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 53049e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 53059e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 53069e603ca0SFUJITA Tomonori .this_id = 7, 53076bb5e6e7SAkinobu Mita .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, 5308cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 53096bb5e6e7SAkinobu Mita .max_sectors = -1U, 53109e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 53119e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5312c40ecc12SChristoph Hellwig .track_queue_depth = 1, 5313817fd66bSDouglas Gilbert .cmd_size = sizeof(struct sdebug_scmd_extra_t), 53149e603ca0SFUJITA Tomonori }; 53159e603ca0SFUJITA Tomonori 53161da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 53171da177e4SLinus Torvalds { 53181da177e4SLinus Torvalds int error = 0; 5319817fd66bSDouglas Gilbert int opts; 53201da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 53211da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5322c6a44287SMartin K. Petersen int host_prot; 53231da177e4SLinus Torvalds 53241da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 53251da177e4SLinus Torvalds 532678d4e5a0SDouglas Gilbert sdebug_driver_template.can_queue = scsi_debug_max_queue; 53270759c666SAkinobu Mita if (scsi_debug_clustering) 53280759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 53291da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 53301da177e4SLinus Torvalds if (NULL == hpnt) { 5331c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 53321da177e4SLinus Torvalds error = -ENODEV; 53331da177e4SLinus Torvalds return error; 53341da177e4SLinus Torvalds } 53351da177e4SLinus Torvalds 53361da177e4SLinus Torvalds sdbg_host->shost = hpnt; 53371da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 53381da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 53391da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 53401da177e4SLinus Torvalds else 53411da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 5342f2d3fd29STomas Winkler /* = scsi_debug_max_luns; */ 5343f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 53441da177e4SLinus Torvalds 5345c6a44287SMartin K. Petersen host_prot = 0; 5346c6a44287SMartin K. Petersen 5347c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 5348c6a44287SMartin K. Petersen 5349c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 5350c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE1_PROTECTION; 5351c6a44287SMartin K. Petersen if (scsi_debug_dix) 5352c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE1_PROTECTION; 5353c6a44287SMartin K. Petersen break; 5354c6a44287SMartin K. Petersen 5355c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 5356c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE2_PROTECTION; 5357c6a44287SMartin K. Petersen if (scsi_debug_dix) 5358c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE2_PROTECTION; 5359c6a44287SMartin K. Petersen break; 5360c6a44287SMartin K. Petersen 5361c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 5362c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE3_PROTECTION; 5363c6a44287SMartin K. Petersen if (scsi_debug_dix) 5364c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE3_PROTECTION; 5365c6a44287SMartin K. Petersen break; 5366c6a44287SMartin K. Petersen 5367c6a44287SMartin K. Petersen default: 5368c6a44287SMartin K. Petersen if (scsi_debug_dix) 5369c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE0_PROTECTION; 5370c6a44287SMartin K. Petersen break; 5371c6a44287SMartin K. Petersen } 5372c6a44287SMartin K. Petersen 5373c6a44287SMartin K. Petersen scsi_host_set_prot(hpnt, host_prot); 5374c6a44287SMartin K. Petersen 5375c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5376c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5377c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5378c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5379c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5380c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5381c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5382c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5383c6a44287SMartin K. Petersen 5384c6a44287SMartin K. Petersen if (scsi_debug_guard == 1) 5385c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5386c6a44287SMartin K. Petersen else 5387c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5388c6a44287SMartin K. Petersen 5389817fd66bSDouglas Gilbert opts = scsi_debug_opts; 5390817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 5391817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5392817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 5393817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5394817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 5395817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5396817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 5397817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5398817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 5399817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5400817fd66bSDouglas Gilbert 54011da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 54021da177e4SLinus Torvalds if (error) { 5403c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 54041da177e4SLinus Torvalds error = -ENODEV; 54051da177e4SLinus Torvalds scsi_host_put(hpnt); 54061da177e4SLinus Torvalds } else 54071da177e4SLinus Torvalds scsi_scan_host(hpnt); 54081da177e4SLinus Torvalds 54091da177e4SLinus Torvalds return error; 54101da177e4SLinus Torvalds } 54111da177e4SLinus Torvalds 54121da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 54131da177e4SLinus Torvalds { 54141da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 54158b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 54161da177e4SLinus Torvalds 54171da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 54181da177e4SLinus Torvalds 54191da177e4SLinus Torvalds if (!sdbg_host) { 5420c1287970STomas Winkler pr_err("Unable to locate host info\n"); 54211da177e4SLinus Torvalds return -ENODEV; 54221da177e4SLinus Torvalds } 54231da177e4SLinus Torvalds 54241da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 54251da177e4SLinus Torvalds 54268b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 54278b40228fSFUJITA Tomonori dev_list) { 54281da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 54291da177e4SLinus Torvalds kfree(sdbg_devinfo); 54301da177e4SLinus Torvalds } 54311da177e4SLinus Torvalds 54321da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 54331da177e4SLinus Torvalds return 0; 54341da177e4SLinus Torvalds } 54351da177e4SLinus Torvalds 54368dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 54378dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 54381da177e4SLinus Torvalds { 54398dea0d02SFUJITA Tomonori return 1; 54408dea0d02SFUJITA Tomonori } 54411da177e4SLinus Torvalds 54428dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 54438dea0d02SFUJITA Tomonori .name = "pseudo", 54448dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 54458dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 54468dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 544782069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 54488dea0d02SFUJITA Tomonori }; 5449