11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * This version is more generic, simulating a variable number of disk 1023183910SDouglas Gilbert * (or disk like devices) sharing a common amount of RAM. To be more 1123183910SDouglas Gilbert * realistic, the simulated devices have the transport attributes of 1223183910SDouglas Gilbert * SAS disks. 131da177e4SLinus Torvalds * 141da177e4SLinus Torvalds * 1578d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 161da177e4SLinus Torvalds * 171da177e4SLinus Torvalds * D. Gilbert (dpg) work for Magneto-Optical device test [20010421] 181da177e4SLinus Torvalds * dpg: work for devfs large number of disks [20010809] 191da177e4SLinus Torvalds * forked for lk 2.5 series [20011216, 20020101] 201da177e4SLinus Torvalds * use vmalloc() more inquiry+mode_sense [20020302] 211da177e4SLinus Torvalds * add timers for delayed responses [20020721] 221da177e4SLinus Torvalds * Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031] 231da177e4SLinus Torvalds * Mike Anderson <andmike@us.ibm.com> sysfs work [20021118] 241da177e4SLinus Torvalds * dpg: change style of boot options to "scsi_debug.num_tgts=2" and 251da177e4SLinus Torvalds * module options to "modprobe scsi_debug num_tgts=2" [20021221] 261da177e4SLinus Torvalds */ 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds #include <linux/module.h> 291da177e4SLinus Torvalds 301da177e4SLinus Torvalds #include <linux/kernel.h> 311da177e4SLinus Torvalds #include <linux/errno.h> 321da177e4SLinus Torvalds #include <linux/timer.h> 335a0e3ad6STejun Heo #include <linux/slab.h> 341da177e4SLinus Torvalds #include <linux/types.h> 351da177e4SLinus Torvalds #include <linux/string.h> 361da177e4SLinus Torvalds #include <linux/genhd.h> 371da177e4SLinus Torvalds #include <linux/fs.h> 381da177e4SLinus Torvalds #include <linux/init.h> 391da177e4SLinus Torvalds #include <linux/proc_fs.h> 401da177e4SLinus Torvalds #include <linux/vmalloc.h> 411da177e4SLinus Torvalds #include <linux/moduleparam.h> 42852e034dSJens Axboe #include <linux/scatterlist.h> 431da177e4SLinus Torvalds #include <linux/blkdev.h> 44c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 45cbf67842SDouglas Gilbert #include <linux/spinlock.h> 46cbf67842SDouglas Gilbert #include <linux/interrupt.h> 47cbf67842SDouglas Gilbert #include <linux/atomic.h> 48cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 49c6a44287SMartin K. Petersen 50c6a44287SMartin K. Petersen #include <net/checksum.h> 519ff26eefSFUJITA Tomonori 5244d92694SMartin K. Petersen #include <asm/unaligned.h> 5344d92694SMartin K. Petersen 549ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 559ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 569ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 571da177e4SLinus Torvalds #include <scsi/scsi_host.h> 581da177e4SLinus Torvalds #include <scsi/scsicam.h> 59a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 60cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 61395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 621da177e4SLinus Torvalds 63c6a44287SMartin K. Petersen #include "sd.h" 641da177e4SLinus Torvalds #include "scsi_logging.h" 651da177e4SLinus Torvalds 6622017ed2SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.85" 6722017ed2SDouglas Gilbert static const char *scsi_debug_version_date = "20141022"; 68cbf67842SDouglas Gilbert 69cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 701da177e4SLinus Torvalds 716f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 72c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 73c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 74c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 751da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 76c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 771da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7822017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 791da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 80c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 81cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 82cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 941da177e4SLinus Torvalds 956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 976f3cbf55SDouglas Gilbert 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds /* Default values for driver parameters */ 1001da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1011da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1021da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1031da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1041da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1051da177e4SLinus Torvalds */ 1065b94e232SMartin K. Petersen #define DEF_ATO 1 107cbf67842SDouglas Gilbert #define DEF_DELAY 1 /* if > 0 unit is a jiffy */ 1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1095b94e232SMartin K. Petersen #define DEF_DIF 0 1105b94e232SMartin K. Petersen #define DEF_DIX 0 1115b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1121da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1135b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1145b94e232SMartin K. Petersen #define DEF_GUARD 0 115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1165b94e232SMartin K. Petersen #define DEF_LBPU 0 1175b94e232SMartin K. Petersen #define DEF_LBPWS 0 1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0 119be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 121cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1231da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1241da177e4SLinus Torvalds #define DEF_OPTS 0 125e308b3d1SMartin K. Petersen #define DEF_OPT_BLKS 64 1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 1275b94e232SMartin K. Petersen #define DEF_PTYPE 0 128d986788bSMartin Pitt #define DEF_REMOVABLE false 129e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */ 1305b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1315b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1325b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1355b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1365b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1375b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 138c2248fc9SDouglas Gilbert #define DEF_STRICT 0 139cbf67842SDouglas Gilbert #define DELAY_OVERRIDDEN -9999 1401da177e4SLinus Torvalds 1411da177e4SLinus Torvalds /* bit mask values for scsi_debug_opts */ 1421da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_NOISE 1 1431da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_MEDIUM_ERR 2 1441da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_TIMEOUT 4 1451da177e4SLinus Torvalds #define SCSI_DEBUG_OPT_RECOVERED_ERR 8 1466f3cbf55SDouglas Gilbert #define SCSI_DEBUG_OPT_TRANSPORT_ERR 16 147c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIF_ERR 32 148c6a44287SMartin K. Petersen #define SCSI_DEBUG_OPT_DIX_ERR 64 14918a4d0a2SMartin K. Petersen #define SCSI_DEBUG_OPT_MAC_TIMEOUT 128 150cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_SHORT_TRANSFER 0x100 151cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_Q_NOISE 0x200 152cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_TSF 0x400 153cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RARE_TSF 0x800 154cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_N_WCE 0x1000 155cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_RESET_NOISE 0x2000 156cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_NO_CDB_NOISE 0x4000 157cbf67842SDouglas Gilbert #define SCSI_DEBUG_OPT_ALL_NOISE (0x1 | 0x200 | 0x2000) 1581da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 1591da177e4SLinus Torvalds * - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set 1601da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 1611da177e4SLinus Torvalds * commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set. 1626f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 1636f3cbf55SDouglas Gilbert * commands if SCSI_DEBUG_OPT_TRANSPORT_ERR is set. 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds * When "every_nth" < 0 then after "- 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 * This will continue until some other action occurs (e.g. the user 1721da177e4SLinus Torvalds * writing a new value (other than -1 or 1) to every_nth via sysfs). 1731da177e4SLinus Torvalds */ 1741da177e4SLinus Torvalds 175cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs)are returned in 176cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 177cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 178cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 179cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 180cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 181cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1820d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 1830d01c5dfSDouglas Gilbert #define SDEBUG_NUM_UAS 4 184cbf67842SDouglas Gilbert 185cbf67842SDouglas Gilbert /* for check_readiness() */ 186c2248fc9SDouglas Gilbert #define UAS_ONLY 1 /* check for UAs only */ 187c2248fc9SDouglas Gilbert #define UAS_TUR 0 /* if no UAs then check if media access possible */ 188cbf67842SDouglas Gilbert 1891da177e4SLinus Torvalds /* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1901da177e4SLinus Torvalds * sector on read commands: */ 1911da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 19232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 1931da177e4SLinus Torvalds 1941da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1951da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 1961da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 197c65b1445SDouglas Gilbert #define SAM2_WLUN_REPORT_LUNS 0xc101 1981da177e4SLinus Torvalds 199cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued 200cbf67842SDouglas Gilbert * (for response) at one time. Can be reduced by max_queue option. Command 201cbf67842SDouglas Gilbert * responses are not queued when delay=0 and ndelay=0. The per-device 202cbf67842SDouglas Gilbert * DEF_CMD_PER_LUN can be changed via sysfs: 203cbf67842SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed 204cbf67842SDouglas Gilbert * SCSI_DEBUG_CANQUEUE. */ 205cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */ 206cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 207cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 208cbf67842SDouglas Gilbert 209cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE 210cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE" 211cbf67842SDouglas Gilbert #endif 21278d4e5a0SDouglas Gilbert 213c2248fc9SDouglas Gilbert /* SCSI opcodes (first byte of cdb) mapped onto these indexes */ 214c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 215c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 216c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 217c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 218c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 219c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 220c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 221c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 222c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 223c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 224c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 225c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 226c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 227c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 228c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 229c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 230c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 231c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 232c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 233c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 234c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 235c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 236c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 237c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 238c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 239c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 240c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 241c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 242c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 243c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 244c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 245c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 246c2248fc9SDouglas Gilbert }; 247c2248fc9SDouglas Gilbert 248c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 249c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 250c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 251c2248fc9SDouglas Gilbert 0, 0, 0, 0, 252c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 253c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 254c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 255c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 256c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 257c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 258c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 259c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 260c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 261c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 262c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 263c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 264c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 265c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 266c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 267c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 268c2248fc9SDouglas Gilbert /* 0x60; 0x60->0x7d are reserved */ 269c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 270c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 271c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 272c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 273c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 274c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 275c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 276c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 277c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 278c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 279c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 280c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 281c2248fc9SDouglas Gilbert 0, 0, 0, 0, 282c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 283c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 284c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 285c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 286c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 287c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 288c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 289c2248fc9SDouglas Gilbert }; 290c2248fc9SDouglas Gilbert 291c2248fc9SDouglas Gilbert #define F_D_IN 1 292c2248fc9SDouglas Gilbert #define F_D_OUT 2 293c2248fc9SDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 294c2248fc9SDouglas Gilbert #define F_D_UNKN 8 295c2248fc9SDouglas Gilbert #define F_RL_WLUN_OK 0x10 296c2248fc9SDouglas Gilbert #define F_SKIP_UA 0x20 297c2248fc9SDouglas Gilbert #define F_DELAY_OVERR 0x40 298c2248fc9SDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 299c2248fc9SDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 300c2248fc9SDouglas Gilbert #define F_INV_OP 0x200 301c2248fc9SDouglas Gilbert #define F_FAKE_RW 0x400 302c2248fc9SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 303c2248fc9SDouglas Gilbert 304c2248fc9SDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 305c2248fc9SDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 306c2248fc9SDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 307c2248fc9SDouglas Gilbert 308c2248fc9SDouglas Gilbert struct sdebug_dev_info; 309c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 310c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 311c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 312c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 313c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 314c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 315c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 316c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 317c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 318c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 319c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 320c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 321c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 322c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 32338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 32438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 325c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 326c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 327c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 32838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 329c2248fc9SDouglas Gilbert 330c2248fc9SDouglas Gilbert struct opcode_info_t { 331c2248fc9SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff 332c2248fc9SDouglas Gilbert * for terminating element */ 333c2248fc9SDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 334c2248fc9SDouglas Gilbert u16 sa; /* service action */ 335c2248fc9SDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 336c2248fc9SDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 337c2248fc9SDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 338c2248fc9SDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 339c2248fc9SDouglas Gilbert /* ignore cdb bytes after position 15 */ 340c2248fc9SDouglas Gilbert }; 341c2248fc9SDouglas Gilbert 342c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 343c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 344c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 345c2248fc9SDouglas Gilbert }; 346c2248fc9SDouglas Gilbert 347c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 348c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 349c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 350c2248fc9SDouglas Gilbert }; 351c2248fc9SDouglas Gilbert 352c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 353c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 354c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 355c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 356c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 357c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 358c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 359c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 360c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 361c2248fc9SDouglas Gilbert }; 362c2248fc9SDouglas Gilbert 363c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 364c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 365c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 366c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 367c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 368c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 369c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 370c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 371c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 372c2248fc9SDouglas Gilbert }; 373c2248fc9SDouglas Gilbert 374c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 375c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 376c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 377c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 378c2248fc9SDouglas Gilbert }; 379c2248fc9SDouglas Gilbert 380c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 381c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 382c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 383c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 384c2248fc9SDouglas Gilbert }; 385c2248fc9SDouglas Gilbert 386c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 38738d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 388c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 389c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 39038d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 391c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 392c2248fc9SDouglas Gilbert 0, 0} }, 393c2248fc9SDouglas Gilbert }; 394c2248fc9SDouglas Gilbert 395c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 396c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 397c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 398c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 399c2248fc9SDouglas Gilbert }; 400c2248fc9SDouglas Gilbert 401c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 402c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 403c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 404c2248fc9SDouglas Gilbert }; 405c2248fc9SDouglas Gilbert 406c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 407c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 408c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 409c2248fc9SDouglas Gilbert }; 410c2248fc9SDouglas Gilbert 411c2248fc9SDouglas Gilbert 412c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 413c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 414c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 415c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 416c2248fc9SDouglas Gilbert /* 0 */ 417c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 418c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 419c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 420c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 421c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 422c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 423c2248fc9SDouglas Gilbert 0, 0} }, 424c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 425c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 426c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 427c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 428c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 429c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 430c2248fc9SDouglas Gilbert 0} }, 431c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 432c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 433c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 434c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 435c2248fc9SDouglas Gilbert 0, 0, 0} }, 436c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 437c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 438c2248fc9SDouglas Gilbert 0, 0} }, 439c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 440c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 441c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 442c2248fc9SDouglas Gilbert /* 10 */ 443c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 444c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 445c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 446c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 447c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 448c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 449c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 450c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 451c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 452c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 453c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 454c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 455c2248fc9SDouglas Gilbert 0} }, 456c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 457c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 458c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */ 459c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 460c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 461c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 462c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 463c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 464c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 465c2248fc9SDouglas Gilbert 0} }, 466c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 467c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 468c2248fc9SDouglas Gilbert 0} }, 469c2248fc9SDouglas Gilbert /* 20 */ 470c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */ 471c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 472c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 473c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 474c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 475c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 476c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 477c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 478c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 479c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 480c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 481c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 482c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 483c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */ 484c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 485c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 486c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 487c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 488c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 489c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 490c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 49138d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 492c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 493c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 494c2248fc9SDouglas Gilbert 495c2248fc9SDouglas Gilbert /* 30 */ 496c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 497c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 498c2248fc9SDouglas Gilbert }; 499c2248fc9SDouglas Gilbert 500817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t { 501817fd66bSDouglas Gilbert bool inj_recovered; 502817fd66bSDouglas Gilbert bool inj_transport; 503817fd66bSDouglas Gilbert bool inj_dif; 504817fd66bSDouglas Gilbert bool inj_dix; 505817fd66bSDouglas Gilbert bool inj_short; 506817fd66bSDouglas Gilbert }; 507817fd66bSDouglas Gilbert 5081da177e4SLinus Torvalds static int scsi_debug_add_host = DEF_NUM_HOST; 5095b94e232SMartin K. Petersen static int scsi_debug_ato = DEF_ATO; 5101da177e4SLinus Torvalds static int scsi_debug_delay = DEF_DELAY; 5111da177e4SLinus Torvalds static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB; 5125b94e232SMartin K. Petersen static int scsi_debug_dif = DEF_DIF; 5135b94e232SMartin K. Petersen static int scsi_debug_dix = DEF_DIX; 5145b94e232SMartin K. Petersen static int scsi_debug_dsense = DEF_D_SENSE; 5151da177e4SLinus Torvalds static int scsi_debug_every_nth = DEF_EVERY_NTH; 5165b94e232SMartin K. Petersen static int scsi_debug_fake_rw = DEF_FAKE_RW; 51768aee7baSAkinobu Mita static unsigned int scsi_debug_guard = DEF_GUARD; 5185b94e232SMartin K. Petersen static int scsi_debug_lowest_aligned = DEF_LOWEST_ALIGNED; 5191da177e4SLinus Torvalds static int scsi_debug_max_luns = DEF_MAX_LUNS; 52078d4e5a0SDouglas Gilbert static int scsi_debug_max_queue = SCSI_DEBUG_CANQUEUE; 521cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 522cbf67842SDouglas Gilbert static int scsi_debug_ndelay = DEF_NDELAY; 523c65b1445SDouglas Gilbert static int scsi_debug_no_lun_0 = DEF_NO_LUN_0; 5245b94e232SMartin K. Petersen static int scsi_debug_no_uld = 0; 5255b94e232SMartin K. Petersen static int scsi_debug_num_parts = DEF_NUM_PARTS; 5265b94e232SMartin K. Petersen static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 527e308b3d1SMartin K. Petersen static int scsi_debug_opt_blks = DEF_OPT_BLKS; 5285b94e232SMartin K. Petersen static int scsi_debug_opts = DEF_OPTS; 5295b94e232SMartin K. Petersen static int scsi_debug_physblk_exp = DEF_PHYSBLK_EXP; 5305b94e232SMartin K. Petersen static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 5315b94e232SMartin K. Petersen static int scsi_debug_scsi_level = DEF_SCSI_LEVEL; 5325b94e232SMartin K. Petersen static int scsi_debug_sector_size = DEF_SECTOR_SIZE; 5335b94e232SMartin K. Petersen static int scsi_debug_virtual_gb = DEF_VIRTUAL_GB; 5345b94e232SMartin K. Petersen static int scsi_debug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 5355b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpu = DEF_LBPU; 5365b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws = DEF_LBPWS; 5375b94e232SMartin K. Petersen static unsigned int scsi_debug_lbpws10 = DEF_LBPWS10; 538be1dd78dSEric Sandeen static unsigned int scsi_debug_lbprz = DEF_LBPRZ; 5396014759cSMartin K. Petersen static unsigned int scsi_debug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 5405b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_granularity = DEF_UNMAP_GRANULARITY; 5415b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 5425b94e232SMartin K. Petersen static unsigned int scsi_debug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 5435b94e232SMartin K. Petersen static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH; 544d986788bSMartin Pitt static bool scsi_debug_removable = DEF_REMOVABLE; 5450759c666SAkinobu Mita static bool scsi_debug_clustering; 546cbf67842SDouglas Gilbert static bool scsi_debug_host_lock = DEF_HOST_LOCK; 547c2248fc9SDouglas Gilbert static bool scsi_debug_strict = DEF_STRICT; 548817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 5491da177e4SLinus Torvalds 550cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count; 551cbf67842SDouglas Gilbert static atomic_t sdebug_completions; 552cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */ 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds #define DEV_READONLY(TGT) (0) 5551da177e4SLinus Torvalds 556c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 5571da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 5581da177e4SLinus Torvalds 5591da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 5601da177e4SLinus Torvalds may still need them */ 5611da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 5621da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 5631da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 5641da177e4SLinus Torvalds 5651da177e4SLinus Torvalds #define SDEBUG_MAX_PARTS 4 5661da177e4SLinus Torvalds 567395cef03SMartin K. Petersen #define SCSI_DEBUG_MAX_CMD_LEN 32 5689e603ca0SFUJITA Tomonori 5695b94e232SMartin K. Petersen static unsigned int scsi_debug_lbp(void) 5705b94e232SMartin K. Petersen { 571cbf67842SDouglas Gilbert return ((0 == scsi_debug_fake_rw) && 572cbf67842SDouglas Gilbert (scsi_debug_lbpu | scsi_debug_lbpws | scsi_debug_lbpws10)); 5735b94e232SMartin K. Petersen } 5745b94e232SMartin K. Petersen 5751da177e4SLinus Torvalds struct sdebug_dev_info { 5761da177e4SLinus Torvalds struct list_head dev_list; 5771da177e4SLinus Torvalds unsigned int channel; 5781da177e4SLinus Torvalds unsigned int target; 5799cb78c16SHannes Reinecke u64 lun; 5801da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 581cbf67842SDouglas Gilbert unsigned long uas_bm[1]; 582cbf67842SDouglas Gilbert atomic_t num_in_q; 583c2248fc9SDouglas Gilbert char stopped; /* TODO: should be atomic */ 584c2248fc9SDouglas Gilbert bool used; 5851da177e4SLinus Torvalds }; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds struct sdebug_host_info { 5881da177e4SLinus Torvalds struct list_head host_list; 5891da177e4SLinus Torvalds struct Scsi_Host *shost; 5901da177e4SLinus Torvalds struct device dev; 5911da177e4SLinus Torvalds struct list_head dev_info_list; 5921da177e4SLinus Torvalds }; 5931da177e4SLinus Torvalds 5941da177e4SLinus Torvalds #define to_sdebug_host(d) \ 5951da177e4SLinus Torvalds container_of(d, struct sdebug_host_info, dev) 5961da177e4SLinus Torvalds 5971da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 5981da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 5991da177e4SLinus Torvalds 600cbf67842SDouglas Gilbert 601cbf67842SDouglas Gilbert struct sdebug_hrtimer { /* ... is derived from hrtimer */ 602cbf67842SDouglas Gilbert struct hrtimer hrt; /* must be first element */ 603cbf67842SDouglas Gilbert int qa_indx; 604cbf67842SDouglas Gilbert }; 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds struct sdebug_queued_cmd { 607cbf67842SDouglas Gilbert /* in_use flagged by a bit in queued_in_use_bm[] */ 608cbf67842SDouglas Gilbert struct timer_list *cmnd_timerp; 609cbf67842SDouglas Gilbert struct tasklet_struct *tletp; 610cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hrtp; 6111da177e4SLinus Torvalds struct scsi_cmnd * a_cmnd; 6121da177e4SLinus Torvalds }; 6131da177e4SLinus Torvalds static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 614cbf67842SDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS]; 615cbf67842SDouglas Gilbert 6161da177e4SLinus Torvalds 6171da177e4SLinus Torvalds static unsigned char * fake_storep; /* ramdisk storage */ 618e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep; /* protection info */ 61944d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6201da177e4SLinus Torvalds 62144d92694SMartin K. Petersen static unsigned long map_size; 622cbf67842SDouglas Gilbert static int num_aborts; 623cbf67842SDouglas Gilbert static int num_dev_resets; 624cbf67842SDouglas Gilbert static int num_target_resets; 625cbf67842SDouglas Gilbert static int num_bus_resets; 626cbf67842SDouglas Gilbert static int num_host_resets; 627c6a44287SMartin K. Petersen static int dix_writes; 628c6a44287SMartin K. Petersen static int dix_reads; 629c6a44287SMartin K. Petersen static int dif_errors; 6301da177e4SLinus Torvalds 6311da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 6321da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6331da177e4SLinus Torvalds 634cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 635cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6381da177e4SLinus Torvalds 6391da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6401da177e4SLinus Torvalds .name = sdebug_proc_name, 6411da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6421da177e4SLinus Torvalds }; 6431da177e4SLinus Torvalds 6441da177e4SLinus Torvalds static const int check_condition_result = 6451da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6461da177e4SLinus Torvalds 647c6a44287SMartin K. Petersen static const int illegal_condition_result = 648c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 649c6a44287SMartin K. Petersen 650cbf67842SDouglas Gilbert static const int device_qfull_result = 651cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 652cbf67842SDouglas Gilbert 653cbf67842SDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 654cbf67842SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 655cbf67842SDouglas Gilbert 0, 0, 0, 0}; 656c65b1445SDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 657c65b1445SDouglas Gilbert 0, 0, 0x2, 0x4b}; 658c65b1445SDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 659c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 660c65b1445SDouglas Gilbert 66114faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 66214faa944SAkinobu Mita { 66314faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 66414faa944SAkinobu Mita 66514faa944SAkinobu Mita return fake_storep + lba * scsi_debug_sector_size; 66614faa944SAkinobu Mita } 66714faa944SAkinobu Mita 66814faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector) 66914faa944SAkinobu Mita { 67014faa944SAkinobu Mita sector = do_div(sector, sdebug_store_sectors); 67114faa944SAkinobu Mita 67214faa944SAkinobu Mita return dif_storep + sector; 67314faa944SAkinobu Mita } 67414faa944SAkinobu Mita 6751da177e4SLinus Torvalds static int sdebug_add_adapter(void); 6761da177e4SLinus Torvalds static void sdebug_remove_adapter(void); 6771da177e4SLinus Torvalds 6788dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 6798dea0d02SFUJITA Tomonori { 6808dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 6818dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 6828dea0d02SFUJITA Tomonori 6838dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 6848dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 6858dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 6868dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 6878dea0d02SFUJITA Tomonori (scsi_debug_num_tgts > hpnt->this_id)) 6888dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts + 1; 6898dea0d02SFUJITA Tomonori else 6908dea0d02SFUJITA Tomonori hpnt->max_id = scsi_debug_num_tgts; 6918dea0d02SFUJITA Tomonori /* scsi_debug_max_luns; */ 6928dea0d02SFUJITA Tomonori hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; 6938dea0d02SFUJITA Tomonori } 6948dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 6958dea0d02SFUJITA Tomonori } 6968dea0d02SFUJITA Tomonori 69722017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 69822017ed2SDouglas Gilbert 69922017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 70022017ed2SDouglas Gilbert static void 70122017ed2SDouglas Gilbert mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d, 70222017ed2SDouglas Gilbert int in_byte, int in_bit) 70322017ed2SDouglas Gilbert { 70422017ed2SDouglas Gilbert unsigned char *sbuff; 70522017ed2SDouglas Gilbert u8 sks[4]; 70622017ed2SDouglas Gilbert int sl, asc; 70722017ed2SDouglas Gilbert 70822017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 70922017ed2SDouglas Gilbert if (!sbuff) { 71022017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 71122017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 71222017ed2SDouglas Gilbert return; 71322017ed2SDouglas Gilbert } 71422017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 71522017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 71622017ed2SDouglas Gilbert scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST, 71722017ed2SDouglas Gilbert asc, 0); 71822017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 71922017ed2SDouglas Gilbert sks[0] = 0x80; 72022017ed2SDouglas Gilbert if (c_d) 72122017ed2SDouglas Gilbert sks[0] |= 0x40; 72222017ed2SDouglas Gilbert if (in_bit >= 0) { 72322017ed2SDouglas Gilbert sks[0] |= 0x8; 72422017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 72522017ed2SDouglas Gilbert } 72622017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 72722017ed2SDouglas Gilbert if (scsi_debug_dsense) { 72822017ed2SDouglas Gilbert sl = sbuff[7] + 8; 72922017ed2SDouglas Gilbert sbuff[7] = sl; 73022017ed2SDouglas Gilbert sbuff[sl] = 0x2; 73122017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 73222017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 73322017ed2SDouglas Gilbert } else 73422017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 73522017ed2SDouglas Gilbert if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 73622017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 73722017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 73822017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 73922017ed2SDouglas Gilbert } 74022017ed2SDouglas Gilbert 741cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7428dea0d02SFUJITA Tomonori { 7438dea0d02SFUJITA Tomonori unsigned char *sbuff; 7448dea0d02SFUJITA Tomonori 745cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 746cbf67842SDouglas Gilbert if (!sbuff) { 747cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 748cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 749cbf67842SDouglas Gilbert return; 750cbf67842SDouglas Gilbert } 751cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7528dea0d02SFUJITA Tomonori 7538dea0d02SFUJITA Tomonori scsi_build_sense_buffer(scsi_debug_dsense, sbuff, key, asc, asq); 7548dea0d02SFUJITA Tomonori 7558dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 756cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 757cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 758cbf67842SDouglas Gilbert my_name, key, asc, asq); 7598dea0d02SFUJITA Tomonori } 7601da177e4SLinus Torvalds 76122017ed2SDouglas Gilbert static void 76222017ed2SDouglas Gilbert mk_sense_invalid_opcode(struct scsi_cmnd *scp) 76322017ed2SDouglas Gilbert { 76422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 76522017ed2SDouglas Gilbert } 76622017ed2SDouglas Gilbert 7671da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7681da177e4SLinus Torvalds { 7691da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 770cbf67842SDouglas Gilbert if (0x1261 == cmd) 771cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 772cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 773cbf67842SDouglas Gilbert else if (0x5331 == cmd) 774cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 775cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 776cbf67842SDouglas Gilbert __func__); 777cbf67842SDouglas Gilbert else 778cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 779cbf67842SDouglas Gilbert __func__, cmd); 7801da177e4SLinus Torvalds } 7811da177e4SLinus Torvalds return -EINVAL; 7821da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 7831da177e4SLinus Torvalds } 7841da177e4SLinus Torvalds 785cbf67842SDouglas Gilbert static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only, 786c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 7871da177e4SLinus Torvalds { 788cbf67842SDouglas Gilbert int k; 789cbf67842SDouglas Gilbert bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts); 790cbf67842SDouglas Gilbert 791cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 792cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 793cbf67842SDouglas Gilbert const char *cp = NULL; 794cbf67842SDouglas Gilbert 795cbf67842SDouglas Gilbert switch (k) { 796cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 797cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 798cbf67842SDouglas Gilbert UA_RESET_ASC, POWER_ON_RESET_ASCQ); 799cbf67842SDouglas Gilbert if (debug) 800cbf67842SDouglas Gilbert cp = "power on reset"; 801cbf67842SDouglas Gilbert break; 802cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 803cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 804cbf67842SDouglas Gilbert UA_RESET_ASC, BUS_RESET_ASCQ); 805cbf67842SDouglas Gilbert if (debug) 806cbf67842SDouglas Gilbert cp = "bus reset"; 807cbf67842SDouglas Gilbert break; 808cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 809cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 810cbf67842SDouglas Gilbert UA_CHANGED_ASC, MODE_CHANGED_ASCQ); 811cbf67842SDouglas Gilbert if (debug) 812cbf67842SDouglas Gilbert cp = "mode parameters changed"; 813cbf67842SDouglas Gilbert break; 8140d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 8150d01c5dfSDouglas Gilbert mk_sense_buffer(SCpnt, UNIT_ATTENTION, 8160d01c5dfSDouglas Gilbert UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ); 8170d01c5dfSDouglas Gilbert if (debug) 8180d01c5dfSDouglas Gilbert cp = "capacity data changed"; 819f49accf1SEwan D. Milne break; 820cbf67842SDouglas Gilbert default: 821cbf67842SDouglas Gilbert pr_warn("%s: unexpected unit attention code=%d\n", 822cbf67842SDouglas Gilbert __func__, k); 823cbf67842SDouglas Gilbert if (debug) 824cbf67842SDouglas Gilbert cp = "unknown"; 825cbf67842SDouglas Gilbert break; 826cbf67842SDouglas Gilbert } 827cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 828cbf67842SDouglas Gilbert if (debug) 829cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 830cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 831cbf67842SDouglas Gilbert my_name, cp); 8321da177e4SLinus Torvalds return check_condition_result; 8331da177e4SLinus Torvalds } 834cbf67842SDouglas Gilbert if ((UAS_TUR == uas_only) && devip->stopped) { 835cbf67842SDouglas Gilbert mk_sense_buffer(SCpnt, NOT_READY, LOGICAL_UNIT_NOT_READY, 836c65b1445SDouglas Gilbert 0x2); 837cbf67842SDouglas Gilbert if (debug) 838cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 839cbf67842SDouglas Gilbert "%s reports: Not ready: %s\n", my_name, 840cbf67842SDouglas Gilbert "initializing command required"); 841c65b1445SDouglas Gilbert return check_condition_result; 842c65b1445SDouglas Gilbert } 8431da177e4SLinus Torvalds return 0; 8441da177e4SLinus Torvalds } 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 8471da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 8481da177e4SLinus Torvalds int arr_len) 8491da177e4SLinus Torvalds { 85021a61829SFUJITA Tomonori int act_len; 851072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 8521da177e4SLinus Torvalds 853072d0bb3SFUJITA Tomonori if (!sdb->length) 8541da177e4SLinus Torvalds return 0; 855072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 8561da177e4SLinus Torvalds return (DID_ERROR << 16); 85721a61829SFUJITA Tomonori 85821a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 85921a61829SFUJITA Tomonori arr, arr_len); 86021a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 86121a61829SFUJITA Tomonori 8621da177e4SLinus Torvalds return 0; 8631da177e4SLinus Torvalds } 8641da177e4SLinus Torvalds 8651da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 8661da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 86721a61829SFUJITA Tomonori int arr_len) 8681da177e4SLinus Torvalds { 86921a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 8701da177e4SLinus Torvalds return 0; 871072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 8721da177e4SLinus Torvalds return -1; 87321a61829SFUJITA Tomonori 87421a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 8791da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 880cbf67842SDouglas Gilbert static const char *inq_product_rev = "0184"; /* version less '.' */ 8811da177e4SLinus Torvalds 882cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 8835a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 8845a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 8855a09e398SHannes Reinecke const char * dev_id_str, 886c65b1445SDouglas Gilbert int dev_id_str_len) 8871da177e4SLinus Torvalds { 888c65b1445SDouglas Gilbert int num, port_a; 889c65b1445SDouglas Gilbert char b[32]; 8901da177e4SLinus Torvalds 891c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 8921da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 8931da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 8941da177e4SLinus Torvalds arr[1] = 0x1; 8951da177e4SLinus Torvalds arr[2] = 0x0; 8961da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 8971da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 8981da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 8991da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9001da177e4SLinus Torvalds arr[3] = num; 9011da177e4SLinus Torvalds num += 4; 902c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 903c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 904c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 905c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 906c65b1445SDouglas Gilbert arr[num++] = 0x0; 907c65b1445SDouglas Gilbert arr[num++] = 0x8; 908c65b1445SDouglas Gilbert arr[num++] = 0x53; /* naa-5 ieee company id=0x333333 (fake) */ 909c65b1445SDouglas Gilbert arr[num++] = 0x33; 910c65b1445SDouglas Gilbert arr[num++] = 0x33; 911c65b1445SDouglas Gilbert arr[num++] = 0x30; 912c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 24); 913c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 16) & 0xff; 914c65b1445SDouglas Gilbert arr[num++] = (dev_id_num >> 8) & 0xff; 915c65b1445SDouglas Gilbert arr[num++] = dev_id_num & 0xff; 916c65b1445SDouglas Gilbert /* Target relative port number */ 917c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 918c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 919c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 920c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 921c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 922c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 923c65b1445SDouglas Gilbert arr[num++] = 0x0; 924c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 925c65b1445SDouglas Gilbert } 926c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 927c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 928c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 929c65b1445SDouglas Gilbert arr[num++] = 0x0; 930c65b1445SDouglas Gilbert arr[num++] = 0x8; 931c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 932c65b1445SDouglas Gilbert arr[num++] = 0x22; 933c65b1445SDouglas Gilbert arr[num++] = 0x22; 934c65b1445SDouglas Gilbert arr[num++] = 0x20; 935c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 936c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 937c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 938c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 9395a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 9405a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 9415a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 9425a09e398SHannes Reinecke arr[num++] = 0x0; 9435a09e398SHannes Reinecke arr[num++] = 0x4; 9445a09e398SHannes Reinecke arr[num++] = 0; 9455a09e398SHannes Reinecke arr[num++] = 0; 9465a09e398SHannes Reinecke arr[num++] = (port_group_id >> 8) & 0xff; 9475a09e398SHannes Reinecke arr[num++] = port_group_id & 0xff; 948c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 949c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 950c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 951c65b1445SDouglas Gilbert arr[num++] = 0x0; 952c65b1445SDouglas Gilbert arr[num++] = 0x8; 953c65b1445SDouglas Gilbert arr[num++] = 0x52; /* naa-5, company id=0x222222 (fake) */ 954c65b1445SDouglas Gilbert arr[num++] = 0x22; 955c65b1445SDouglas Gilbert arr[num++] = 0x22; 956c65b1445SDouglas Gilbert arr[num++] = 0x20; 957c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 24); 958c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 16) & 0xff; 959c65b1445SDouglas Gilbert arr[num++] = (target_dev_id >> 8) & 0xff; 960c65b1445SDouglas Gilbert arr[num++] = target_dev_id & 0xff; 961c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 962c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 963c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 964c65b1445SDouglas Gilbert arr[num++] = 0x0; 965c65b1445SDouglas Gilbert arr[num++] = 24; 966c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 967c65b1445SDouglas Gilbert num += 12; 968c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 969c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 970c65b1445SDouglas Gilbert num += 8; 971c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 972c65b1445SDouglas Gilbert num += 4; 973c65b1445SDouglas Gilbert return num; 974c65b1445SDouglas Gilbert } 975c65b1445SDouglas Gilbert 976c65b1445SDouglas Gilbert 977c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 978c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 979c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 980c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 981c65b1445SDouglas Gilbert }; 982c65b1445SDouglas Gilbert 983cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 984c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 985c65b1445SDouglas Gilbert { 986c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 987c65b1445SDouglas Gilbert return sizeof(vpd84_data); 988c65b1445SDouglas Gilbert } 989c65b1445SDouglas Gilbert 990cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 991c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 992c65b1445SDouglas Gilbert { 993c65b1445SDouglas Gilbert int num = 0; 994c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 995c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 996c65b1445SDouglas Gilbert int plen, olen; 997c65b1445SDouglas Gilbert 998c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 999c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1000c65b1445SDouglas Gilbert arr[num++] = 0x0; 1001c65b1445SDouglas Gilbert olen = strlen(na1); 1002c65b1445SDouglas Gilbert plen = olen + 1; 1003c65b1445SDouglas Gilbert if (plen % 4) 1004c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1005c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1006c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1007c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1008c65b1445SDouglas Gilbert num += plen; 1009c65b1445SDouglas Gilbert 1010c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1011c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1012c65b1445SDouglas Gilbert arr[num++] = 0x0; 1013c65b1445SDouglas Gilbert olen = strlen(na2); 1014c65b1445SDouglas Gilbert plen = olen + 1; 1015c65b1445SDouglas Gilbert if (plen % 4) 1016c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1017c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1018c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1019c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1020c65b1445SDouglas Gilbert num += plen; 1021c65b1445SDouglas Gilbert 1022c65b1445SDouglas Gilbert return num; 1023c65b1445SDouglas Gilbert } 1024c65b1445SDouglas Gilbert 1025c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1026c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 1027c65b1445SDouglas Gilbert { 1028c65b1445SDouglas Gilbert int num = 0; 1029c65b1445SDouglas Gilbert int port_a, port_b; 1030c65b1445SDouglas Gilbert 1031c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1032c65b1445SDouglas Gilbert port_b = port_a + 1; 1033c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1034c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1035c65b1445SDouglas Gilbert arr[num++] = 0x0; 1036c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1037c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1038c65b1445SDouglas Gilbert num += 6; 1039c65b1445SDouglas Gilbert arr[num++] = 0x0; 1040c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1041c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1042c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1043c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1044c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1045c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1046c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 1047c65b1445SDouglas Gilbert arr[num++] = 0x22; 1048c65b1445SDouglas Gilbert arr[num++] = 0x22; 1049c65b1445SDouglas Gilbert arr[num++] = 0x20; 1050c65b1445SDouglas Gilbert arr[num++] = (port_a >> 24); 1051c65b1445SDouglas Gilbert arr[num++] = (port_a >> 16) & 0xff; 1052c65b1445SDouglas Gilbert arr[num++] = (port_a >> 8) & 0xff; 1053c65b1445SDouglas Gilbert arr[num++] = port_a & 0xff; 1054c65b1445SDouglas Gilbert 1055c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1056c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1057c65b1445SDouglas Gilbert arr[num++] = 0x0; 1058c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1059c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1060c65b1445SDouglas Gilbert num += 6; 1061c65b1445SDouglas Gilbert arr[num++] = 0x0; 1062c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1063c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1064c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1065c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1066c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1067c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1068c65b1445SDouglas Gilbert arr[num++] = 0x52; /* NAA-5, company_id=0x222222 (fake) */ 1069c65b1445SDouglas Gilbert arr[num++] = 0x22; 1070c65b1445SDouglas Gilbert arr[num++] = 0x22; 1071c65b1445SDouglas Gilbert arr[num++] = 0x20; 1072c65b1445SDouglas Gilbert arr[num++] = (port_b >> 24); 1073c65b1445SDouglas Gilbert arr[num++] = (port_b >> 16) & 0xff; 1074c65b1445SDouglas Gilbert arr[num++] = (port_b >> 8) & 0xff; 1075c65b1445SDouglas Gilbert arr[num++] = port_b & 0xff; 1076c65b1445SDouglas Gilbert 1077c65b1445SDouglas Gilbert return num; 1078c65b1445SDouglas Gilbert } 1079c65b1445SDouglas Gilbert 1080c65b1445SDouglas Gilbert 1081c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1082c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1083c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1084c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1085c65b1445SDouglas Gilbert '1','2','3','4', 1086c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1087c65b1445SDouglas Gilbert 0xec,0,0,0, 1088c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1089c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1090c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1091c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1092c65b1445SDouglas Gilbert 0x53,0x41, 1093c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1094c65b1445SDouglas Gilbert 0x20,0x20, 1095c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1096c65b1445SDouglas Gilbert 0x10,0x80, 1097c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1098c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1099c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1100c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1101c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1102c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1103c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1104c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1105c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1106c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1107c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1108c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1109c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1110c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1111c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1112c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1113c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1114c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1115c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1116c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1117c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1118c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1119c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1120c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1121c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1122c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1123c65b1445SDouglas Gilbert }; 1124c65b1445SDouglas Gilbert 1125cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1126c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 1127c65b1445SDouglas Gilbert { 1128c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1129c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1130c65b1445SDouglas Gilbert } 1131c65b1445SDouglas Gilbert 1132c65b1445SDouglas Gilbert 1133c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11341e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 11351e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11361e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11371e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1138c65b1445SDouglas Gilbert }; 1139c65b1445SDouglas Gilbert 1140cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1141c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 1142c65b1445SDouglas Gilbert { 1143ea61fca5SMartin K. Petersen unsigned int gran; 1144ea61fca5SMartin K. Petersen 1145c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1146e308b3d1SMartin K. Petersen 1147e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 1148ea61fca5SMartin K. Petersen gran = 1 << scsi_debug_physblk_exp; 1149ea61fca5SMartin K. Petersen arr[2] = (gran >> 8) & 0xff; 1150ea61fca5SMartin K. Petersen arr[3] = gran & 0xff; 1151e308b3d1SMartin K. Petersen 1152e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1153c65b1445SDouglas Gilbert if (sdebug_store_sectors > 0x400) { 1154c65b1445SDouglas Gilbert arr[4] = (sdebug_store_sectors >> 24) & 0xff; 1155c65b1445SDouglas Gilbert arr[5] = (sdebug_store_sectors >> 16) & 0xff; 1156c65b1445SDouglas Gilbert arr[6] = (sdebug_store_sectors >> 8) & 0xff; 1157c65b1445SDouglas Gilbert arr[7] = sdebug_store_sectors & 0xff; 1158c65b1445SDouglas Gilbert } 115944d92694SMartin K. Petersen 1160e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1161e308b3d1SMartin K. Petersen put_unaligned_be32(scsi_debug_opt_blks, &arr[8]); 1162e308b3d1SMartin K. Petersen 11635b94e232SMartin K. Petersen if (scsi_debug_lbpu) { 1164e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 11656014759cSMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_blocks, &arr[16]); 1166e308b3d1SMartin K. Petersen 1167e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 116844d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_max_desc, &arr[20]); 116944d92694SMartin K. Petersen } 117044d92694SMartin K. Petersen 1171e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 117244d92694SMartin K. Petersen if (scsi_debug_unmap_alignment) { 117344d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_alignment, &arr[28]); 117444d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 117544d92694SMartin K. Petersen } 117644d92694SMartin K. Petersen 1177e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 117844d92694SMartin K. Petersen put_unaligned_be32(scsi_debug_unmap_granularity, &arr[24]); 11796014759cSMartin K. Petersen 11805b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 11815b94e232SMartin K. Petersen put_unaligned_be64(scsi_debug_write_same_length, &arr[32]); 11825b94e232SMartin K. Petersen 11835b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 118444d92694SMartin K. Petersen 1185c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 11881e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1189eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 1190eac6e8e4SMatthew Wilcox { 1191eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1192eac6e8e4SMatthew Wilcox arr[0] = 0; 11931e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 11941e49f785SDouglas Gilbert arr[2] = 0; 11951e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1196eac6e8e4SMatthew Wilcox 1197eac6e8e4SMatthew Wilcox return 0x3c; 1198eac6e8e4SMatthew Wilcox } 11991da177e4SLinus Torvalds 1200be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */ 12016014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 12026014759cSMartin K. Petersen { 12033f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 12046014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 12056014759cSMartin K. Petersen 12065b94e232SMartin K. Petersen if (scsi_debug_lbpu) 12076014759cSMartin K. Petersen arr[1] = 1 << 7; 12086014759cSMartin K. Petersen 12095b94e232SMartin K. Petersen if (scsi_debug_lbpws) 12106014759cSMartin K. Petersen arr[1] |= 1 << 6; 12116014759cSMartin K. Petersen 12125b94e232SMartin K. Petersen if (scsi_debug_lbpws10) 12135b94e232SMartin K. Petersen arr[1] |= 1 << 5; 12145b94e232SMartin K. Petersen 1215be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1216be1dd78dSEric Sandeen arr[1] |= 1 << 2; 1217be1dd78dSEric Sandeen 12183f0bc3b3SMartin K. Petersen return 0x4; 12196014759cSMartin K. Petersen } 12206014759cSMartin K. Petersen 12211da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1222c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12231da177e4SLinus Torvalds 1224c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12251da177e4SLinus Torvalds { 12261da177e4SLinus Torvalds unsigned char pq_pdt; 12275a09e398SHannes Reinecke unsigned char * arr; 122801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12295a09e398SHannes Reinecke int alloc_len, n, ret; 1230c2248fc9SDouglas Gilbert bool have_wlun; 12311da177e4SLinus Torvalds 12321da177e4SLinus Torvalds alloc_len = (cmd[3] << 8) + cmd[4]; 12336f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12346f3cbf55SDouglas Gilbert if (! arr) 12356f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1236c2248fc9SDouglas Gilbert have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS); 1237c2248fc9SDouglas Gilbert if (have_wlun) 1238c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 1239c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (0 == devip->lun)) 1240c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 1241c65b1445SDouglas Gilbert else 12421da177e4SLinus Torvalds pq_pdt = (scsi_debug_ptype & 0x1f); 12431da177e4SLinus Torvalds arr[0] = pq_pdt; 12441da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 124522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 12465a09e398SHannes Reinecke kfree(arr); 12471da177e4SLinus Torvalds return check_condition_result; 12481da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 12495a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1250c65b1445SDouglas Gilbert char lu_id_str[6]; 1251c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 12521da177e4SLinus Torvalds 12535a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 12545a09e398SHannes Reinecke (devip->channel & 0x7f); 125523183910SDouglas Gilbert if (0 == scsi_debug_vpd_use_hostno) 125623183910SDouglas Gilbert host_no = 0; 1257c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1258c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1259c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1260c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1261c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 12621da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1263c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1264c65b1445SDouglas Gilbert n = 4; 1265c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1266c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1267c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1268c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1269c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1270c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1271c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1272c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1273c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1274c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 1275eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 12765b94e232SMartin K. Petersen if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ 12775b94e232SMartin K. Petersen arr[n++] = 0xb2; 1278c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 12791da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1280c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 12811da177e4SLinus Torvalds arr[3] = len; 1282c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 12831da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1284c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 12855a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 12865a09e398SHannes Reinecke target_dev_id, lu_id_num, 12875a09e398SHannes Reinecke lu_id_str, len); 1288c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1289c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1290c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 1291c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1292c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1293c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 1294c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1295c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1296c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1297c6a44287SMartin K. Petersen if (scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) 1298c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1299c6a44287SMartin K. Petersen else if (scsi_debug_dif) 1300c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1301c6a44287SMartin K. Petersen else 1302c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1303c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1304c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1305c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1306c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1307c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1308c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1309c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1310c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1311c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1312c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1313c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 1314c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 1315c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1316c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 1317c65b1445SDouglas Gilbert arr[2] = (n >> 8); 1318c65b1445SDouglas Gilbert arr[3] = (n & 0xff); 1319c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 1320c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1321c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 1322eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 1323eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1324eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 13255b94e232SMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ 13266014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 13276014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 13281da177e4SLinus Torvalds } else { 132922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13305a09e398SHannes Reinecke kfree(arr); 13311da177e4SLinus Torvalds return check_condition_result; 13321da177e4SLinus Torvalds } 1333c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 13345a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1335c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13365a09e398SHannes Reinecke kfree(arr); 13375a09e398SHannes Reinecke return ret; 13381da177e4SLinus Torvalds } 13391da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1340d986788bSMartin Pitt arr[1] = scsi_debug_removable ? 0x80 : 0; /* Removable disk */ 13411da177e4SLinus Torvalds arr[2] = scsi_debug_scsi_level; 13421da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 13431da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1344c6a44287SMartin K. Petersen arr[5] = scsi_debug_dif ? 1 : 0; /* PROTECT bit */ 13455a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) 13465a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1347c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 13481da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1349c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 13501da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 13511da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 13521da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 13531da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1354e46b0344SDouglas Gilbert arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */ 1355e46b0344SDouglas Gilbert arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */ 1356c65b1445SDouglas Gilbert n = 62; 13571da177e4SLinus Torvalds if (scsi_debug_ptype == 0) { 1358e46b0344SDouglas Gilbert arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */ 13591da177e4SLinus Torvalds } else if (scsi_debug_ptype == 1) { 1360e46b0344SDouglas Gilbert arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */ 13611da177e4SLinus Torvalds } 1362e46b0344SDouglas Gilbert arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */ 13635a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 13641da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 13655a09e398SHannes Reinecke kfree(arr); 13665a09e398SHannes Reinecke return ret; 13671da177e4SLinus Torvalds } 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 13701da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13711da177e4SLinus Torvalds { 13721da177e4SLinus Torvalds unsigned char * sbuff; 137301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1374cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 1375c2248fc9SDouglas Gilbert bool dsense, want_dsense; 13761da177e4SLinus Torvalds int len = 18; 13771da177e4SLinus Torvalds 1378c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1379c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1380c2248fc9SDouglas Gilbert want_dsense = dsense || scsi_debug_dsense; 1381cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1382c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1383c2248fc9SDouglas Gilbert if (dsense) { 1384c65b1445SDouglas Gilbert arr[0] = 0x72; 1385c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1386c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1387c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1388c2248fc9SDouglas Gilbert len = 8; 1389c65b1445SDouglas Gilbert } else { 1390c65b1445SDouglas Gilbert arr[0] = 0x70; 1391c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1392c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1393c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1394c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1395c65b1445SDouglas Gilbert } 1396c65b1445SDouglas Gilbert } else { 1397cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1398c2248fc9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == scsi_debug_dsense) 1399c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1400c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1401c2248fc9SDouglas Gilbert if (dsense) { 1402c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1403c2248fc9SDouglas Gilbert arr[0] = 0x72; 1404c2248fc9SDouglas Gilbert len = 8; 1405c2248fc9SDouglas Gilbert } else { 1406c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1407c2248fc9SDouglas Gilbert arr[0] = 0x70; 1408c2248fc9SDouglas Gilbert arr[7] = 0xa; 1409c2248fc9SDouglas Gilbert } 1410c2248fc9SDouglas Gilbert } else if (dsense) { 1411c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14121da177e4SLinus Torvalds arr[0] = 0x72; 14131da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14141da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14151da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14161da177e4SLinus Torvalds len = 8; 1417c2248fc9SDouglas Gilbert } else { 1418c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1419c2248fc9SDouglas Gilbert arr[0] = 0x70; 1420c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1421c2248fc9SDouglas Gilbert arr[7] = 0xa; 1422c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1423c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1424c65b1445SDouglas Gilbert } 1425c2248fc9SDouglas Gilbert 1426c65b1445SDouglas Gilbert } 1427cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14281da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14291da177e4SLinus Torvalds } 14301da177e4SLinus Torvalds 1431c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1432c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1433c65b1445SDouglas Gilbert { 143401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1435c2248fc9SDouglas Gilbert int power_cond, start; 1436c65b1445SDouglas Gilbert 1437c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1438c65b1445SDouglas Gilbert if (power_cond) { 143922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1440c65b1445SDouglas Gilbert return check_condition_result; 1441c65b1445SDouglas Gilbert } 1442c65b1445SDouglas Gilbert start = cmd[4] & 1; 1443c65b1445SDouglas Gilbert if (start == devip->stopped) 1444c65b1445SDouglas Gilbert devip->stopped = !start; 1445c65b1445SDouglas Gilbert return 0; 1446c65b1445SDouglas Gilbert } 1447c65b1445SDouglas Gilbert 144828898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 144928898873SFUJITA Tomonori { 145028898873SFUJITA Tomonori if (scsi_debug_virtual_gb > 0) 14515447ed6cSDouglas Gilbert return (sector_t)scsi_debug_virtual_gb * 14525447ed6cSDouglas Gilbert (1073741824 / scsi_debug_sector_size); 145328898873SFUJITA Tomonori else 145428898873SFUJITA Tomonori return sdebug_store_sectors; 145528898873SFUJITA Tomonori } 145628898873SFUJITA Tomonori 14571da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 14581da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 14591da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14601da177e4SLinus Torvalds { 14611da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1462c65b1445SDouglas Gilbert unsigned int capac; 14631da177e4SLinus Torvalds 1464c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 146528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 14661da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1467c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1468c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 14691da177e4SLinus Torvalds arr[0] = (capac >> 24); 14701da177e4SLinus Torvalds arr[1] = (capac >> 16) & 0xff; 14711da177e4SLinus Torvalds arr[2] = (capac >> 8) & 0xff; 14721da177e4SLinus Torvalds arr[3] = capac & 0xff; 1473c65b1445SDouglas Gilbert } else { 1474c65b1445SDouglas Gilbert arr[0] = 0xff; 1475c65b1445SDouglas Gilbert arr[1] = 0xff; 1476c65b1445SDouglas Gilbert arr[2] = 0xff; 1477c65b1445SDouglas Gilbert arr[3] = 0xff; 1478c65b1445SDouglas Gilbert } 1479597136abSMartin K. Petersen arr[6] = (scsi_debug_sector_size >> 8) & 0xff; 1480597136abSMartin K. Petersen arr[7] = scsi_debug_sector_size & 0xff; 14811da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 1484c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1485c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1486c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1487c65b1445SDouglas Gilbert { 148801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1489c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1490c65b1445SDouglas Gilbert unsigned long long capac; 1491c2248fc9SDouglas Gilbert int k, alloc_len; 1492c65b1445SDouglas Gilbert 1493c65b1445SDouglas Gilbert alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8) 1494c65b1445SDouglas Gilbert + cmd[13]); 1495c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 149628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1497c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1498c65b1445SDouglas Gilbert capac = sdebug_capacity - 1; 1499c65b1445SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 1500c65b1445SDouglas Gilbert arr[7 - k] = capac & 0xff; 1501597136abSMartin K. Petersen arr[8] = (scsi_debug_sector_size >> 24) & 0xff; 1502597136abSMartin K. Petersen arr[9] = (scsi_debug_sector_size >> 16) & 0xff; 1503597136abSMartin K. Petersen arr[10] = (scsi_debug_sector_size >> 8) & 0xff; 1504597136abSMartin K. Petersen arr[11] = scsi_debug_sector_size & 0xff; 1505ea61fca5SMartin K. Petersen arr[13] = scsi_debug_physblk_exp & 0xf; 1506ea61fca5SMartin K. Petersen arr[14] = (scsi_debug_lowest_aligned >> 8) & 0x3f; 150744d92694SMartin K. Petersen 1508be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 15095b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1510be1dd78dSEric Sandeen if (scsi_debug_lbprz) 1511be1dd78dSEric Sandeen arr[14] |= 0x40; /* LBPRZ */ 1512be1dd78dSEric Sandeen } 151344d92694SMartin K. Petersen 1514ea61fca5SMartin K. Petersen arr[15] = scsi_debug_lowest_aligned & 0xff; 1515c6a44287SMartin K. Petersen 1516c6a44287SMartin K. Petersen if (scsi_debug_dif) { 1517c6a44287SMartin K. Petersen arr[12] = (scsi_debug_dif - 1) << 1; /* P_TYPE */ 1518c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1519c6a44287SMartin K. Petersen } 1520c6a44287SMartin K. Petersen 1521c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1522c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1523c65b1445SDouglas Gilbert } 1524c65b1445SDouglas Gilbert 15255a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15265a09e398SHannes Reinecke 15275a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15285a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15295a09e398SHannes Reinecke { 153001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15315a09e398SHannes Reinecke unsigned char * arr; 15325a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15335a09e398SHannes Reinecke int n, ret, alen, rlen; 15345a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15355a09e398SHannes Reinecke 15365a09e398SHannes Reinecke alen = ((cmd[6] << 24) + (cmd[7] << 16) + (cmd[8] << 8) 15375a09e398SHannes Reinecke + cmd[9]); 15385a09e398SHannes Reinecke 15396f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15406f3cbf55SDouglas Gilbert if (! arr) 15416f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15425a09e398SHannes Reinecke /* 15435a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 15445a09e398SHannes Reinecke * real and a fake port with no device connected. 15455a09e398SHannes Reinecke * So we create two port groups with one port each 15465a09e398SHannes Reinecke * and set the group with port B to unavailable. 15475a09e398SHannes Reinecke */ 15485a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 15495a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 15505a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 15515a09e398SHannes Reinecke (devip->channel & 0x7f); 15525a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 15535a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 15545a09e398SHannes Reinecke 15555a09e398SHannes Reinecke /* 15565a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 15575a09e398SHannes Reinecke */ 15585a09e398SHannes Reinecke n = 4; 15595a09e398SHannes Reinecke if (0 == scsi_debug_vpd_use_hostno) { 15605a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 15615a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 15625a09e398SHannes Reinecke } else { 15635a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 15645a09e398SHannes Reinecke arr[n++] = 0x01; /* claim: only support active/optimized paths */ 15655a09e398SHannes Reinecke } 15665a09e398SHannes Reinecke arr[n++] = (port_group_a >> 8) & 0xff; 15675a09e398SHannes Reinecke arr[n++] = port_group_a & 0xff; 15685a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15695a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15705a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15715a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15725a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15735a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15745a09e398SHannes Reinecke arr[n++] = (port_a >> 8) & 0xff; 15755a09e398SHannes Reinecke arr[n++] = port_a & 0xff; 15765a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 15775a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 15785a09e398SHannes Reinecke arr[n++] = (port_group_b >> 8) & 0xff; 15795a09e398SHannes Reinecke arr[n++] = port_group_b & 0xff; 15805a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15815a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15825a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15835a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15845a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15855a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15865a09e398SHannes Reinecke arr[n++] = (port_b >> 8) & 0xff; 15875a09e398SHannes Reinecke arr[n++] = port_b & 0xff; 15885a09e398SHannes Reinecke 15895a09e398SHannes Reinecke rlen = n - 4; 15905a09e398SHannes Reinecke arr[0] = (rlen >> 24) & 0xff; 15915a09e398SHannes Reinecke arr[1] = (rlen >> 16) & 0xff; 15925a09e398SHannes Reinecke arr[2] = (rlen >> 8) & 0xff; 15935a09e398SHannes Reinecke arr[3] = rlen & 0xff; 15945a09e398SHannes Reinecke 15955a09e398SHannes Reinecke /* 15965a09e398SHannes Reinecke * Return the smallest value of either 15975a09e398SHannes Reinecke * - The allocated length 15985a09e398SHannes Reinecke * - The constructed command length 15995a09e398SHannes Reinecke * - The maximum array size 16005a09e398SHannes Reinecke */ 16015a09e398SHannes Reinecke rlen = min(alen,n); 16025a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 16035a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 16045a09e398SHannes Reinecke kfree(arr); 16055a09e398SHannes Reinecke return ret; 16065a09e398SHannes Reinecke } 16075a09e398SHannes Reinecke 160838d5c833SDouglas Gilbert static int 160938d5c833SDouglas Gilbert resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 161038d5c833SDouglas Gilbert { 161138d5c833SDouglas Gilbert bool rctd; 161238d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 161338d5c833SDouglas Gilbert u16 req_sa, u; 161438d5c833SDouglas Gilbert u32 alloc_len, a_len; 161538d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 161638d5c833SDouglas Gilbert const struct opcode_info_t *oip; 161738d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 161838d5c833SDouglas Gilbert u8 *arr; 161938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 162038d5c833SDouglas Gilbert 162138d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 162238d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 162338d5c833SDouglas Gilbert req_opcode = cmd[3]; 162438d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 162538d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16266d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 162738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 162838d5c833SDouglas Gilbert return check_condition_result; 162938d5c833SDouglas Gilbert } 163038d5c833SDouglas Gilbert if (alloc_len > 8192) 163138d5c833SDouglas Gilbert a_len = 8192; 163238d5c833SDouglas Gilbert else 163338d5c833SDouglas Gilbert a_len = alloc_len; 163499531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 163538d5c833SDouglas Gilbert if (NULL == arr) { 163638d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 163738d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 163838d5c833SDouglas Gilbert return check_condition_result; 163938d5c833SDouglas Gilbert } 164038d5c833SDouglas Gilbert switch (reporting_opts) { 164138d5c833SDouglas Gilbert case 0: /* all commands */ 164238d5c833SDouglas Gilbert /* count number of commands */ 164338d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 164438d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 164538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 164638d5c833SDouglas Gilbert continue; 164738d5c833SDouglas Gilbert count += (oip->num_attached + 1); 164838d5c833SDouglas Gilbert } 164938d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 165038d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 165138d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 165238d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 165338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 165438d5c833SDouglas Gilbert continue; 165538d5c833SDouglas Gilbert na = oip->num_attached; 165638d5c833SDouglas Gilbert arr[offset] = oip->opcode; 165738d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 165838d5c833SDouglas Gilbert if (rctd) 165938d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 166038d5c833SDouglas Gilbert if (FF_SA & oip->flags) 166138d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 166238d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 166338d5c833SDouglas Gilbert if (rctd) 166438d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 166538d5c833SDouglas Gilbert r_oip = oip; 166638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 166738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 166838d5c833SDouglas Gilbert continue; 166938d5c833SDouglas Gilbert offset += bump; 167038d5c833SDouglas Gilbert arr[offset] = oip->opcode; 167138d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 167238d5c833SDouglas Gilbert if (rctd) 167338d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 167438d5c833SDouglas Gilbert if (FF_SA & oip->flags) 167538d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 167638d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 167738d5c833SDouglas Gilbert arr + offset + 6); 167838d5c833SDouglas Gilbert if (rctd) 167938d5c833SDouglas Gilbert put_unaligned_be16(0xa, 168038d5c833SDouglas Gilbert arr + offset + 8); 168138d5c833SDouglas Gilbert } 168238d5c833SDouglas Gilbert oip = r_oip; 168338d5c833SDouglas Gilbert offset += bump; 168438d5c833SDouglas Gilbert } 168538d5c833SDouglas Gilbert break; 168638d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 168738d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 168838d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 168938d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 169038d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 169138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 169238d5c833SDouglas Gilbert supp = 1; 169338d5c833SDouglas Gilbert offset = 4; 169438d5c833SDouglas Gilbert } else { 169538d5c833SDouglas Gilbert if (1 == reporting_opts) { 169638d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 169738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 169838d5c833SDouglas Gilbert 2, 2); 169938d5c833SDouglas Gilbert kfree(arr); 170038d5c833SDouglas Gilbert return check_condition_result; 170138d5c833SDouglas Gilbert } 170238d5c833SDouglas Gilbert req_sa = 0; 170338d5c833SDouglas Gilbert } else if (2 == reporting_opts && 170438d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 170538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 170638d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 170738d5c833SDouglas Gilbert return check_condition_result; 170838d5c833SDouglas Gilbert } 170938d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 171038d5c833SDouglas Gilbert req_opcode == oip->opcode) 171138d5c833SDouglas Gilbert supp = 3; 171238d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 171338d5c833SDouglas Gilbert na = oip->num_attached; 171438d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 171538d5c833SDouglas Gilbert ++k, ++oip) { 171638d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 171738d5c833SDouglas Gilbert break; 171838d5c833SDouglas Gilbert } 171938d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 172038d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 172138d5c833SDouglas Gilbert na = oip->num_attached; 172238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 172338d5c833SDouglas Gilbert ++k, ++oip) { 172438d5c833SDouglas Gilbert if (req_sa == oip->sa) 172538d5c833SDouglas Gilbert break; 172638d5c833SDouglas Gilbert } 172738d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 172838d5c833SDouglas Gilbert } else 172938d5c833SDouglas Gilbert supp = 3; 173038d5c833SDouglas Gilbert if (3 == supp) { 173138d5c833SDouglas Gilbert u = oip->len_mask[0]; 173238d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 173338d5c833SDouglas Gilbert arr[4] = oip->opcode; 173438d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 173538d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 173638d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 173738d5c833SDouglas Gilbert offset = 4 + u; 173838d5c833SDouglas Gilbert } else 173938d5c833SDouglas Gilbert offset = 4; 174038d5c833SDouglas Gilbert } 174138d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 174238d5c833SDouglas Gilbert if (rctd) { 174338d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 174438d5c833SDouglas Gilbert offset += 12; 174538d5c833SDouglas Gilbert } 174638d5c833SDouglas Gilbert break; 174738d5c833SDouglas Gilbert default: 174838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 174938d5c833SDouglas Gilbert kfree(arr); 175038d5c833SDouglas Gilbert return check_condition_result; 175138d5c833SDouglas Gilbert } 175238d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 175338d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 175438d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 175538d5c833SDouglas Gilbert kfree(arr); 175638d5c833SDouglas Gilbert return errsts; 175738d5c833SDouglas Gilbert } 175838d5c833SDouglas Gilbert 175938d5c833SDouglas Gilbert static int 176038d5c833SDouglas Gilbert resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 176138d5c833SDouglas Gilbert { 176238d5c833SDouglas Gilbert bool repd; 176338d5c833SDouglas Gilbert u32 alloc_len, len; 176438d5c833SDouglas Gilbert u8 arr[16]; 176538d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 176638d5c833SDouglas Gilbert 176738d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 176838d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 176938d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 177038d5c833SDouglas Gilbert if (alloc_len < 4) { 177138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 177238d5c833SDouglas Gilbert return check_condition_result; 177338d5c833SDouglas Gilbert } 177438d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 177538d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 177638d5c833SDouglas Gilbert if (repd) { 177738d5c833SDouglas Gilbert arr[3] = 0xc; 177838d5c833SDouglas Gilbert len = 16; 177938d5c833SDouglas Gilbert } else 178038d5c833SDouglas Gilbert len = 4; 178138d5c833SDouglas Gilbert 178238d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 178338d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 178438d5c833SDouglas Gilbert } 178538d5c833SDouglas Gilbert 17861da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 17871da177e4SLinus Torvalds 17881da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 17891da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 17901da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 17911da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 17921da177e4SLinus Torvalds 17931da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 17941da177e4SLinus Torvalds if (1 == pcontrol) 17951da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 17961da177e4SLinus Torvalds return sizeof(err_recov_pg); 17971da177e4SLinus Torvalds } 17981da177e4SLinus Torvalds 17991da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 18001da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 18011da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 18021da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 18031da177e4SLinus Torvalds 18041da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 18051da177e4SLinus Torvalds if (1 == pcontrol) 18061da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 18071da177e4SLinus Torvalds return sizeof(disconnect_pg); 18081da177e4SLinus Torvalds } 18091da177e4SLinus Torvalds 18101da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 18111da177e4SLinus Torvalds { /* Format device page for mode_sense */ 18121da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 18131da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 18141da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 18151da177e4SLinus Torvalds 18161da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 18171da177e4SLinus Torvalds p[10] = (sdebug_sectors_per >> 8) & 0xff; 18181da177e4SLinus Torvalds p[11] = sdebug_sectors_per & 0xff; 1819597136abSMartin K. Petersen p[12] = (scsi_debug_sector_size >> 8) & 0xff; 1820597136abSMartin K. Petersen p[13] = scsi_debug_sector_size & 0xff; 1821d986788bSMartin Pitt if (scsi_debug_removable) 18221da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 18231da177e4SLinus Torvalds if (1 == pcontrol) 18241da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 18251da177e4SLinus Torvalds return sizeof(format_pg); 18261da177e4SLinus Torvalds } 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18291da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1830cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1831cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1832cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18331da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18341da177e4SLinus Torvalds 1835cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_N_WCE & scsi_debug_opts) 1836cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18371da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18381da177e4SLinus Torvalds if (1 == pcontrol) 1839cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1840cbf67842SDouglas Gilbert else if (2 == pcontrol) 1841cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18421da177e4SLinus Torvalds return sizeof(caching_pg); 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds 18451da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 18461da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1847c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1848c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1849c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 18501da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 18511da177e4SLinus Torvalds 18521da177e4SLinus Torvalds if (scsi_debug_dsense) 18531da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1854c65b1445SDouglas Gilbert else 1855c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1856c6a44287SMartin K. Petersen 1857c6a44287SMartin K. Petersen if (scsi_debug_ato) 1858c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1859c6a44287SMartin K. Petersen 18601da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 18611da177e4SLinus Torvalds if (1 == pcontrol) 1862c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1863c65b1445SDouglas Gilbert else if (2 == pcontrol) 1864c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 18651da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 1868c65b1445SDouglas Gilbert 18691da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 18701da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1871c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 18721da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1873c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1874c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1875c65b1445SDouglas Gilbert 18761da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 18771da177e4SLinus Torvalds if (1 == pcontrol) 1878c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1879c65b1445SDouglas Gilbert else if (2 == pcontrol) 1880c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 18811da177e4SLinus Torvalds return sizeof(iec_m_pg); 18821da177e4SLinus Torvalds } 18831da177e4SLinus Torvalds 1884c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1885c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1886c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1887c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1888c65b1445SDouglas Gilbert 1889c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1890c65b1445SDouglas Gilbert if (1 == pcontrol) 1891c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1892c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1893c65b1445SDouglas Gilbert } 1894c65b1445SDouglas Gilbert 1895c65b1445SDouglas Gilbert 1896c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1897c65b1445SDouglas Gilbert int target_dev_id) 1898c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1899c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1900c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1901c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1902c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1903c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1904c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1905c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1906c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1907c65b1445SDouglas Gilbert 0x52, 0x22, 0x22, 0x20, 0x0, 0x0, 0x0, 0x0, 1908c65b1445SDouglas Gilbert 0x51, 0x11, 0x11, 0x10, 0x0, 0x0, 0x0, 0x1, 1909c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1910c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1911c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1912c65b1445SDouglas Gilbert }; 1913c65b1445SDouglas Gilbert int port_a, port_b; 1914c65b1445SDouglas Gilbert 1915c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1916c65b1445SDouglas Gilbert port_b = port_a + 1; 1917c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1918c65b1445SDouglas Gilbert p[20] = (port_a >> 24); 1919c65b1445SDouglas Gilbert p[21] = (port_a >> 16) & 0xff; 1920c65b1445SDouglas Gilbert p[22] = (port_a >> 8) & 0xff; 1921c65b1445SDouglas Gilbert p[23] = port_a & 0xff; 1922c65b1445SDouglas Gilbert p[48 + 20] = (port_b >> 24); 1923c65b1445SDouglas Gilbert p[48 + 21] = (port_b >> 16) & 0xff; 1924c65b1445SDouglas Gilbert p[48 + 22] = (port_b >> 8) & 0xff; 1925c65b1445SDouglas Gilbert p[48 + 23] = port_b & 0xff; 1926c65b1445SDouglas Gilbert if (1 == pcontrol) 1927c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1928c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1929c65b1445SDouglas Gilbert } 1930c65b1445SDouglas Gilbert 1931c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1932c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1933c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1934c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1935c65b1445SDouglas Gilbert }; 1936c65b1445SDouglas Gilbert 1937c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1938c65b1445SDouglas Gilbert if (1 == pcontrol) 1939c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1940c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1941c65b1445SDouglas Gilbert } 1942c65b1445SDouglas Gilbert 19431da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 19441da177e4SLinus Torvalds 1945c2248fc9SDouglas Gilbert static int 1946c2248fc9SDouglas Gilbert resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 19471da177e4SLinus Torvalds { 194823183910SDouglas Gilbert unsigned char dbd, llbaa; 194923183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 19501da177e4SLinus Torvalds unsigned char dev_spec; 1951c2248fc9SDouglas Gilbert int k, alloc_len, msense_6, offset, len, target_dev_id; 1952c2248fc9SDouglas Gilbert int target = scp->device->id; 19531da177e4SLinus Torvalds unsigned char * ap; 19541da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 195501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19561da177e4SLinus Torvalds 195723183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 19581da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 19591da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 19601da177e4SLinus Torvalds subpcode = cmd[3]; 19611da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 196223183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 196323183910SDouglas Gilbert if ((0 == scsi_debug_ptype) && (0 == dbd)) 196423183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 196523183910SDouglas Gilbert else 196623183910SDouglas Gilbert bd_len = 0; 19671da177e4SLinus Torvalds alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]); 19681da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 19691da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 1970cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 19711da177e4SLinus Torvalds return check_condition_result; 19721da177e4SLinus Torvalds } 1973c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1974c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 197523183910SDouglas Gilbert /* set DPOFUA bit for disks */ 197623183910SDouglas Gilbert if (0 == scsi_debug_ptype) 197723183910SDouglas Gilbert dev_spec = (DEV_READONLY(target) ? 0x80 : 0x0) | 0x10; 197823183910SDouglas Gilbert else 197923183910SDouglas Gilbert dev_spec = 0x0; 19801da177e4SLinus Torvalds if (msense_6) { 19811da177e4SLinus Torvalds arr[2] = dev_spec; 198223183910SDouglas Gilbert arr[3] = bd_len; 19831da177e4SLinus Torvalds offset = 4; 19841da177e4SLinus Torvalds } else { 19851da177e4SLinus Torvalds arr[3] = dev_spec; 198623183910SDouglas Gilbert if (16 == bd_len) 198723183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 198823183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 19891da177e4SLinus Torvalds offset = 8; 19901da177e4SLinus Torvalds } 19911da177e4SLinus Torvalds ap = arr + offset; 199228898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 199328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 199428898873SFUJITA Tomonori 199523183910SDouglas Gilbert if (8 == bd_len) { 199623183910SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) { 199723183910SDouglas Gilbert ap[0] = 0xff; 199823183910SDouglas Gilbert ap[1] = 0xff; 199923183910SDouglas Gilbert ap[2] = 0xff; 200023183910SDouglas Gilbert ap[3] = 0xff; 200123183910SDouglas Gilbert } else { 200223183910SDouglas Gilbert ap[0] = (sdebug_capacity >> 24) & 0xff; 200323183910SDouglas Gilbert ap[1] = (sdebug_capacity >> 16) & 0xff; 200423183910SDouglas Gilbert ap[2] = (sdebug_capacity >> 8) & 0xff; 200523183910SDouglas Gilbert ap[3] = sdebug_capacity & 0xff; 200623183910SDouglas Gilbert } 2007597136abSMartin K. Petersen ap[6] = (scsi_debug_sector_size >> 8) & 0xff; 2008597136abSMartin K. Petersen ap[7] = scsi_debug_sector_size & 0xff; 200923183910SDouglas Gilbert offset += bd_len; 201023183910SDouglas Gilbert ap = arr + offset; 201123183910SDouglas Gilbert } else if (16 == bd_len) { 201223183910SDouglas Gilbert unsigned long long capac = sdebug_capacity; 201323183910SDouglas Gilbert 201423183910SDouglas Gilbert for (k = 0; k < 8; ++k, capac >>= 8) 201523183910SDouglas Gilbert ap[7 - k] = capac & 0xff; 2016597136abSMartin K. Petersen ap[12] = (scsi_debug_sector_size >> 24) & 0xff; 2017597136abSMartin K. Petersen ap[13] = (scsi_debug_sector_size >> 16) & 0xff; 2018597136abSMartin K. Petersen ap[14] = (scsi_debug_sector_size >> 8) & 0xff; 2019597136abSMartin K. Petersen ap[15] = scsi_debug_sector_size & 0xff; 202023183910SDouglas Gilbert offset += bd_len; 202123183910SDouglas Gilbert ap = arr + offset; 202223183910SDouglas Gilbert } 20231da177e4SLinus Torvalds 2024c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2025c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 202622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 20271da177e4SLinus Torvalds return check_condition_result; 20281da177e4SLinus Torvalds } 20291da177e4SLinus Torvalds switch (pcode) { 20301da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 20311da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20321da177e4SLinus Torvalds offset += len; 20331da177e4SLinus Torvalds break; 20341da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 20351da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20361da177e4SLinus Torvalds offset += len; 20371da177e4SLinus Torvalds break; 20381da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 20391da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20401da177e4SLinus Torvalds offset += len; 20411da177e4SLinus Torvalds break; 20421da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 20431da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 20441da177e4SLinus Torvalds offset += len; 20451da177e4SLinus Torvalds break; 20461da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 20471da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 20481da177e4SLinus Torvalds offset += len; 20491da177e4SLinus Torvalds break; 2050c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2051c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 205222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2053c65b1445SDouglas Gilbert return check_condition_result; 2054c65b1445SDouglas Gilbert } 2055c65b1445SDouglas Gilbert len = 0; 2056c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2057c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2058c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2059c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2060c65b1445SDouglas Gilbert target_dev_id); 2061c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2062c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2063c65b1445SDouglas Gilbert offset += len; 2064c65b1445SDouglas Gilbert break; 20651da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 20661da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 20671da177e4SLinus Torvalds offset += len; 20681da177e4SLinus Torvalds break; 20691da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2070c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 20711da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20721da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 20731da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 20741da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 20751da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2076c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2077c65b1445SDouglas Gilbert if (0xff == subpcode) { 2078c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2079c65b1445SDouglas Gilbert target, target_dev_id); 2080c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2081c65b1445SDouglas Gilbert } 20821da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2083c65b1445SDouglas Gilbert } else { 208422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2085c65b1445SDouglas Gilbert return check_condition_result; 2086c65b1445SDouglas Gilbert } 20871da177e4SLinus Torvalds offset += len; 20881da177e4SLinus Torvalds break; 20891da177e4SLinus Torvalds default: 209022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 20911da177e4SLinus Torvalds return check_condition_result; 20921da177e4SLinus Torvalds } 20931da177e4SLinus Torvalds if (msense_6) 20941da177e4SLinus Torvalds arr[0] = offset - 1; 20951da177e4SLinus Torvalds else { 20961da177e4SLinus Torvalds arr[0] = ((offset - 2) >> 8) & 0xff; 20971da177e4SLinus Torvalds arr[1] = (offset - 2) & 0xff; 20981da177e4SLinus Torvalds } 20991da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 21001da177e4SLinus Torvalds } 21011da177e4SLinus Torvalds 2102c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2103c65b1445SDouglas Gilbert 2104c2248fc9SDouglas Gilbert static int 2105c2248fc9SDouglas Gilbert resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 2106c65b1445SDouglas Gilbert { 2107c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2108c2248fc9SDouglas Gilbert int param_len, res, mpage; 2109c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 211001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2111c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2112c65b1445SDouglas Gilbert 2113c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2114c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2115c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2116c65b1445SDouglas Gilbert param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]); 2117c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 211822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2119c65b1445SDouglas Gilbert return check_condition_result; 2120c65b1445SDouglas Gilbert } 2121c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2122c65b1445SDouglas Gilbert if (-1 == res) 2123c65b1445SDouglas Gilbert return (DID_ERROR << 16); 2124c65b1445SDouglas Gilbert else if ((res < param_len) && 2125c65b1445SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2126cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2127cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2128cbf67842SDouglas Gilbert __func__, param_len, res); 2129c65b1445SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2); 2130c65b1445SDouglas Gilbert bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]); 213123183910SDouglas Gilbert if (md_len > 2) { 213222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2133c65b1445SDouglas Gilbert return check_condition_result; 2134c65b1445SDouglas Gilbert } 2135c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2136c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2137c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2138c65b1445SDouglas Gilbert if (ps) { 213922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2140c65b1445SDouglas Gilbert return check_condition_result; 2141c65b1445SDouglas Gilbert } 2142c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2143c65b1445SDouglas Gilbert pg_len = spf ? ((arr[off + 2] << 8) + arr[off + 3] + 4) : 2144c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2145c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2146cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2147c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2148c65b1445SDouglas Gilbert return check_condition_result; 2149c65b1445SDouglas Gilbert } 2150c65b1445SDouglas Gilbert switch (mpage) { 2151cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2152cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2153cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2154cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2155cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2156cbf67842SDouglas Gilbert } 2157cbf67842SDouglas Gilbert break; 2158c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2159c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2160c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2161c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2162c65b1445SDouglas Gilbert scsi_debug_dsense = !!(ctrl_m_pg[2] & 0x4); 2163cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2164c65b1445SDouglas Gilbert } 2165c65b1445SDouglas Gilbert break; 2166c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2167c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2168c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2169c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2170cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2171c65b1445SDouglas Gilbert } 2172c65b1445SDouglas Gilbert break; 2173c65b1445SDouglas Gilbert default: 2174c65b1445SDouglas Gilbert break; 2175c65b1445SDouglas Gilbert } 217622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2177c65b1445SDouglas Gilbert return check_condition_result; 2178cbf67842SDouglas Gilbert set_mode_changed_ua: 2179cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2180cbf67842SDouglas Gilbert return 0; 2181c65b1445SDouglas Gilbert } 2182c65b1445SDouglas Gilbert 2183c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2184c65b1445SDouglas Gilbert { 2185c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2186c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2187c65b1445SDouglas Gilbert }; 2188c65b1445SDouglas Gilbert 2189c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2190c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2191c65b1445SDouglas Gilbert } 2192c65b1445SDouglas Gilbert 2193c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2194c65b1445SDouglas Gilbert { 2195c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2196c65b1445SDouglas Gilbert }; 2197c65b1445SDouglas Gilbert 2198c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2199c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2200c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2201c65b1445SDouglas Gilbert arr[5] = 0xff; 2202c65b1445SDouglas Gilbert } 2203c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2204c65b1445SDouglas Gilbert } 2205c65b1445SDouglas Gilbert 2206c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2207c65b1445SDouglas Gilbert 2208c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2209c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2210c65b1445SDouglas Gilbert { 2211c2248fc9SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n; 2212c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 221301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2214c65b1445SDouglas Gilbert 2215c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2216c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2217c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2218c65b1445SDouglas Gilbert if (ppc || sp) { 221922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2220c65b1445SDouglas Gilbert return check_condition_result; 2221c65b1445SDouglas Gilbert } 2222c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 2223c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 222423183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2225c65b1445SDouglas Gilbert alloc_len = (cmd[7] << 8) + cmd[8]; 2226c65b1445SDouglas Gilbert arr[0] = pcode; 222723183910SDouglas Gilbert if (0 == subpcode) { 2228c65b1445SDouglas Gilbert switch (pcode) { 2229c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2230c65b1445SDouglas Gilbert n = 4; 2231c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2232c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2233c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2234c65b1445SDouglas Gilbert arr[3] = n - 4; 2235c65b1445SDouglas Gilbert break; 2236c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2237c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2238c65b1445SDouglas Gilbert break; 2239c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2240c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2241c65b1445SDouglas Gilbert break; 2242c65b1445SDouglas Gilbert default: 224322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2244c65b1445SDouglas Gilbert return check_condition_result; 2245c65b1445SDouglas Gilbert } 224623183910SDouglas Gilbert } else if (0xff == subpcode) { 224723183910SDouglas Gilbert arr[0] |= 0x40; 224823183910SDouglas Gilbert arr[1] = subpcode; 224923183910SDouglas Gilbert switch (pcode) { 225023183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 225123183910SDouglas Gilbert n = 4; 225223183910SDouglas Gilbert arr[n++] = 0x0; 225323183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 225423183910SDouglas Gilbert arr[n++] = 0x0; 225523183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 225623183910SDouglas Gilbert arr[n++] = 0xd; 225723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 225823183910SDouglas Gilbert arr[n++] = 0x2f; 225923183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 226023183910SDouglas Gilbert arr[3] = n - 4; 226123183910SDouglas Gilbert break; 226223183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 226323183910SDouglas Gilbert n = 4; 226423183910SDouglas Gilbert arr[n++] = 0xd; 226523183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 226623183910SDouglas Gilbert arr[3] = n - 4; 226723183910SDouglas Gilbert break; 226823183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 226923183910SDouglas Gilbert n = 4; 227023183910SDouglas Gilbert arr[n++] = 0x2f; 227123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 227223183910SDouglas Gilbert arr[3] = n - 4; 227323183910SDouglas Gilbert break; 227423183910SDouglas Gilbert default: 227522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 227623183910SDouglas Gilbert return check_condition_result; 227723183910SDouglas Gilbert } 227823183910SDouglas Gilbert } else { 227922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 228023183910SDouglas Gilbert return check_condition_result; 228123183910SDouglas Gilbert } 2282c65b1445SDouglas Gilbert len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len); 2283c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2284c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2285c65b1445SDouglas Gilbert } 2286c65b1445SDouglas Gilbert 2287cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 228819789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 22891da177e4SLinus Torvalds { 2290c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 229122017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 22921da177e4SLinus Torvalds return check_condition_result; 22931da177e4SLinus Torvalds } 2294c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2295c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 229622017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2297cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2298c65b1445SDouglas Gilbert return check_condition_result; 2299c65b1445SDouglas Gilbert } 230019789100SFUJITA Tomonori return 0; 230119789100SFUJITA Tomonori } 230219789100SFUJITA Tomonori 2303a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2304c2248fc9SDouglas Gilbert static int 2305c2248fc9SDouglas Gilbert do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write) 230619789100SFUJITA Tomonori { 230719789100SFUJITA Tomonori int ret; 2308c2248fc9SDouglas Gilbert u64 block, rest = 0; 2309a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2310a4517511SAkinobu Mita enum dma_data_direction dir; 2311a4517511SAkinobu Mita size_t (*func)(struct scatterlist *, unsigned int, void *, size_t, 2312a4517511SAkinobu Mita off_t); 231319789100SFUJITA Tomonori 2314c2248fc9SDouglas Gilbert if (do_write) { 2315a4517511SAkinobu Mita sdb = scsi_out(scmd); 2316a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2317a4517511SAkinobu Mita func = sg_pcopy_to_buffer; 2318a4517511SAkinobu Mita } else { 2319a4517511SAkinobu Mita sdb = scsi_in(scmd); 2320a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2321a4517511SAkinobu Mita func = sg_pcopy_from_buffer; 2322a4517511SAkinobu Mita } 2323a4517511SAkinobu Mita 2324a4517511SAkinobu Mita if (!sdb->length) 2325a4517511SAkinobu Mita return 0; 2326a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2327a4517511SAkinobu Mita return -1; 232819789100SFUJITA Tomonori 232919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 233019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 233119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 233219789100SFUJITA Tomonori 2333a4517511SAkinobu Mita ret = func(sdb->table.sgl, sdb->table.nents, 2334a4517511SAkinobu Mita fake_storep + (block * scsi_debug_sector_size), 2335a4517511SAkinobu Mita (num - rest) * scsi_debug_sector_size, 0); 2336a4517511SAkinobu Mita if (ret != (num - rest) * scsi_debug_sector_size) 2337a4517511SAkinobu Mita return ret; 2338a4517511SAkinobu Mita 2339a4517511SAkinobu Mita if (rest) { 2340a4517511SAkinobu Mita ret += func(sdb->table.sgl, sdb->table.nents, 2341a4517511SAkinobu Mita fake_storep, rest * scsi_debug_sector_size, 2342597136abSMartin K. Petersen (num - rest) * scsi_debug_sector_size); 2343a4517511SAkinobu Mita } 234419789100SFUJITA Tomonori 234519789100SFUJITA Tomonori return ret; 234619789100SFUJITA Tomonori } 234719789100SFUJITA Tomonori 234838d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 234938d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 235038d5c833SDouglas Gilbert * return false. */ 235138d5c833SDouglas Gilbert static bool 235238d5c833SDouglas Gilbert comp_write_worker(u64 lba, u32 num, const u8 *arr) 235338d5c833SDouglas Gilbert { 235438d5c833SDouglas Gilbert bool res; 235538d5c833SDouglas Gilbert u64 block, rest = 0; 235638d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 235738d5c833SDouglas Gilbert u32 lb_size = scsi_debug_sector_size; 235838d5c833SDouglas Gilbert 235938d5c833SDouglas Gilbert block = do_div(lba, store_blks); 236038d5c833SDouglas Gilbert if (block + num > store_blks) 236138d5c833SDouglas Gilbert rest = block + num - store_blks; 236238d5c833SDouglas Gilbert 236338d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 236438d5c833SDouglas Gilbert (num - rest) * lb_size); 236538d5c833SDouglas Gilbert if (!res) 236638d5c833SDouglas Gilbert return res; 236738d5c833SDouglas Gilbert if (rest) 236838d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 236938d5c833SDouglas Gilbert rest * lb_size); 237038d5c833SDouglas Gilbert if (!res) 237138d5c833SDouglas Gilbert return res; 237238d5c833SDouglas Gilbert arr += num * lb_size; 237338d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 237438d5c833SDouglas Gilbert if (rest) 237538d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 237638d5c833SDouglas Gilbert rest * lb_size); 237738d5c833SDouglas Gilbert return res; 237838d5c833SDouglas Gilbert } 237938d5c833SDouglas Gilbert 238051d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2381beb40ea4SAkinobu Mita { 238251d648afSAkinobu Mita __be16 csum; 2383beb40ea4SAkinobu Mita 238451d648afSAkinobu Mita if (scsi_debug_guard) 238551d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 238651d648afSAkinobu Mita else 2387beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 238851d648afSAkinobu Mita 2389beb40ea4SAkinobu Mita return csum; 2390beb40ea4SAkinobu Mita } 2391beb40ea4SAkinobu Mita 2392beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 2393beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2394beb40ea4SAkinobu Mita { 239551d648afSAkinobu Mita __be16 csum = dif_compute_csum(data, scsi_debug_sector_size); 2396beb40ea4SAkinobu Mita 2397beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2398beb40ea4SAkinobu Mita pr_err("%s: GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2399beb40ea4SAkinobu Mita __func__, 2400beb40ea4SAkinobu Mita (unsigned long)sector, 2401beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2402beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2403beb40ea4SAkinobu Mita return 0x01; 2404beb40ea4SAkinobu Mita } 2405beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE1_PROTECTION && 2406beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2407beb40ea4SAkinobu Mita pr_err("%s: REF check failed on sector %lu\n", 2408beb40ea4SAkinobu Mita __func__, (unsigned long)sector); 2409beb40ea4SAkinobu Mita return 0x03; 2410beb40ea4SAkinobu Mita } 2411beb40ea4SAkinobu Mita if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2412beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2413beb40ea4SAkinobu Mita pr_err("%s: REF check failed on sector %lu\n", 2414beb40ea4SAkinobu Mita __func__, (unsigned long)sector); 2415beb40ea4SAkinobu Mita return 0x03; 2416beb40ea4SAkinobu Mita } 2417beb40ea4SAkinobu Mita return 0; 2418beb40ea4SAkinobu Mita } 2419beb40ea4SAkinobu Mita 2420bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 242165f72f2aSAkinobu Mita unsigned int sectors, bool read) 2422c6a44287SMartin K. Petersen { 2423be4e11beSAkinobu Mita size_t resid; 2424c6a44287SMartin K. Petersen void *paddr; 242514faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2426be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2427c6a44287SMartin K. Petersen 2428e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2429e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2430c6a44287SMartin K. Petersen 2431be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2432be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2433be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2434be4e11beSAkinobu Mita 2435be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2436be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 243714faa944SAkinobu Mita void *start = dif_store(sector); 2438be4e11beSAkinobu Mita size_t rest = 0; 243914faa944SAkinobu Mita 244014faa944SAkinobu Mita if (dif_store_end < start + len) 244114faa944SAkinobu Mita rest = start + len - dif_store_end; 2442c6a44287SMartin K. Petersen 2443be4e11beSAkinobu Mita paddr = miter.addr; 244414faa944SAkinobu Mita 244565f72f2aSAkinobu Mita if (read) 244665f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 244765f72f2aSAkinobu Mita else 244865f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 244965f72f2aSAkinobu Mita 245065f72f2aSAkinobu Mita if (rest) { 245165f72f2aSAkinobu Mita if (read) 245214faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 245365f72f2aSAkinobu Mita else 245465f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 245565f72f2aSAkinobu Mita } 2456c6a44287SMartin K. Petersen 2457e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2458c6a44287SMartin K. Petersen resid -= len; 2459c6a44287SMartin K. Petersen } 2460be4e11beSAkinobu Mita sg_miter_stop(&miter); 2461bb8c063cSAkinobu Mita } 2462c6a44287SMartin K. Petersen 2463bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2464bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2465bb8c063cSAkinobu Mita { 2466bb8c063cSAkinobu Mita unsigned int i; 2467bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 2468bb8c063cSAkinobu Mita sector_t sector; 2469bb8c063cSAkinobu Mita 2470c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2471bb8c063cSAkinobu Mita int ret; 2472bb8c063cSAkinobu Mita 2473bb8c063cSAkinobu Mita sector = start_sec + i; 2474bb8c063cSAkinobu Mita sdt = dif_store(sector); 2475bb8c063cSAkinobu Mita 247651d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2477bb8c063cSAkinobu Mita continue; 2478bb8c063cSAkinobu Mita 2479bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2480bb8c063cSAkinobu Mita if (ret) { 2481bb8c063cSAkinobu Mita dif_errors++; 2482bb8c063cSAkinobu Mita return ret; 2483bb8c063cSAkinobu Mita } 2484bb8c063cSAkinobu Mita } 2485bb8c063cSAkinobu Mita 248665f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2487c6a44287SMartin K. Petersen dix_reads++; 2488c6a44287SMartin K. Petersen 2489c6a44287SMartin K. Petersen return 0; 2490c6a44287SMartin K. Petersen } 2491c6a44287SMartin K. Petersen 2492c2248fc9SDouglas Gilbert static int 2493c2248fc9SDouglas Gilbert resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 249419789100SFUJITA Tomonori { 2495c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2496c2248fc9SDouglas Gilbert u64 lba; 2497c2248fc9SDouglas Gilbert u32 num; 2498c2248fc9SDouglas Gilbert u32 ei_lba; 249919789100SFUJITA Tomonori unsigned long iflags; 250019789100SFUJITA Tomonori int ret; 2501c2248fc9SDouglas Gilbert bool check_prot; 250219789100SFUJITA Tomonori 2503c2248fc9SDouglas Gilbert switch (cmd[0]) { 2504c2248fc9SDouglas Gilbert case READ_16: 2505c2248fc9SDouglas Gilbert ei_lba = 0; 2506c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2507c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2508c2248fc9SDouglas Gilbert check_prot = true; 2509c2248fc9SDouglas Gilbert break; 2510c2248fc9SDouglas Gilbert case READ_10: 2511c2248fc9SDouglas Gilbert ei_lba = 0; 2512c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2513c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2514c2248fc9SDouglas Gilbert check_prot = true; 2515c2248fc9SDouglas Gilbert break; 2516c2248fc9SDouglas Gilbert case READ_6: 2517c2248fc9SDouglas Gilbert ei_lba = 0; 2518c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2519c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2520c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2521c2248fc9SDouglas Gilbert check_prot = true; 2522c2248fc9SDouglas Gilbert break; 2523c2248fc9SDouglas Gilbert case READ_12: 2524c2248fc9SDouglas Gilbert ei_lba = 0; 2525c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2526c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2527c2248fc9SDouglas Gilbert check_prot = true; 2528c2248fc9SDouglas Gilbert break; 2529c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2530c2248fc9SDouglas Gilbert ei_lba = 0; 2531c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2532c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2533c2248fc9SDouglas Gilbert check_prot = false; 2534c2248fc9SDouglas Gilbert break; 2535c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2536c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2537c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2538c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2539c2248fc9SDouglas Gilbert check_prot = false; 2540c2248fc9SDouglas Gilbert break; 2541c2248fc9SDouglas Gilbert } 2542c2248fc9SDouglas Gilbert if (check_prot) { 2543c2248fc9SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2544c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2545c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2546c2248fc9SDouglas Gilbert return check_condition_result; 2547c2248fc9SDouglas Gilbert } 2548c2248fc9SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 2549c2248fc9SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 2550c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2551c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2552c2248fc9SDouglas Gilbert "to DIF device\n"); 2553c2248fc9SDouglas Gilbert } 2554c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2555c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2556c2248fc9SDouglas Gilbert 2557c2248fc9SDouglas Gilbert if (ep->inj_short) 2558c2248fc9SDouglas Gilbert num /= 2; 2559c2248fc9SDouglas Gilbert } 2560c2248fc9SDouglas Gilbert 2561c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2562c2248fc9SDouglas Gilbert if (lba + num > sdebug_capacity) { 2563c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2564c2248fc9SDouglas Gilbert return check_condition_result; 2565c2248fc9SDouglas Gilbert } 2566c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2567c2248fc9SDouglas Gilbert if (num > sdebug_store_sectors) { 2568c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2569c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2570c2248fc9SDouglas Gilbert return check_condition_result; 2571c2248fc9SDouglas Gilbert } 257219789100SFUJITA Tomonori 25731da177e4SLinus Torvalds if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) && 257432f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2575c65b1445SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR)) { 2576c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2577c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2578c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2579c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2580c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 258132f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 258232f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2583c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2584c65b1445SDouglas Gilbert } 2585c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 25861da177e4SLinus Torvalds return check_condition_result; 25871da177e4SLinus Torvalds } 2588c6a44287SMartin K. Petersen 25896c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 25906c78cc06SAkinobu Mita 2591c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2592c2248fc9SDouglas Gilbert if (scsi_debug_dix && scsi_prot_sg_count(scp)) { 2593c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2594c6a44287SMartin K. Petersen 2595c6a44287SMartin K. Petersen if (prot_ret) { 25966c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2597c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2598c6a44287SMartin K. Petersen return illegal_condition_result; 2599c6a44287SMartin K. Petersen } 2600c6a44287SMartin K. Petersen } 2601c6a44287SMartin K. Petersen 2602c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 26031da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2604a4517511SAkinobu Mita if (ret == -1) 2605a4517511SAkinobu Mita return DID_ERROR << 16; 2606a4517511SAkinobu Mita 2607c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2608a4517511SAkinobu Mita 2609c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2610c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2611c2248fc9SDouglas Gilbert 2612c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2613c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2614c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2615c2248fc9SDouglas Gilbert return check_condition_result; 2616c2248fc9SDouglas Gilbert } else if (ep->inj_transport) { 2617c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2618c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2619c2248fc9SDouglas Gilbert return check_condition_result; 2620c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2621c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2622c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2623c2248fc9SDouglas Gilbert return illegal_condition_result; 2624c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2625c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2626c2248fc9SDouglas Gilbert return illegal_condition_result; 2627c2248fc9SDouglas Gilbert } 2628c2248fc9SDouglas Gilbert } 2629a4517511SAkinobu Mita return 0; 26301da177e4SLinus Torvalds } 26311da177e4SLinus Torvalds 2632c6a44287SMartin K. Petersen void dump_sector(unsigned char *buf, int len) 2633c6a44287SMartin K. Petersen { 2634cbf67842SDouglas Gilbert int i, j, n; 2635c6a44287SMartin K. Petersen 2636cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2637c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2638cbf67842SDouglas Gilbert char b[128]; 2639c6a44287SMartin K. Petersen 2640cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2641c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2642c6a44287SMartin K. Petersen 2643cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2644cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2645cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2646cbf67842SDouglas Gilbert else 2647cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2648cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2649cbf67842SDouglas Gilbert } 2650cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2651c6a44287SMartin K. Petersen } 2652c6a44287SMartin K. Petersen } 2653c6a44287SMartin K. Petersen 2654c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2655395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2656c6a44287SMartin K. Petersen { 2657be4e11beSAkinobu Mita int ret; 2658c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 2659be4e11beSAkinobu Mita void *daddr; 266065f72f2aSAkinobu Mita sector_t sector = start_sec; 2661c6a44287SMartin K. Petersen int ppage_offset; 2662be4e11beSAkinobu Mita int dpage_offset; 2663be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2664be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2665c6a44287SMartin K. Petersen 2666c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2667c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2668c6a44287SMartin K. Petersen 2669be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2670be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2671be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2672be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2673be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2674c6a44287SMartin K. Petersen 2675be4e11beSAkinobu Mita /* For each protection page */ 2676be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2677be4e11beSAkinobu Mita dpage_offset = 0; 2678be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2679be4e11beSAkinobu Mita ret = 0x01; 2680be4e11beSAkinobu Mita goto out; 2681c6a44287SMartin K. Petersen } 2682c6a44287SMartin K. Petersen 2683be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 2684be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 2685be4e11beSAkinobu Mita /* If we're at the end of the current 2686be4e11beSAkinobu Mita * data page advance to the next one 2687be4e11beSAkinobu Mita */ 2688be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2689be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2690be4e11beSAkinobu Mita ret = 0x01; 2691be4e11beSAkinobu Mita goto out; 2692be4e11beSAkinobu Mita } 2693be4e11beSAkinobu Mita dpage_offset = 0; 2694be4e11beSAkinobu Mita } 2695c6a44287SMartin K. Petersen 2696be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2697be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2698be4e11beSAkinobu Mita 2699be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2700beb40ea4SAkinobu Mita if (ret) { 2701be4e11beSAkinobu Mita dump_sector(daddr, scsi_debug_sector_size); 2702395cef03SMartin K. Petersen goto out; 2703395cef03SMartin K. Petersen } 2704395cef03SMartin K. Petersen 2705c6a44287SMartin K. Petersen sector++; 2706395cef03SMartin K. Petersen ei_lba++; 2707be4e11beSAkinobu Mita dpage_offset += scsi_debug_sector_size; 2708c6a44287SMartin K. Petersen } 2709be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2710be4e11beSAkinobu Mita sg_miter_stop(&diter); 2711c6a44287SMartin K. Petersen } 2712be4e11beSAkinobu Mita sg_miter_stop(&piter); 2713c6a44287SMartin K. Petersen 271465f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2715c6a44287SMartin K. Petersen dix_writes++; 2716c6a44287SMartin K. Petersen 2717c6a44287SMartin K. Petersen return 0; 2718c6a44287SMartin K. Petersen 2719c6a44287SMartin K. Petersen out: 2720c6a44287SMartin K. Petersen dif_errors++; 2721be4e11beSAkinobu Mita sg_miter_stop(&diter); 2722be4e11beSAkinobu Mita sg_miter_stop(&piter); 2723c6a44287SMartin K. Petersen return ret; 2724c6a44287SMartin K. Petersen } 2725c6a44287SMartin K. Petersen 2726b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2727b90ebc3dSAkinobu Mita { 2728b90ebc3dSAkinobu Mita if (scsi_debug_unmap_alignment) { 2729b90ebc3dSAkinobu Mita lba += scsi_debug_unmap_granularity - 2730b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2731b90ebc3dSAkinobu Mita } 2732b90ebc3dSAkinobu Mita do_div(lba, scsi_debug_unmap_granularity); 2733b90ebc3dSAkinobu Mita 2734b90ebc3dSAkinobu Mita return lba; 2735b90ebc3dSAkinobu Mita } 2736b90ebc3dSAkinobu Mita 2737b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2738b90ebc3dSAkinobu Mita { 2739a027b5b9SAkinobu Mita sector_t lba = index * scsi_debug_unmap_granularity; 2740a027b5b9SAkinobu Mita 2741a027b5b9SAkinobu Mita if (scsi_debug_unmap_alignment) { 2742a027b5b9SAkinobu Mita lba -= scsi_debug_unmap_granularity - 2743b90ebc3dSAkinobu Mita scsi_debug_unmap_alignment; 2744b90ebc3dSAkinobu Mita } 2745b90ebc3dSAkinobu Mita 2746a027b5b9SAkinobu Mita return lba; 2747a027b5b9SAkinobu Mita } 2748a027b5b9SAkinobu Mita 274944d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 275044d92694SMartin K. Petersen { 2751b90ebc3dSAkinobu Mita sector_t end; 2752b90ebc3dSAkinobu Mita unsigned int mapped; 2753b90ebc3dSAkinobu Mita unsigned long index; 2754b90ebc3dSAkinobu Mita unsigned long next; 275544d92694SMartin K. Petersen 2756b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2757b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 275844d92694SMartin K. Petersen 275944d92694SMartin K. Petersen if (mapped) 2760b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 276144d92694SMartin K. Petersen else 2762b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 276344d92694SMartin K. Petersen 2764b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 276544d92694SMartin K. Petersen *num = end - lba; 276644d92694SMartin K. Petersen 276744d92694SMartin K. Petersen return mapped; 276844d92694SMartin K. Petersen } 276944d92694SMartin K. Petersen 277044d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 277144d92694SMartin K. Petersen { 277244d92694SMartin K. Petersen sector_t end = lba + len; 277344d92694SMartin K. Petersen 277444d92694SMartin K. Petersen while (lba < end) { 2775b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 277644d92694SMartin K. Petersen 2777b90ebc3dSAkinobu Mita if (index < map_size) 2778b90ebc3dSAkinobu Mita set_bit(index, map_storep); 277944d92694SMartin K. Petersen 2780b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 278144d92694SMartin K. Petersen } 278244d92694SMartin K. Petersen } 278344d92694SMartin K. Petersen 278444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 278544d92694SMartin K. Petersen { 278644d92694SMartin K. Petersen sector_t end = lba + len; 278744d92694SMartin K. Petersen 278844d92694SMartin K. Petersen while (lba < end) { 2789b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 279044d92694SMartin K. Petersen 2791b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2792b90ebc3dSAkinobu Mita lba + scsi_debug_unmap_granularity <= end && 2793b90ebc3dSAkinobu Mita index < map_size) { 2794b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2795b90ebc3dSAkinobu Mita if (scsi_debug_lbprz) { 2796be1dd78dSEric Sandeen memset(fake_storep + 2797cc34a8e6SAkinobu Mita lba * scsi_debug_sector_size, 0, 2798cc34a8e6SAkinobu Mita scsi_debug_sector_size * 2799cc34a8e6SAkinobu Mita scsi_debug_unmap_granularity); 2800be1dd78dSEric Sandeen } 2801e9926b43SAkinobu Mita if (dif_storep) { 2802e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2803e9926b43SAkinobu Mita sizeof(*dif_storep) * 2804e9926b43SAkinobu Mita scsi_debug_unmap_granularity); 2805e9926b43SAkinobu Mita } 2806b90ebc3dSAkinobu Mita } 2807b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 280844d92694SMartin K. Petersen } 280944d92694SMartin K. Petersen } 281044d92694SMartin K. Petersen 2811c2248fc9SDouglas Gilbert static int 2812c2248fc9SDouglas Gilbert resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 28131da177e4SLinus Torvalds { 2814c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2815c2248fc9SDouglas Gilbert u64 lba; 2816c2248fc9SDouglas Gilbert u32 num; 2817c2248fc9SDouglas Gilbert u32 ei_lba; 28181da177e4SLinus Torvalds unsigned long iflags; 281919789100SFUJITA Tomonori int ret; 2820c2248fc9SDouglas Gilbert bool check_prot; 28211da177e4SLinus Torvalds 2822c2248fc9SDouglas Gilbert switch (cmd[0]) { 2823c2248fc9SDouglas Gilbert case WRITE_16: 2824c2248fc9SDouglas Gilbert ei_lba = 0; 2825c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2826c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2827c2248fc9SDouglas Gilbert check_prot = true; 2828c2248fc9SDouglas Gilbert break; 2829c2248fc9SDouglas Gilbert case WRITE_10: 2830c2248fc9SDouglas Gilbert ei_lba = 0; 2831c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2832c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2833c2248fc9SDouglas Gilbert check_prot = true; 2834c2248fc9SDouglas Gilbert break; 2835c2248fc9SDouglas Gilbert case WRITE_6: 2836c2248fc9SDouglas Gilbert ei_lba = 0; 2837c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2838c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2839c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2840c2248fc9SDouglas Gilbert check_prot = true; 2841c2248fc9SDouglas Gilbert break; 2842c2248fc9SDouglas Gilbert case WRITE_12: 2843c2248fc9SDouglas Gilbert ei_lba = 0; 2844c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2845c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2846c2248fc9SDouglas Gilbert check_prot = true; 2847c2248fc9SDouglas Gilbert break; 2848c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2849c2248fc9SDouglas Gilbert ei_lba = 0; 2850c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2851c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2852c2248fc9SDouglas Gilbert check_prot = false; 2853c2248fc9SDouglas Gilbert break; 2854c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2855c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2856c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2857c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2858c2248fc9SDouglas Gilbert check_prot = false; 2859c2248fc9SDouglas Gilbert break; 2860c2248fc9SDouglas Gilbert } 2861c2248fc9SDouglas Gilbert if (check_prot) { 2862c2248fc9SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 2863c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2864c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2865c2248fc9SDouglas Gilbert return check_condition_result; 2866c2248fc9SDouglas Gilbert } 2867c2248fc9SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 2868c2248fc9SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 2869c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2870c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2871c2248fc9SDouglas Gilbert "to DIF device\n"); 2872c2248fc9SDouglas Gilbert } 2873c2248fc9SDouglas Gilbert 2874c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2875c2248fc9SDouglas Gilbert if (lba + num > sdebug_capacity) { 2876c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2877c2248fc9SDouglas Gilbert return check_condition_result; 2878c2248fc9SDouglas Gilbert } 2879c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2880c2248fc9SDouglas Gilbert if (num > sdebug_store_sectors) { 2881c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2882c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2883c2248fc9SDouglas Gilbert return check_condition_result; 2884c2248fc9SDouglas Gilbert } 28851da177e4SLinus Torvalds 28866c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 28876c78cc06SAkinobu Mita 2888c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2889c2248fc9SDouglas Gilbert if (scsi_debug_dix && scsi_prot_sg_count(scp)) { 2890c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2891c6a44287SMartin K. Petersen 2892c6a44287SMartin K. Petersen if (prot_ret) { 28936c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2894c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2895c6a44287SMartin K. Petersen return illegal_condition_result; 2896c6a44287SMartin K. Petersen } 2897c6a44287SMartin K. Petersen } 2898c6a44287SMartin K. Petersen 2899c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 29009ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 290144d92694SMartin K. Petersen map_region(lba, num); 29021da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 290319789100SFUJITA Tomonori if (-1 == ret) 29041da177e4SLinus Torvalds return (DID_ERROR << 16); 2905597136abSMartin K. Petersen else if ((ret < (num * scsi_debug_sector_size)) && 29061da177e4SLinus Torvalds (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2907c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2908cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2909cbf67842SDouglas Gilbert my_name, num * scsi_debug_sector_size, ret); 291044d92694SMartin K. Petersen 2911c2248fc9SDouglas Gilbert if (sdebug_any_injecting_opt) { 2912c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2913c2248fc9SDouglas Gilbert 2914c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2915c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2916c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2917c2248fc9SDouglas Gilbert return check_condition_result; 2918c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2919c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2920c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2921c2248fc9SDouglas Gilbert return illegal_condition_result; 2922c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2923c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2924c2248fc9SDouglas Gilbert return illegal_condition_result; 2925c2248fc9SDouglas Gilbert } 2926c2248fc9SDouglas Gilbert } 29271da177e4SLinus Torvalds return 0; 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds 2930c2248fc9SDouglas Gilbert static int 2931c2248fc9SDouglas Gilbert resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba, 2932c2248fc9SDouglas Gilbert bool unmap, bool ndob) 293344d92694SMartin K. Petersen { 293444d92694SMartin K. Petersen unsigned long iflags; 293544d92694SMartin K. Petersen unsigned long long i; 293644d92694SMartin K. Petersen int ret; 293744d92694SMartin K. Petersen 2938c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 293944d92694SMartin K. Petersen if (ret) 294044d92694SMartin K. Petersen return ret; 294144d92694SMartin K. Petersen 294244d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 294344d92694SMartin K. Petersen 29449ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 294544d92694SMartin K. Petersen unmap_region(lba, num); 294644d92694SMartin K. Petersen goto out; 294744d92694SMartin K. Petersen } 294844d92694SMartin K. Petersen 2949c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 2950c2248fc9SDouglas Gilbert if (ndob) { 2951c2248fc9SDouglas Gilbert memset(fake_storep + (lba * scsi_debug_sector_size), 0, 2952c2248fc9SDouglas Gilbert scsi_debug_sector_size); 2953c2248fc9SDouglas Gilbert ret = 0; 2954c2248fc9SDouglas Gilbert } else 2955c2248fc9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + 2956c2248fc9SDouglas Gilbert (lba * scsi_debug_sector_size), 295744d92694SMartin K. Petersen scsi_debug_sector_size); 295844d92694SMartin K. Petersen 295944d92694SMartin K. Petersen if (-1 == ret) { 296044d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 296144d92694SMartin K. Petersen return (DID_ERROR << 16); 296244d92694SMartin K. Petersen } else if ((ret < (num * scsi_debug_sector_size)) && 296344d92694SMartin K. Petersen (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 2964c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2965cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 2966cbf67842SDouglas Gilbert my_name, "write same", 2967cbf67842SDouglas Gilbert num * scsi_debug_sector_size, ret); 296844d92694SMartin K. Petersen 296944d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 297044d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 297144d92694SMartin K. Petersen memcpy(fake_storep + ((lba + i) * scsi_debug_sector_size), 297244d92694SMartin K. Petersen fake_storep + (lba * scsi_debug_sector_size), 297344d92694SMartin K. Petersen scsi_debug_sector_size); 297444d92694SMartin K. Petersen 29759ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 297644d92694SMartin K. Petersen map_region(lba, num); 297744d92694SMartin K. Petersen out: 297844d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 297944d92694SMartin K. Petersen 298044d92694SMartin K. Petersen return 0; 298144d92694SMartin K. Petersen } 298244d92694SMartin K. Petersen 2983c2248fc9SDouglas Gilbert static int 2984c2248fc9SDouglas Gilbert resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 2985c2248fc9SDouglas Gilbert { 2986c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2987c2248fc9SDouglas Gilbert u32 lba; 2988c2248fc9SDouglas Gilbert u16 num; 2989c2248fc9SDouglas Gilbert u32 ei_lba = 0; 2990c2248fc9SDouglas Gilbert bool unmap = false; 2991c2248fc9SDouglas Gilbert 2992c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 2993c2248fc9SDouglas Gilbert if (scsi_debug_lbpws10 == 0) { 2994c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 2995c2248fc9SDouglas Gilbert return check_condition_result; 2996c2248fc9SDouglas Gilbert } else 2997c2248fc9SDouglas Gilbert unmap = true; 2998c2248fc9SDouglas Gilbert } 2999c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3000c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3001c2248fc9SDouglas Gilbert if (num > scsi_debug_write_same_length) { 3002c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3003c2248fc9SDouglas Gilbert return check_condition_result; 3004c2248fc9SDouglas Gilbert } 3005c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3006c2248fc9SDouglas Gilbert } 3007c2248fc9SDouglas Gilbert 3008c2248fc9SDouglas Gilbert static int 3009c2248fc9SDouglas Gilbert resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3010c2248fc9SDouglas Gilbert { 3011c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3012c2248fc9SDouglas Gilbert u64 lba; 3013c2248fc9SDouglas Gilbert u32 num; 3014c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3015c2248fc9SDouglas Gilbert bool unmap = false; 3016c2248fc9SDouglas Gilbert bool ndob = false; 3017c2248fc9SDouglas Gilbert 3018c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3019c2248fc9SDouglas Gilbert if (scsi_debug_lbpws == 0) { 3020c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3021c2248fc9SDouglas Gilbert return check_condition_result; 3022c2248fc9SDouglas Gilbert } else 3023c2248fc9SDouglas Gilbert unmap = true; 3024c2248fc9SDouglas Gilbert } 3025c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3026c2248fc9SDouglas Gilbert ndob = true; 3027c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3028c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3029c2248fc9SDouglas Gilbert if (num > scsi_debug_write_same_length) { 3030c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3031c2248fc9SDouglas Gilbert return check_condition_result; 3032c2248fc9SDouglas Gilbert } 3033c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3034c2248fc9SDouglas Gilbert } 3035c2248fc9SDouglas Gilbert 303638d5c833SDouglas Gilbert static int 303738d5c833SDouglas Gilbert resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 303838d5c833SDouglas Gilbert { 303938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 304038d5c833SDouglas Gilbert u8 *arr; 304138d5c833SDouglas Gilbert u8 *fake_storep_hold; 304238d5c833SDouglas Gilbert u64 lba; 304338d5c833SDouglas Gilbert u32 dnum; 304438d5c833SDouglas Gilbert u32 lb_size = scsi_debug_sector_size; 304538d5c833SDouglas Gilbert u8 num; 304638d5c833SDouglas Gilbert unsigned long iflags; 304738d5c833SDouglas Gilbert int ret; 3048d467d31fSDouglas Gilbert int retval = 0; 304938d5c833SDouglas Gilbert 3050d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 305138d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 305238d5c833SDouglas Gilbert if (0 == num) 305338d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 305438d5c833SDouglas Gilbert if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION && 305538d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 305638d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 305738d5c833SDouglas Gilbert return check_condition_result; 305838d5c833SDouglas Gilbert } 305938d5c833SDouglas Gilbert if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION || 306038d5c833SDouglas Gilbert scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) && 306138d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 306238d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 306338d5c833SDouglas Gilbert "to DIF device\n"); 306438d5c833SDouglas Gilbert 306538d5c833SDouglas Gilbert /* inline check_device_access_params() */ 306638d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 306738d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 306838d5c833SDouglas Gilbert return check_condition_result; 306938d5c833SDouglas Gilbert } 307038d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 307138d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 307238d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 307338d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 307438d5c833SDouglas Gilbert return check_condition_result; 307538d5c833SDouglas Gilbert } 3076d467d31fSDouglas Gilbert dnum = 2 * num; 3077d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3078d467d31fSDouglas Gilbert if (NULL == arr) { 3079d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3080d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3081d467d31fSDouglas Gilbert return check_condition_result; 3082d467d31fSDouglas Gilbert } 308338d5c833SDouglas Gilbert 308438d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 308538d5c833SDouglas Gilbert 308638d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 308738d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 308838d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 308938d5c833SDouglas Gilbert fake_storep = arr; 309038d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 309138d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 309238d5c833SDouglas Gilbert if (ret == -1) { 3093d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3094d467d31fSDouglas Gilbert goto cleanup; 309538d5c833SDouglas Gilbert } else if ((ret < (dnum * lb_size)) && 309638d5c833SDouglas Gilbert (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 309738d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 309838d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 309938d5c833SDouglas Gilbert dnum * lb_size, ret); 310038d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 310138d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3102d467d31fSDouglas Gilbert retval = check_condition_result; 3103d467d31fSDouglas Gilbert goto cleanup; 310438d5c833SDouglas Gilbert } 310538d5c833SDouglas Gilbert if (scsi_debug_lbp()) 310638d5c833SDouglas Gilbert map_region(lba, num); 3107d467d31fSDouglas Gilbert cleanup: 310838d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3109d467d31fSDouglas Gilbert kfree(arr); 3110d467d31fSDouglas Gilbert return retval; 311138d5c833SDouglas Gilbert } 311238d5c833SDouglas Gilbert 311344d92694SMartin K. Petersen struct unmap_block_desc { 311444d92694SMartin K. Petersen __be64 lba; 311544d92694SMartin K. Petersen __be32 blocks; 311644d92694SMartin K. Petersen __be32 __reserved; 311744d92694SMartin K. Petersen }; 311844d92694SMartin K. Petersen 3119c2248fc9SDouglas Gilbert static int 3120c2248fc9SDouglas Gilbert resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 312144d92694SMartin K. Petersen { 312244d92694SMartin K. Petersen unsigned char *buf; 312344d92694SMartin K. Petersen struct unmap_block_desc *desc; 312444d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 312544d92694SMartin K. Petersen int ret; 31266c78cc06SAkinobu Mita unsigned long iflags; 312744d92694SMartin K. Petersen 312844d92694SMartin K. Petersen 3129c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3130c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3131c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3132c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 313344d92694SMartin K. Petersen 313444d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3135c2248fc9SDouglas Gilbert if (descriptors > scsi_debug_unmap_max_desc) { 3136c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 313744d92694SMartin K. Petersen return check_condition_result; 3138c2248fc9SDouglas Gilbert } 313944d92694SMartin K. Petersen 3140c2248fc9SDouglas Gilbert buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 3141c2248fc9SDouglas Gilbert if (!buf) { 3142c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3143c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3144c2248fc9SDouglas Gilbert return check_condition_result; 3145c2248fc9SDouglas Gilbert } 3146c2248fc9SDouglas Gilbert 3147c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 314844d92694SMartin K. Petersen 314944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 315044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 315144d92694SMartin K. Petersen 315244d92694SMartin K. Petersen desc = (void *)&buf[8]; 315344d92694SMartin K. Petersen 31546c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 31556c78cc06SAkinobu Mita 315644d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 315744d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 315844d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 315944d92694SMartin K. Petersen 3160c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 316144d92694SMartin K. Petersen if (ret) 316244d92694SMartin K. Petersen goto out; 316344d92694SMartin K. Petersen 316444d92694SMartin K. Petersen unmap_region(lba, num); 316544d92694SMartin K. Petersen } 316644d92694SMartin K. Petersen 316744d92694SMartin K. Petersen ret = 0; 316844d92694SMartin K. Petersen 316944d92694SMartin K. Petersen out: 31706c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 317144d92694SMartin K. Petersen kfree(buf); 317244d92694SMartin K. Petersen 317344d92694SMartin K. Petersen return ret; 317444d92694SMartin K. Petersen } 317544d92694SMartin K. Petersen 317644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 317744d92694SMartin K. Petersen 3178c2248fc9SDouglas Gilbert static int 3179c2248fc9SDouglas Gilbert resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 318044d92694SMartin K. Petersen { 3181c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3182c2248fc9SDouglas Gilbert u64 lba; 3183c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3184c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 318544d92694SMartin K. Petersen int ret; 318644d92694SMartin K. Petersen 3187c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3188c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 318944d92694SMartin K. Petersen 319044d92694SMartin K. Petersen if (alloc_len < 24) 319144d92694SMartin K. Petersen return 0; 319244d92694SMartin K. Petersen 3193c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 319444d92694SMartin K. Petersen if (ret) 319544d92694SMartin K. Petersen return ret; 319644d92694SMartin K. Petersen 3197c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 319844d92694SMartin K. Petersen mapped = map_state(lba, &num); 3199c2248fc9SDouglas Gilbert else { 3200c2248fc9SDouglas Gilbert mapped = 1; 3201c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3202c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3203c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3204c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3205c2248fc9SDouglas Gilbert else 3206c2248fc9SDouglas Gilbert num = 0xffffffff; 3207c2248fc9SDouglas Gilbert } 320844d92694SMartin K. Petersen 320944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3210c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3211c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3212c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3213c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 321444d92694SMartin K. Petersen 3215c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 321644d92694SMartin K. Petersen } 321744d92694SMartin K. Petersen 3218c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 32191da177e4SLinus Torvalds 32201da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 32211da177e4SLinus Torvalds struct sdebug_dev_info * devip) 32221da177e4SLinus Torvalds { 32231da177e4SLinus Torvalds unsigned int alloc_len; 322422017ed2SDouglas Gilbert int lun_cnt, i, upper, num, n, want_wlun, shortish; 322522017ed2SDouglas Gilbert u64 lun; 322601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 32271da177e4SLinus Torvalds int select_report = (int)cmd[2]; 32281da177e4SLinus Torvalds struct scsi_lun *one_lun; 32291da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 3230c65b1445SDouglas Gilbert unsigned char * max_addr; 32311da177e4SLinus Torvalds 32321da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 323322017ed2SDouglas Gilbert shortish = (alloc_len < 4); 323422017ed2SDouglas Gilbert if (shortish || (select_report > 2)) { 323522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1); 32361da177e4SLinus Torvalds return check_condition_result; 32371da177e4SLinus Torvalds } 32381da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 32391da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 32401da177e4SLinus Torvalds lun_cnt = scsi_debug_max_luns; 3241c65b1445SDouglas Gilbert if (1 == select_report) 3242c65b1445SDouglas Gilbert lun_cnt = 0; 3243c65b1445SDouglas Gilbert else if (scsi_debug_no_lun_0 && (lun_cnt > 0)) 3244c65b1445SDouglas Gilbert --lun_cnt; 324522017ed2SDouglas Gilbert want_wlun = (select_report > 0) ? 1 : 0; 324622017ed2SDouglas Gilbert num = lun_cnt + want_wlun; 3247c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 3248c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 3249c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 3250c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 3251c65b1445SDouglas Gilbert if (n < num) { 325222017ed2SDouglas Gilbert want_wlun = 0; 3253c65b1445SDouglas Gilbert lun_cnt = n; 3254c65b1445SDouglas Gilbert } 32551da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 3256c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 3257c65b1445SDouglas Gilbert for (i = 0, lun = (scsi_debug_no_lun_0 ? 1 : 0); 3258c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 3259c65b1445SDouglas Gilbert i++, lun++) { 3260c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 32611da177e4SLinus Torvalds if (upper) 32621da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 32631da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 3264c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 32651da177e4SLinus Torvalds } 326622017ed2SDouglas Gilbert if (want_wlun) { 3267c65b1445SDouglas Gilbert one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff; 3268c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff; 3269c65b1445SDouglas Gilbert i++; 3270c65b1445SDouglas Gilbert } 3271c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 32721da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 32731da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 32741da177e4SLinus Torvalds } 32751da177e4SLinus Torvalds 3276c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3277c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3278c639d14eSFUJITA Tomonori { 3279be4e11beSAkinobu Mita int j; 3280c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3281c639d14eSFUJITA Tomonori unsigned int offset; 3282c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3283be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3284c639d14eSFUJITA Tomonori 3285c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3286c639d14eSFUJITA Tomonori buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC); 3287c5af0db9SAkinobu Mita if (!buf) { 328822017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 328922017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3290c5af0db9SAkinobu Mita return check_condition_result; 3291c5af0db9SAkinobu Mita } 3292c639d14eSFUJITA Tomonori 329321a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3294c639d14eSFUJITA Tomonori 3295c639d14eSFUJITA Tomonori offset = 0; 3296be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3297be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3298c639d14eSFUJITA Tomonori 3299be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3300be4e11beSAkinobu Mita kaddr = miter.addr; 3301be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3302be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3303c639d14eSFUJITA Tomonori 3304be4e11beSAkinobu Mita offset += miter.length; 3305c639d14eSFUJITA Tomonori } 3306be4e11beSAkinobu Mita sg_miter_stop(&miter); 3307c639d14eSFUJITA Tomonori kfree(buf); 3308c639d14eSFUJITA Tomonori 3309be4e11beSAkinobu Mita return 0; 3310c639d14eSFUJITA Tomonori } 3311c639d14eSFUJITA Tomonori 3312c2248fc9SDouglas Gilbert static int 3313c2248fc9SDouglas Gilbert resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3314c2248fc9SDouglas Gilbert { 3315c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3316c2248fc9SDouglas Gilbert u64 lba; 3317c2248fc9SDouglas Gilbert u32 num; 3318c2248fc9SDouglas Gilbert int errsts; 3319c2248fc9SDouglas Gilbert 3320c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3321c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3322c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3323c2248fc9SDouglas Gilbert return check_condition_result; 3324c2248fc9SDouglas Gilbert } 3325c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3326c2248fc9SDouglas Gilbert if (errsts) 3327c2248fc9SDouglas Gilbert return errsts; 3328c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3329c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3330c2248fc9SDouglas Gilbert if (errsts) 3331c2248fc9SDouglas Gilbert return errsts; 3332c2248fc9SDouglas Gilbert } 3333c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3334c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3335c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3336c2248fc9SDouglas Gilbert } 3337c2248fc9SDouglas Gilbert 3338cbf67842SDouglas Gilbert /* When timer or tasklet goes off this function is called. */ 3339cbf67842SDouglas Gilbert static void sdebug_q_cmd_complete(unsigned long indx) 33401da177e4SLinus Torvalds { 3341cbf67842SDouglas Gilbert int qa_indx; 3342cbf67842SDouglas Gilbert int retiring = 0; 33431da177e4SLinus Torvalds unsigned long iflags; 3344cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3345cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3346cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 33471da177e4SLinus Torvalds 3348cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3349cbf67842SDouglas Gilbert qa_indx = indx; 3350cbf67842SDouglas Gilbert if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { 3351cbf67842SDouglas Gilbert pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx); 33521da177e4SLinus Torvalds return; 33531da177e4SLinus Torvalds } 33541da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3355cbf67842SDouglas Gilbert sqcp = &queued_arr[qa_indx]; 3356cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3357cbf67842SDouglas Gilbert if (NULL == scp) { 33581da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3359cbf67842SDouglas Gilbert pr_err("%s: scp is NULL\n", __func__); 33601da177e4SLinus Torvalds return; 33611da177e4SLinus Torvalds } 3362cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3363cbf67842SDouglas Gilbert if (devip) 3364cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3365cbf67842SDouglas Gilbert else 3366cbf67842SDouglas Gilbert pr_err("%s: devip=NULL\n", __func__); 3367cbf67842SDouglas Gilbert if (atomic_read(&retired_max_queue) > 0) 3368cbf67842SDouglas Gilbert retiring = 1; 3369cbf67842SDouglas Gilbert 3370cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3371cbf67842SDouglas Gilbert if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { 33721da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3373cbf67842SDouglas Gilbert pr_err("%s: Unexpected completion\n", __func__); 3374cbf67842SDouglas Gilbert return; 33751da177e4SLinus Torvalds } 33761da177e4SLinus Torvalds 3377cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3378cbf67842SDouglas Gilbert int k, retval; 3379cbf67842SDouglas Gilbert 3380cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3381cbf67842SDouglas Gilbert if (qa_indx >= retval) { 3382cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3383cbf67842SDouglas Gilbert pr_err("%s: index %d too large\n", __func__, retval); 3384cbf67842SDouglas Gilbert return; 3385cbf67842SDouglas Gilbert } 3386cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, retval); 3387cbf67842SDouglas Gilbert if ((k < scsi_debug_max_queue) || (k == retval)) 3388cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3389cbf67842SDouglas Gilbert else 3390cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3391cbf67842SDouglas Gilbert } 3392cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3393cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3394cbf67842SDouglas Gilbert } 3395cbf67842SDouglas Gilbert 3396cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3397cbf67842SDouglas Gilbert static enum hrtimer_restart 3398cbf67842SDouglas Gilbert sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3399cbf67842SDouglas Gilbert { 3400cbf67842SDouglas Gilbert int qa_indx; 3401cbf67842SDouglas Gilbert int retiring = 0; 3402cbf67842SDouglas Gilbert unsigned long iflags; 3403cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hrtp = (struct sdebug_hrtimer *)timer; 3404cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3405cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3406cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3407cbf67842SDouglas Gilbert 3408cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3409cbf67842SDouglas Gilbert qa_indx = sd_hrtp->qa_indx; 3410cbf67842SDouglas Gilbert if ((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE)) { 3411cbf67842SDouglas Gilbert pr_err("%s: wild qa_indx=%d\n", __func__, qa_indx); 3412cbf67842SDouglas Gilbert goto the_end; 3413cbf67842SDouglas Gilbert } 3414cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 3415cbf67842SDouglas Gilbert sqcp = &queued_arr[qa_indx]; 3416cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3417cbf67842SDouglas Gilbert if (NULL == scp) { 3418cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3419cbf67842SDouglas Gilbert pr_err("%s: scp is NULL\n", __func__); 3420cbf67842SDouglas Gilbert goto the_end; 3421cbf67842SDouglas Gilbert } 3422cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3423cbf67842SDouglas Gilbert if (devip) 3424cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3425cbf67842SDouglas Gilbert else 3426cbf67842SDouglas Gilbert pr_err("%s: devip=NULL\n", __func__); 3427cbf67842SDouglas Gilbert if (atomic_read(&retired_max_queue) > 0) 3428cbf67842SDouglas Gilbert retiring = 1; 3429cbf67842SDouglas Gilbert 3430cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3431cbf67842SDouglas Gilbert if (!test_and_clear_bit(qa_indx, queued_in_use_bm)) { 3432cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3433cbf67842SDouglas Gilbert pr_err("%s: Unexpected completion\n", __func__); 3434cbf67842SDouglas Gilbert goto the_end; 3435cbf67842SDouglas Gilbert } 3436cbf67842SDouglas Gilbert 3437cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3438cbf67842SDouglas Gilbert int k, retval; 3439cbf67842SDouglas Gilbert 3440cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3441cbf67842SDouglas Gilbert if (qa_indx >= retval) { 3442cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3443cbf67842SDouglas Gilbert pr_err("%s: index %d too large\n", __func__, retval); 3444cbf67842SDouglas Gilbert goto the_end; 3445cbf67842SDouglas Gilbert } 3446cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, retval); 3447cbf67842SDouglas Gilbert if ((k < scsi_debug_max_queue) || (k == retval)) 3448cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3449cbf67842SDouglas Gilbert else 3450cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3451cbf67842SDouglas Gilbert } 3452cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3453cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3454cbf67842SDouglas Gilbert the_end: 3455cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3456cbf67842SDouglas Gilbert } 34571da177e4SLinus Torvalds 34588dea0d02SFUJITA Tomonori static struct sdebug_dev_info * 34598dea0d02SFUJITA Tomonori sdebug_device_create(struct sdebug_host_info *sdbg_host, gfp_t flags) 34605cb2fc06SFUJITA Tomonori { 34615cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 34625cb2fc06SFUJITA Tomonori 34635cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 34645cb2fc06SFUJITA Tomonori if (devip) { 34655cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 34665cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 34675cb2fc06SFUJITA Tomonori } 34685cb2fc06SFUJITA Tomonori return devip; 34695cb2fc06SFUJITA Tomonori } 34705cb2fc06SFUJITA Tomonori 34711da177e4SLinus Torvalds static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev) 34721da177e4SLinus Torvalds { 34731da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 34741da177e4SLinus Torvalds struct sdebug_dev_info * open_devip = NULL; 34751da177e4SLinus Torvalds struct sdebug_dev_info * devip = 34761da177e4SLinus Torvalds (struct sdebug_dev_info *)sdev->hostdata; 34771da177e4SLinus Torvalds 34781da177e4SLinus Torvalds if (devip) 34791da177e4SLinus Torvalds return devip; 3480d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 34811da177e4SLinus Torvalds if (!sdbg_host) { 3482cbf67842SDouglas Gilbert pr_err("%s: Host info NULL\n", __func__); 34831da177e4SLinus Torvalds return NULL; 34841da177e4SLinus Torvalds } 34851da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 34861da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 34871da177e4SLinus Torvalds (devip->target == sdev->id) && 34881da177e4SLinus Torvalds (devip->lun == sdev->lun)) 34891da177e4SLinus Torvalds return devip; 34901da177e4SLinus Torvalds else { 34911da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 34921da177e4SLinus Torvalds open_devip = devip; 34931da177e4SLinus Torvalds } 34941da177e4SLinus Torvalds } 34955cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 34965cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 34975cb2fc06SFUJITA Tomonori if (!open_devip) { 34981da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 3499cadbd4a5SHarvey Harrison __func__, __LINE__); 35001da177e4SLinus Torvalds return NULL; 35011da177e4SLinus Torvalds } 35021da177e4SLinus Torvalds } 3503a75869d1SFUJITA Tomonori 35041da177e4SLinus Torvalds open_devip->channel = sdev->channel; 35051da177e4SLinus Torvalds open_devip->target = sdev->id; 35061da177e4SLinus Torvalds open_devip->lun = sdev->lun; 35071da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3508cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3509cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3510c2248fc9SDouglas Gilbert open_devip->used = true; 35111da177e4SLinus Torvalds return open_devip; 35121da177e4SLinus Torvalds } 35131da177e4SLinus Torvalds 35148dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 35151da177e4SLinus Torvalds { 35168dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 35179cb78c16SHannes Reinecke printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %llu>\n", 35188dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 351975ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 35208dea0d02SFUJITA Tomonori return 0; 35218dea0d02SFUJITA Tomonori } 35221da177e4SLinus Torvalds 35238dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 35248dea0d02SFUJITA Tomonori { 35258dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip; 3526a34c4e98SFUJITA Tomonori 35271da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 35289cb78c16SHannes Reinecke printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %llu>\n", 35298dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 35308dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 35318dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 35328dea0d02SFUJITA Tomonori devip = devInfoReg(sdp); 35338dea0d02SFUJITA Tomonori if (NULL == devip) 35348dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3535c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 35366bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 353778d4e5a0SDouglas Gilbert if (scsi_debug_no_uld) 353878d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 35398dea0d02SFUJITA Tomonori return 0; 35408dea0d02SFUJITA Tomonori } 35418dea0d02SFUJITA Tomonori 35428dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 35438dea0d02SFUJITA Tomonori { 35448dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 35458dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 35468dea0d02SFUJITA Tomonori 35478dea0d02SFUJITA Tomonori if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) 35489cb78c16SHannes Reinecke printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %llu>\n", 35498dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 35508dea0d02SFUJITA Tomonori if (devip) { 355125985edcSLucas De Marchi /* make this slot available for re-use */ 3552c2248fc9SDouglas Gilbert devip->used = false; 35538dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 35548dea0d02SFUJITA Tomonori } 35558dea0d02SFUJITA Tomonori } 35568dea0d02SFUJITA Tomonori 3557cbf67842SDouglas Gilbert /* Returns 1 if cmnd found (deletes its timer or tasklet), else returns 0 */ 35588dea0d02SFUJITA Tomonori static int stop_queued_cmnd(struct scsi_cmnd *cmnd) 35598dea0d02SFUJITA Tomonori { 35608dea0d02SFUJITA Tomonori unsigned long iflags; 3561cbf67842SDouglas Gilbert int k, qmax, r_qmax; 35628dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3563cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 35648dea0d02SFUJITA Tomonori 35658dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3566cbf67842SDouglas Gilbert qmax = scsi_debug_max_queue; 3567cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3568cbf67842SDouglas Gilbert if (r_qmax > qmax) 3569cbf67842SDouglas Gilbert qmax = r_qmax; 3570cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3571cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 35728dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3573cbf67842SDouglas Gilbert if (cmnd == sqcp->a_cmnd) { 3574db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3575db525fceSDouglas Gilbert cmnd->device->hostdata; 3576db525fceSDouglas Gilbert if (devip) 3577db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3578db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3579db525fceSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, 3580db525fceSDouglas Gilbert iflags); 3581cbf67842SDouglas Gilbert if (scsi_debug_ndelay > 0) { 3582cbf67842SDouglas Gilbert if (sqcp->sd_hrtp) 3583cbf67842SDouglas Gilbert hrtimer_cancel( 3584cbf67842SDouglas Gilbert &sqcp->sd_hrtp->hrt); 3585cbf67842SDouglas Gilbert } else if (scsi_debug_delay > 0) { 3586cbf67842SDouglas Gilbert if (sqcp->cmnd_timerp) 3587cbf67842SDouglas Gilbert del_timer_sync( 3588cbf67842SDouglas Gilbert sqcp->cmnd_timerp); 3589cbf67842SDouglas Gilbert } else if (scsi_debug_delay < 0) { 3590cbf67842SDouglas Gilbert if (sqcp->tletp) 3591cbf67842SDouglas Gilbert tasklet_kill(sqcp->tletp); 3592cbf67842SDouglas Gilbert } 3593db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3594db525fceSDouglas Gilbert return 1; 35958dea0d02SFUJITA Tomonori } 35968dea0d02SFUJITA Tomonori } 3597cbf67842SDouglas Gilbert } 35988dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 3599db525fceSDouglas Gilbert return 0; 36008dea0d02SFUJITA Tomonori } 36018dea0d02SFUJITA Tomonori 3602cbf67842SDouglas Gilbert /* Deletes (stops) timers or tasklets of all queued commands */ 36038dea0d02SFUJITA Tomonori static void stop_all_queued(void) 36048dea0d02SFUJITA Tomonori { 36058dea0d02SFUJITA Tomonori unsigned long iflags; 36068dea0d02SFUJITA Tomonori int k; 36078dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3608cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 36098dea0d02SFUJITA Tomonori 36108dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3611cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3612cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 36138dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3614cbf67842SDouglas Gilbert if (sqcp->a_cmnd) { 3615db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3616db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3617db525fceSDouglas Gilbert if (devip) 3618db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3619db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3620db525fceSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, 3621db525fceSDouglas Gilbert iflags); 3622cbf67842SDouglas Gilbert if (scsi_debug_ndelay > 0) { 3623cbf67842SDouglas Gilbert if (sqcp->sd_hrtp) 3624cbf67842SDouglas Gilbert hrtimer_cancel( 3625cbf67842SDouglas Gilbert &sqcp->sd_hrtp->hrt); 3626cbf67842SDouglas Gilbert } else if (scsi_debug_delay > 0) { 3627cbf67842SDouglas Gilbert if (sqcp->cmnd_timerp) 3628cbf67842SDouglas Gilbert del_timer_sync( 3629cbf67842SDouglas Gilbert sqcp->cmnd_timerp); 3630cbf67842SDouglas Gilbert } else if (scsi_debug_delay < 0) { 3631cbf67842SDouglas Gilbert if (sqcp->tletp) 3632cbf67842SDouglas Gilbert tasklet_kill(sqcp->tletp); 3633cbf67842SDouglas Gilbert } 3634db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3635db525fceSDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 36368dea0d02SFUJITA Tomonori } 36378dea0d02SFUJITA Tomonori } 3638cbf67842SDouglas Gilbert } 3639cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3640cbf67842SDouglas Gilbert } 3641cbf67842SDouglas Gilbert 3642cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3643cbf67842SDouglas Gilbert static void free_all_queued(void) 3644cbf67842SDouglas Gilbert { 3645cbf67842SDouglas Gilbert unsigned long iflags; 3646cbf67842SDouglas Gilbert int k; 3647cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3648cbf67842SDouglas Gilbert 3649cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 3650cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3651cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 3652cbf67842SDouglas Gilbert kfree(sqcp->cmnd_timerp); 3653cbf67842SDouglas Gilbert sqcp->cmnd_timerp = NULL; 3654cbf67842SDouglas Gilbert kfree(sqcp->tletp); 3655cbf67842SDouglas Gilbert sqcp->tletp = NULL; 3656cbf67842SDouglas Gilbert kfree(sqcp->sd_hrtp); 3657cbf67842SDouglas Gilbert sqcp->sd_hrtp = NULL; 3658cbf67842SDouglas Gilbert } 36598dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 36601da177e4SLinus Torvalds } 36611da177e4SLinus Torvalds 36621da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 36631da177e4SLinus Torvalds { 36641da177e4SLinus Torvalds ++num_aborts; 3665cbf67842SDouglas Gilbert if (SCpnt) { 3666cbf67842SDouglas Gilbert if (SCpnt->device && 3667cbf67842SDouglas Gilbert (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)) 3668cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", 3669cbf67842SDouglas Gilbert __func__); 36701da177e4SLinus Torvalds stop_queued_cmnd(SCpnt); 3671cbf67842SDouglas Gilbert } 36721da177e4SLinus Torvalds return SUCCESS; 36731da177e4SLinus Torvalds } 36741da177e4SLinus Torvalds 36751da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 36761da177e4SLinus Torvalds { 36771da177e4SLinus Torvalds struct sdebug_dev_info * devip; 36781da177e4SLinus Torvalds 36791da177e4SLinus Torvalds ++num_dev_resets; 3680cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3681cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3682cbf67842SDouglas Gilbert 3683cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3684cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3685cbf67842SDouglas Gilbert devip = devInfoReg(sdp); 36861da177e4SLinus Torvalds if (devip) 3687cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 36881da177e4SLinus Torvalds } 36891da177e4SLinus Torvalds return SUCCESS; 36901da177e4SLinus Torvalds } 36911da177e4SLinus Torvalds 3692cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3693cbf67842SDouglas Gilbert { 3694cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3695cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3696cbf67842SDouglas Gilbert struct scsi_device *sdp; 3697cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3698cbf67842SDouglas Gilbert int k = 0; 3699cbf67842SDouglas Gilbert 3700cbf67842SDouglas Gilbert ++num_target_resets; 3701cbf67842SDouglas Gilbert if (!SCpnt) 3702cbf67842SDouglas Gilbert goto lie; 3703cbf67842SDouglas Gilbert sdp = SCpnt->device; 3704cbf67842SDouglas Gilbert if (!sdp) 3705cbf67842SDouglas Gilbert goto lie; 3706cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3707cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3708cbf67842SDouglas Gilbert hp = sdp->host; 3709cbf67842SDouglas Gilbert if (!hp) 3710cbf67842SDouglas Gilbert goto lie; 3711cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3712cbf67842SDouglas Gilbert if (sdbg_host) { 3713cbf67842SDouglas Gilbert list_for_each_entry(devip, 3714cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3715cbf67842SDouglas Gilbert dev_list) 3716cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3717cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3718cbf67842SDouglas Gilbert ++k; 3719cbf67842SDouglas Gilbert } 3720cbf67842SDouglas Gilbert } 3721cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3722cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3723cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3724cbf67842SDouglas Gilbert lie: 3725cbf67842SDouglas Gilbert return SUCCESS; 3726cbf67842SDouglas Gilbert } 3727cbf67842SDouglas Gilbert 37281da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 37291da177e4SLinus Torvalds { 37301da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3731cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 37321da177e4SLinus Torvalds struct scsi_device * sdp; 37331da177e4SLinus Torvalds struct Scsi_Host * hp; 3734cbf67842SDouglas Gilbert int k = 0; 37351da177e4SLinus Torvalds 37361da177e4SLinus Torvalds ++num_bus_resets; 3737cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3738cbf67842SDouglas Gilbert goto lie; 3739cbf67842SDouglas Gilbert sdp = SCpnt->device; 3740cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts) 3741cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3742cbf67842SDouglas Gilbert hp = sdp->host; 3743cbf67842SDouglas Gilbert if (hp) { 3744d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 37451da177e4SLinus Torvalds if (sdbg_host) { 3746cbf67842SDouglas Gilbert list_for_each_entry(devip, 37471da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3748cbf67842SDouglas Gilbert dev_list) { 3749cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3750cbf67842SDouglas Gilbert ++k; 37511da177e4SLinus Torvalds } 37521da177e4SLinus Torvalds } 3753cbf67842SDouglas Gilbert } 3754cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3755cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3756cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3757cbf67842SDouglas Gilbert lie: 37581da177e4SLinus Torvalds return SUCCESS; 37591da177e4SLinus Torvalds } 37601da177e4SLinus Torvalds 37611da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 37621da177e4SLinus Torvalds { 37631da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3764cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3765cbf67842SDouglas Gilbert int k = 0; 37661da177e4SLinus Torvalds 37671da177e4SLinus Torvalds ++num_host_resets; 3768cbf67842SDouglas Gilbert if ((SCpnt->device) && (SCSI_DEBUG_OPT_ALL_NOISE & scsi_debug_opts)) 3769cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 37701da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 37711da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3772cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3773cbf67842SDouglas Gilbert dev_list) { 3774cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3775cbf67842SDouglas Gilbert ++k; 3776cbf67842SDouglas Gilbert } 37771da177e4SLinus Torvalds } 37781da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 37791da177e4SLinus Torvalds stop_all_queued(); 3780cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_RESET_NOISE & scsi_debug_opts) 3781cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3782cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 37831da177e4SLinus Torvalds return SUCCESS; 37841da177e4SLinus Torvalds } 37851da177e4SLinus Torvalds 3786f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 37875f2578e5SFUJITA Tomonori unsigned long store_size) 37881da177e4SLinus Torvalds { 37891da177e4SLinus Torvalds struct partition * pp; 37901da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 37911da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 37921da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 37931da177e4SLinus Torvalds 37941da177e4SLinus Torvalds /* assume partition table already zeroed */ 3795f58b0efbSFUJITA Tomonori if ((scsi_debug_num_parts < 1) || (store_size < 1048576)) 37961da177e4SLinus Torvalds return; 37971da177e4SLinus Torvalds if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) { 37981da177e4SLinus Torvalds scsi_debug_num_parts = SDEBUG_MAX_PARTS; 3799cbf67842SDouglas Gilbert pr_warn("%s: reducing partitions to %d\n", __func__, 3800cbf67842SDouglas Gilbert SDEBUG_MAX_PARTS); 38011da177e4SLinus Torvalds } 3802c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 38031da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 38041da177e4SLinus Torvalds / scsi_debug_num_parts; 38051da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 38061da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 38071da177e4SLinus Torvalds for (k = 1; k < scsi_debug_num_parts; ++k) 38081da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 38091da177e4SLinus Torvalds * heads_by_sects; 38101da177e4SLinus Torvalds starts[scsi_debug_num_parts] = num_sectors; 38111da177e4SLinus Torvalds starts[scsi_debug_num_parts + 1] = 0; 38121da177e4SLinus Torvalds 38131da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 38141da177e4SLinus Torvalds ramp[511] = 0xAA; 38151da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 38161da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 38171da177e4SLinus Torvalds start_sec = starts[k]; 38181da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 38191da177e4SLinus Torvalds pp->boot_ind = 0; 38201da177e4SLinus Torvalds 38211da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 38221da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 38231da177e4SLinus Torvalds / sdebug_sectors_per; 38241da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 38251da177e4SLinus Torvalds 38261da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 38271da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 38281da177e4SLinus Torvalds / sdebug_sectors_per; 38291da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 38301da177e4SLinus Torvalds 3831150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3832150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 38331da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 38341da177e4SLinus Torvalds } 38351da177e4SLinus Torvalds } 38361da177e4SLinus Torvalds 3837cbf67842SDouglas Gilbert static int 3838cbf67842SDouglas Gilbert schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 3839cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 38401da177e4SLinus Torvalds { 3841cbf67842SDouglas Gilbert unsigned long iflags; 3842cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 3843cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp = NULL; 38441da177e4SLinus Torvalds struct scsi_device *sdp = cmnd->device; 38451da177e4SLinus Torvalds 3846cbf67842SDouglas Gilbert if (NULL == cmnd || NULL == devip) { 3847cbf67842SDouglas Gilbert pr_warn("%s: called with NULL cmnd or devip pointer\n", 3848cbf67842SDouglas Gilbert __func__); 3849cbf67842SDouglas Gilbert /* no particularly good error to report back */ 3850cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 38511da177e4SLinus Torvalds } 3852cbf67842SDouglas Gilbert if ((scsi_result) && (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)) 3853cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 3854cbf67842SDouglas Gilbert __func__, scsi_result); 3855cd62b7daSDouglas Gilbert if (delta_jiff == 0) 3856cd62b7daSDouglas Gilbert goto respond_in_thread; 38571da177e4SLinus Torvalds 3858cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 38591da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3860cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 3861cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 3862cbf67842SDouglas Gilbert inject = 0; 3863cd62b7daSDouglas Gilbert if ((qdepth > 0) && (num_in_q >= qdepth)) { 3864cd62b7daSDouglas Gilbert if (scsi_result) { 3865cd62b7daSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3866cd62b7daSDouglas Gilbert goto respond_in_thread; 3867cd62b7daSDouglas Gilbert } else 3868cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3869cd62b7daSDouglas Gilbert } else if ((scsi_debug_every_nth != 0) && 3870cd62b7daSDouglas Gilbert (SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) && 3871cd62b7daSDouglas Gilbert (scsi_result == 0)) { 3872cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 3873cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 3874cbf67842SDouglas Gilbert abs(scsi_debug_every_nth))) { 3875cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3876cbf67842SDouglas Gilbert inject = 1; 3877cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 38781da177e4SLinus Torvalds } 3879cbf67842SDouglas Gilbert } 3880cbf67842SDouglas Gilbert 3881cd62b7daSDouglas Gilbert k = find_first_zero_bit(queued_in_use_bm, scsi_debug_max_queue); 388278d4e5a0SDouglas Gilbert if (k >= scsi_debug_max_queue) { 38831da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3884cd62b7daSDouglas Gilbert if (scsi_result) 3885cd62b7daSDouglas Gilbert goto respond_in_thread; 3886cd62b7daSDouglas Gilbert else if (SCSI_DEBUG_OPT_ALL_TSF & scsi_debug_opts) 3887cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3888cbf67842SDouglas Gilbert if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) 3889cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3890cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 3891cd62b7daSDouglas Gilbert __func__, scsi_debug_max_queue, 3892cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 3893cbf67842SDouglas Gilbert "report: host busy")); 3894cd62b7daSDouglas Gilbert if (scsi_result) 3895cd62b7daSDouglas Gilbert goto respond_in_thread; 3896cd62b7daSDouglas Gilbert else 3897cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 38981da177e4SLinus Torvalds } 3899cbf67842SDouglas Gilbert __set_bit(k, queued_in_use_bm); 3900cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 3901cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 39021da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 3903cbf67842SDouglas Gilbert cmnd->result = scsi_result; 39041da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3905cbf67842SDouglas Gilbert if (delta_jiff > 0) { 3906cbf67842SDouglas Gilbert if (NULL == sqcp->cmnd_timerp) { 3907cbf67842SDouglas Gilbert sqcp->cmnd_timerp = kmalloc(sizeof(struct timer_list), 3908cbf67842SDouglas Gilbert GFP_ATOMIC); 3909cbf67842SDouglas Gilbert if (NULL == sqcp->cmnd_timerp) 3910cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3911cbf67842SDouglas Gilbert init_timer(sqcp->cmnd_timerp); 3912cbf67842SDouglas Gilbert } 3913cbf67842SDouglas Gilbert sqcp->cmnd_timerp->function = sdebug_q_cmd_complete; 3914cbf67842SDouglas Gilbert sqcp->cmnd_timerp->data = k; 3915cbf67842SDouglas Gilbert sqcp->cmnd_timerp->expires = get_jiffies_64() + delta_jiff; 3916cbf67842SDouglas Gilbert add_timer(sqcp->cmnd_timerp); 3917cbf67842SDouglas Gilbert } else if (scsi_debug_ndelay > 0) { 3918cbf67842SDouglas Gilbert ktime_t kt = ktime_set(0, scsi_debug_ndelay); 3919cbf67842SDouglas Gilbert struct sdebug_hrtimer *sd_hp = sqcp->sd_hrtp; 3920cbf67842SDouglas Gilbert 3921cbf67842SDouglas Gilbert if (NULL == sd_hp) { 3922cbf67842SDouglas Gilbert sd_hp = kmalloc(sizeof(*sd_hp), GFP_ATOMIC); 3923cbf67842SDouglas Gilbert if (NULL == sd_hp) 3924cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3925cbf67842SDouglas Gilbert sqcp->sd_hrtp = sd_hp; 3926cbf67842SDouglas Gilbert hrtimer_init(&sd_hp->hrt, CLOCK_MONOTONIC, 3927cbf67842SDouglas Gilbert HRTIMER_MODE_REL); 3928cbf67842SDouglas Gilbert sd_hp->hrt.function = sdebug_q_cmd_hrt_complete; 3929cbf67842SDouglas Gilbert sd_hp->qa_indx = k; 3930cbf67842SDouglas Gilbert } 3931cbf67842SDouglas Gilbert hrtimer_start(&sd_hp->hrt, kt, HRTIMER_MODE_REL); 3932cbf67842SDouglas Gilbert } else { /* delay < 0 */ 3933cbf67842SDouglas Gilbert if (NULL == sqcp->tletp) { 3934cbf67842SDouglas Gilbert sqcp->tletp = kmalloc(sizeof(*sqcp->tletp), 3935cbf67842SDouglas Gilbert GFP_ATOMIC); 3936cbf67842SDouglas Gilbert if (NULL == sqcp->tletp) 3937cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3938cbf67842SDouglas Gilbert tasklet_init(sqcp->tletp, 3939cbf67842SDouglas Gilbert sdebug_q_cmd_complete, k); 3940cbf67842SDouglas Gilbert } 3941cbf67842SDouglas Gilbert if (-1 == delta_jiff) 3942cbf67842SDouglas Gilbert tasklet_hi_schedule(sqcp->tletp); 3943cbf67842SDouglas Gilbert else 3944cbf67842SDouglas Gilbert tasklet_schedule(sqcp->tletp); 3945cbf67842SDouglas Gilbert } 3946cd62b7daSDouglas Gilbert if ((SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) && 3947cd62b7daSDouglas Gilbert (scsi_result == device_qfull_result)) 3948cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3949cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 3950cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 3951cbf67842SDouglas Gilbert "status: TASK SET FULL"); 39521da177e4SLinus Torvalds return 0; 3953cd62b7daSDouglas Gilbert 3954cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 3955cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 3956cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 3957cd62b7daSDouglas Gilbert return 0; 39581da177e4SLinus Torvalds } 3959cbf67842SDouglas Gilbert 396023183910SDouglas Gilbert /* Note: The following macros create attribute files in the 396123183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 396223183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 396323183910SDouglas Gilbert as it can when the corresponding attribute in the 396423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 396523183910SDouglas Gilbert */ 3966c65b1445SDouglas Gilbert module_param_named(add_host, scsi_debug_add_host, int, S_IRUGO | S_IWUSR); 39675b94e232SMartin K. Petersen module_param_named(ato, scsi_debug_ato, int, S_IRUGO); 39680759c666SAkinobu Mita module_param_named(clustering, scsi_debug_clustering, bool, S_IRUGO | S_IWUSR); 3969c65b1445SDouglas Gilbert module_param_named(delay, scsi_debug_delay, int, S_IRUGO | S_IWUSR); 3970c65b1445SDouglas Gilbert module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, S_IRUGO); 39715b94e232SMartin K. Petersen module_param_named(dif, scsi_debug_dif, int, S_IRUGO); 39725b94e232SMartin K. Petersen module_param_named(dix, scsi_debug_dix, int, S_IRUGO); 3973c65b1445SDouglas Gilbert module_param_named(dsense, scsi_debug_dsense, int, S_IRUGO | S_IWUSR); 3974c65b1445SDouglas Gilbert module_param_named(every_nth, scsi_debug_every_nth, int, S_IRUGO | S_IWUSR); 397523183910SDouglas Gilbert module_param_named(fake_rw, scsi_debug_fake_rw, int, S_IRUGO | S_IWUSR); 397668aee7baSAkinobu Mita module_param_named(guard, scsi_debug_guard, uint, S_IRUGO); 3977cbf67842SDouglas Gilbert module_param_named(host_lock, scsi_debug_host_lock, bool, S_IRUGO | S_IWUSR); 39785b94e232SMartin K. Petersen module_param_named(lbpu, scsi_debug_lbpu, int, S_IRUGO); 39795b94e232SMartin K. Petersen module_param_named(lbpws, scsi_debug_lbpws, int, S_IRUGO); 39805b94e232SMartin K. Petersen module_param_named(lbpws10, scsi_debug_lbpws10, int, S_IRUGO); 3981be1dd78dSEric Sandeen module_param_named(lbprz, scsi_debug_lbprz, int, S_IRUGO); 39825b94e232SMartin K. Petersen module_param_named(lowest_aligned, scsi_debug_lowest_aligned, int, S_IRUGO); 3983c65b1445SDouglas Gilbert module_param_named(max_luns, scsi_debug_max_luns, int, S_IRUGO | S_IWUSR); 398478d4e5a0SDouglas Gilbert module_param_named(max_queue, scsi_debug_max_queue, int, S_IRUGO | S_IWUSR); 3985cbf67842SDouglas Gilbert module_param_named(ndelay, scsi_debug_ndelay, int, S_IRUGO | S_IWUSR); 3986c65b1445SDouglas Gilbert module_param_named(no_lun_0, scsi_debug_no_lun_0, int, S_IRUGO | S_IWUSR); 398778d4e5a0SDouglas Gilbert module_param_named(no_uld, scsi_debug_no_uld, int, S_IRUGO); 3988c65b1445SDouglas Gilbert module_param_named(num_parts, scsi_debug_num_parts, int, S_IRUGO); 3989c65b1445SDouglas Gilbert module_param_named(num_tgts, scsi_debug_num_tgts, int, S_IRUGO | S_IWUSR); 39905b94e232SMartin K. Petersen module_param_named(opt_blks, scsi_debug_opt_blks, int, S_IRUGO); 3991c65b1445SDouglas Gilbert module_param_named(opts, scsi_debug_opts, int, S_IRUGO | S_IWUSR); 39925b94e232SMartin K. Petersen module_param_named(physblk_exp, scsi_debug_physblk_exp, int, S_IRUGO); 3993c65b1445SDouglas Gilbert module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR); 3994d986788bSMartin Pitt module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR); 3995c65b1445SDouglas Gilbert module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO); 39965b94e232SMartin K. Petersen module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO); 3997c2248fc9SDouglas Gilbert module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR); 39985b94e232SMartin K. Petersen module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO); 39995b94e232SMartin K. Petersen module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO); 40005b94e232SMartin K. Petersen module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO); 40015b94e232SMartin K. Petersen module_param_named(unmap_max_desc, scsi_debug_unmap_max_desc, int, S_IRUGO); 4002c65b1445SDouglas Gilbert module_param_named(virtual_gb, scsi_debug_virtual_gb, int, S_IRUGO | S_IWUSR); 400323183910SDouglas Gilbert module_param_named(vpd_use_hostno, scsi_debug_vpd_use_hostno, int, 400423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 40055b94e232SMartin K. Petersen module_param_named(write_same_length, scsi_debug_write_same_length, int, 40065b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 40071da177e4SLinus Torvalds 40081da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 40091da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 40101da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 40111da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 40121da177e4SLinus Torvalds 40131da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 40145b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 40150759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4016cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4017c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 40185b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 40195b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4020c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4021beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 402223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 40235b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4024cbf67842SDouglas Gilbert MODULE_PARM_DESC(host_lock, "use host_lock around all commands (def=0)"); 40255b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 40265b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 40275b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4028be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); 40295b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4030c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4031cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4032cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4033c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 403478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 40351da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4036c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 40375b94e232SMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in block (def=64)"); 40386f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 40395b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 40401da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4041d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4042e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])"); 4043ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4044c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 40455b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 40465b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 40476014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 40486014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 4049c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 40505b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 40515b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 40521da177e4SLinus Torvalds 40531da177e4SLinus Torvalds static char sdebug_info[256]; 40541da177e4SLinus Torvalds 40551da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 40561da177e4SLinus Torvalds { 40571da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 40581da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 40591da177e4SLinus Torvalds scsi_debug_version_date, scsi_debug_dev_size_mb, 40601da177e4SLinus Torvalds scsi_debug_opts); 40611da177e4SLinus Torvalds return sdebug_info; 40621da177e4SLinus Torvalds } 40631da177e4SLinus Torvalds 4064cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4065c8ed555aSAl Viro static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, int length) 40661da177e4SLinus Torvalds { 40671da177e4SLinus Torvalds char arr[16]; 4068c8ed555aSAl Viro int opts; 40691da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 40701da177e4SLinus Torvalds 40711da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 40721da177e4SLinus Torvalds return -EACCES; 40731da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 40741da177e4SLinus Torvalds arr[minLen] = '\0'; 4075c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 40761da177e4SLinus Torvalds return -EINVAL; 4077c8ed555aSAl Viro scsi_debug_opts = opts; 40781da177e4SLinus Torvalds if (scsi_debug_every_nth != 0) 4079cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 40801da177e4SLinus Torvalds return length; 40811da177e4SLinus Torvalds } 4082c8ed555aSAl Viro 4083cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4084cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4085cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4086c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4087c8ed555aSAl Viro { 4088cbf67842SDouglas Gilbert int f, l; 4089cbf67842SDouglas Gilbert char b[32]; 4090cbf67842SDouglas Gilbert 4091cbf67842SDouglas Gilbert if (scsi_debug_every_nth > 0) 4092cbf67842SDouglas Gilbert snprintf(b, sizeof(b), " (curr:%d)", 4093cbf67842SDouglas Gilbert ((SCSI_DEBUG_OPT_RARE_TSF & scsi_debug_opts) ? 4094cbf67842SDouglas Gilbert atomic_read(&sdebug_a_tsf) : 4095cbf67842SDouglas Gilbert atomic_read(&sdebug_cmnd_count))); 4096cbf67842SDouglas Gilbert else 4097cbf67842SDouglas Gilbert b[0] = '\0'; 4098cbf67842SDouglas Gilbert 4099cbf67842SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n" 41001da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 4101cbf67842SDouglas Gilbert "every_nth=%d%s\n" 4102cbf67842SDouglas Gilbert "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n" 41031da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 4104cbf67842SDouglas Gilbert "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, " 4105cbf67842SDouglas Gilbert "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d " 4106cbf67842SDouglas Gilbert "usec_in_jiffy=%lu\n", 4107cbf67842SDouglas Gilbert SCSI_DEBUG_VERSION, scsi_debug_version_date, 4108cbf67842SDouglas Gilbert scsi_debug_num_tgts, scsi_debug_dev_size_mb, scsi_debug_opts, 4109cbf67842SDouglas Gilbert scsi_debug_every_nth, b, scsi_debug_delay, scsi_debug_ndelay, 4110cbf67842SDouglas Gilbert scsi_debug_max_luns, atomic_read(&sdebug_completions), 4111597136abSMartin K. Petersen scsi_debug_sector_size, sdebug_cylinders_per, sdebug_heads, 4112cbf67842SDouglas Gilbert sdebug_sectors_per, num_aborts, num_dev_resets, 4113cbf67842SDouglas Gilbert num_target_resets, num_bus_resets, num_host_resets, 4114cbf67842SDouglas Gilbert dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000); 4115cbf67842SDouglas Gilbert 4116cbf67842SDouglas Gilbert f = find_first_bit(queued_in_use_bm, scsi_debug_max_queue); 4117cbf67842SDouglas Gilbert if (f != scsi_debug_max_queue) { 4118cbf67842SDouglas Gilbert l = find_last_bit(queued_in_use_bm, scsi_debug_max_queue); 4119cbf67842SDouglas Gilbert seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n", 4120cbf67842SDouglas Gilbert "queued_in_use_bm", f, l); 4121cbf67842SDouglas Gilbert } 4122c8ed555aSAl Viro return 0; 41231da177e4SLinus Torvalds } 41241da177e4SLinus Torvalds 412582069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 41261da177e4SLinus Torvalds { 41271da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay); 41281da177e4SLinus Torvalds } 4129cbf67842SDouglas Gilbert /* Returns -EBUSY if delay is being changed and commands are queued */ 413082069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 413182069379SAkinobu Mita size_t count) 41321da177e4SLinus Torvalds { 4133cbf67842SDouglas Gilbert int delay, res; 41341da177e4SLinus Torvalds 4135cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &delay))) { 4136cbf67842SDouglas Gilbert res = count; 4137cbf67842SDouglas Gilbert if (scsi_debug_delay != delay) { 4138cbf67842SDouglas Gilbert unsigned long iflags; 4139cbf67842SDouglas Gilbert int k; 4140cbf67842SDouglas Gilbert 4141cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4142cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4143cbf67842SDouglas Gilbert scsi_debug_max_queue); 4144cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4145cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4146cbf67842SDouglas Gilbert else { 41471da177e4SLinus Torvalds scsi_debug_delay = delay; 4148cbf67842SDouglas Gilbert scsi_debug_ndelay = 0; 41491da177e4SLinus Torvalds } 4150cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4151cbf67842SDouglas Gilbert } 4152cbf67842SDouglas Gilbert return res; 41531da177e4SLinus Torvalds } 41541da177e4SLinus Torvalds return -EINVAL; 41551da177e4SLinus Torvalds } 415682069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 41571da177e4SLinus Torvalds 4158cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4159cbf67842SDouglas Gilbert { 4160cbf67842SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ndelay); 4161cbf67842SDouglas Gilbert } 4162cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4163cbf67842SDouglas Gilbert /* If > 0 and accepted then scsi_debug_delay is set to DELAY_OVERRIDDEN */ 4164cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4165cbf67842SDouglas Gilbert size_t count) 4166cbf67842SDouglas Gilbert { 4167cbf67842SDouglas Gilbert unsigned long iflags; 4168cbf67842SDouglas Gilbert int ndelay, res, k; 4169cbf67842SDouglas Gilbert 4170cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4171cbf67842SDouglas Gilbert (ndelay >= 0) && (ndelay < 1000000000)) { 4172cbf67842SDouglas Gilbert res = count; 4173cbf67842SDouglas Gilbert if (scsi_debug_ndelay != ndelay) { 4174cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4175cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4176cbf67842SDouglas Gilbert scsi_debug_max_queue); 4177cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4178cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4179cbf67842SDouglas Gilbert else { 4180cbf67842SDouglas Gilbert scsi_debug_ndelay = ndelay; 4181cbf67842SDouglas Gilbert scsi_debug_delay = ndelay ? DELAY_OVERRIDDEN 4182cbf67842SDouglas Gilbert : DEF_DELAY; 4183cbf67842SDouglas Gilbert } 4184cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4185cbf67842SDouglas Gilbert } 4186cbf67842SDouglas Gilbert return res; 4187cbf67842SDouglas Gilbert } 4188cbf67842SDouglas Gilbert return -EINVAL; 4189cbf67842SDouglas Gilbert } 4190cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4191cbf67842SDouglas Gilbert 419282069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 41931da177e4SLinus Torvalds { 41941da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts); 41951da177e4SLinus Torvalds } 41961da177e4SLinus Torvalds 419782069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 419882069379SAkinobu Mita size_t count) 41991da177e4SLinus Torvalds { 42001da177e4SLinus Torvalds int opts; 42011da177e4SLinus Torvalds char work[20]; 42021da177e4SLinus Torvalds 42031da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 420448a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 42051da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 42061da177e4SLinus Torvalds goto opts_done; 42071da177e4SLinus Torvalds } else { 42081da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 42091da177e4SLinus Torvalds goto opts_done; 42101da177e4SLinus Torvalds } 42111da177e4SLinus Torvalds } 42121da177e4SLinus Torvalds return -EINVAL; 42131da177e4SLinus Torvalds opts_done: 42141da177e4SLinus Torvalds scsi_debug_opts = opts; 4215817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 4216817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4217817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 4218817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4219817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 4220817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4221817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 4222817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4223817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 4224817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 4225cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4226cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 42271da177e4SLinus Torvalds return count; 42281da177e4SLinus Torvalds } 422982069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 42301da177e4SLinus Torvalds 423182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 42321da177e4SLinus Torvalds { 42331da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype); 42341da177e4SLinus Torvalds } 423582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 423682069379SAkinobu Mita size_t count) 42371da177e4SLinus Torvalds { 42381da177e4SLinus Torvalds int n; 42391da177e4SLinus Torvalds 42401da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 42411da177e4SLinus Torvalds scsi_debug_ptype = n; 42421da177e4SLinus Torvalds return count; 42431da177e4SLinus Torvalds } 42441da177e4SLinus Torvalds return -EINVAL; 42451da177e4SLinus Torvalds } 424682069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 42471da177e4SLinus Torvalds 424882069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 42491da177e4SLinus Torvalds { 42501da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense); 42511da177e4SLinus Torvalds } 425282069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 425382069379SAkinobu Mita size_t count) 42541da177e4SLinus Torvalds { 42551da177e4SLinus Torvalds int n; 42561da177e4SLinus Torvalds 42571da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 42581da177e4SLinus Torvalds scsi_debug_dsense = n; 42591da177e4SLinus Torvalds return count; 42601da177e4SLinus Torvalds } 42611da177e4SLinus Torvalds return -EINVAL; 42621da177e4SLinus Torvalds } 426382069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 42641da177e4SLinus Torvalds 426582069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 426623183910SDouglas Gilbert { 426723183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_fake_rw); 426823183910SDouglas Gilbert } 426982069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 427082069379SAkinobu Mita size_t count) 427123183910SDouglas Gilbert { 427223183910SDouglas Gilbert int n; 427323183910SDouglas Gilbert 427423183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4275cbf67842SDouglas Gilbert n = (n > 0); 4276cbf67842SDouglas Gilbert scsi_debug_fake_rw = (scsi_debug_fake_rw > 0); 4277cbf67842SDouglas Gilbert if (scsi_debug_fake_rw != n) { 4278cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4279cbf67842SDouglas Gilbert unsigned long sz = 4280cbf67842SDouglas Gilbert (unsigned long)scsi_debug_dev_size_mb * 4281cbf67842SDouglas Gilbert 1048576; 4282cbf67842SDouglas Gilbert 4283cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4284cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4285cbf67842SDouglas Gilbert pr_err("%s: out of memory, 9\n", 4286cbf67842SDouglas Gilbert __func__); 4287cbf67842SDouglas Gilbert return -ENOMEM; 4288cbf67842SDouglas Gilbert } 4289cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4290cbf67842SDouglas Gilbert } 429123183910SDouglas Gilbert scsi_debug_fake_rw = n; 4292cbf67842SDouglas Gilbert } 429323183910SDouglas Gilbert return count; 429423183910SDouglas Gilbert } 429523183910SDouglas Gilbert return -EINVAL; 429623183910SDouglas Gilbert } 429782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 429823183910SDouglas Gilbert 429982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4300c65b1445SDouglas Gilbert { 4301c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_lun_0); 4302c65b1445SDouglas Gilbert } 430382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 430482069379SAkinobu Mita size_t count) 4305c65b1445SDouglas Gilbert { 4306c65b1445SDouglas Gilbert int n; 4307c65b1445SDouglas Gilbert 4308c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4309c65b1445SDouglas Gilbert scsi_debug_no_lun_0 = n; 4310c65b1445SDouglas Gilbert return count; 4311c65b1445SDouglas Gilbert } 4312c65b1445SDouglas Gilbert return -EINVAL; 4313c65b1445SDouglas Gilbert } 431482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4315c65b1445SDouglas Gilbert 431682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 43171da177e4SLinus Torvalds { 43181da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts); 43191da177e4SLinus Torvalds } 432082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 432182069379SAkinobu Mita size_t count) 43221da177e4SLinus Torvalds { 43231da177e4SLinus Torvalds int n; 43241da177e4SLinus Torvalds 43251da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 43261da177e4SLinus Torvalds scsi_debug_num_tgts = n; 43271da177e4SLinus Torvalds sdebug_max_tgts_luns(); 43281da177e4SLinus Torvalds return count; 43291da177e4SLinus Torvalds } 43301da177e4SLinus Torvalds return -EINVAL; 43311da177e4SLinus Torvalds } 433282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 43331da177e4SLinus Torvalds 433482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 43351da177e4SLinus Torvalds { 43361da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb); 43371da177e4SLinus Torvalds } 433882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 43391da177e4SLinus Torvalds 434082069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 43411da177e4SLinus Torvalds { 43421da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts); 43431da177e4SLinus Torvalds } 434482069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 43451da177e4SLinus Torvalds 434682069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 43471da177e4SLinus Torvalds { 43481da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth); 43491da177e4SLinus Torvalds } 435082069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 435182069379SAkinobu Mita size_t count) 43521da177e4SLinus Torvalds { 43531da177e4SLinus Torvalds int nth; 43541da177e4SLinus Torvalds 43551da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 43561da177e4SLinus Torvalds scsi_debug_every_nth = nth; 4357cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 43581da177e4SLinus Torvalds return count; 43591da177e4SLinus Torvalds } 43601da177e4SLinus Torvalds return -EINVAL; 43611da177e4SLinus Torvalds } 436282069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 43631da177e4SLinus Torvalds 436482069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 43651da177e4SLinus Torvalds { 43661da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns); 43671da177e4SLinus Torvalds } 436882069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 436982069379SAkinobu Mita size_t count) 43701da177e4SLinus Torvalds { 43711da177e4SLinus Torvalds int n; 43721da177e4SLinus Torvalds 43731da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 43741da177e4SLinus Torvalds scsi_debug_max_luns = n; 43751da177e4SLinus Torvalds sdebug_max_tgts_luns(); 43761da177e4SLinus Torvalds return count; 43771da177e4SLinus Torvalds } 43781da177e4SLinus Torvalds return -EINVAL; 43791da177e4SLinus Torvalds } 438082069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 43811da177e4SLinus Torvalds 438282069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 438378d4e5a0SDouglas Gilbert { 438478d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_queue); 438578d4e5a0SDouglas Gilbert } 4386cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4387cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 438882069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 438982069379SAkinobu Mita size_t count) 439078d4e5a0SDouglas Gilbert { 4391cbf67842SDouglas Gilbert unsigned long iflags; 4392cbf67842SDouglas Gilbert int n, k; 439378d4e5a0SDouglas Gilbert 439478d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 439578d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 4396cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4397cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE); 439878d4e5a0SDouglas Gilbert scsi_debug_max_queue = n; 4399cbf67842SDouglas Gilbert if (SCSI_DEBUG_CANQUEUE == k) 4400cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4401cbf67842SDouglas Gilbert else if (k >= n) 4402cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4403cbf67842SDouglas Gilbert else 4404cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4405cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 440678d4e5a0SDouglas Gilbert return count; 440778d4e5a0SDouglas Gilbert } 440878d4e5a0SDouglas Gilbert return -EINVAL; 440978d4e5a0SDouglas Gilbert } 441082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 441178d4e5a0SDouglas Gilbert 441282069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 441378d4e5a0SDouglas Gilbert { 441478d4e5a0SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_no_uld); 441578d4e5a0SDouglas Gilbert } 441682069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 441778d4e5a0SDouglas Gilbert 441882069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 44191da177e4SLinus Torvalds { 44201da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level); 44211da177e4SLinus Torvalds } 442282069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 44231da177e4SLinus Torvalds 442482069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4425c65b1445SDouglas Gilbert { 4426c65b1445SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_virtual_gb); 4427c65b1445SDouglas Gilbert } 442882069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 442982069379SAkinobu Mita size_t count) 4430c65b1445SDouglas Gilbert { 4431c65b1445SDouglas Gilbert int n; 44320d01c5dfSDouglas Gilbert bool changed; 4433c65b1445SDouglas Gilbert 4434c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 44350d01c5dfSDouglas Gilbert changed = (scsi_debug_virtual_gb != n); 4436c65b1445SDouglas Gilbert scsi_debug_virtual_gb = n; 443728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 44380d01c5dfSDouglas Gilbert if (changed) { 44390d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 44400d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 444128898873SFUJITA Tomonori 44424bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 44430d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 44440d01c5dfSDouglas Gilbert host_list) { 44450d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 44460d01c5dfSDouglas Gilbert dev_list) { 44470d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 44480d01c5dfSDouglas Gilbert dp->uas_bm); 44490d01c5dfSDouglas Gilbert } 44500d01c5dfSDouglas Gilbert } 44514bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 44520d01c5dfSDouglas Gilbert } 4453c65b1445SDouglas Gilbert return count; 4454c65b1445SDouglas Gilbert } 4455c65b1445SDouglas Gilbert return -EINVAL; 4456c65b1445SDouglas Gilbert } 445782069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4458c65b1445SDouglas Gilbert 445982069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 44601da177e4SLinus Torvalds { 44611da177e4SLinus Torvalds return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host); 44621da177e4SLinus Torvalds } 44631da177e4SLinus Torvalds 446482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 446582069379SAkinobu Mita size_t count) 44661da177e4SLinus Torvalds { 44671da177e4SLinus Torvalds int delta_hosts; 44681da177e4SLinus Torvalds 4469f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 44701da177e4SLinus Torvalds return -EINVAL; 44711da177e4SLinus Torvalds if (delta_hosts > 0) { 44721da177e4SLinus Torvalds do { 44731da177e4SLinus Torvalds sdebug_add_adapter(); 44741da177e4SLinus Torvalds } while (--delta_hosts); 44751da177e4SLinus Torvalds } else if (delta_hosts < 0) { 44761da177e4SLinus Torvalds do { 44771da177e4SLinus Torvalds sdebug_remove_adapter(); 44781da177e4SLinus Torvalds } while (++delta_hosts); 44791da177e4SLinus Torvalds } 44801da177e4SLinus Torvalds return count; 44811da177e4SLinus Torvalds } 448282069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 44831da177e4SLinus Torvalds 448482069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 448523183910SDouglas Gilbert { 448623183910SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_vpd_use_hostno); 448723183910SDouglas Gilbert } 448882069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 448982069379SAkinobu Mita size_t count) 449023183910SDouglas Gilbert { 449123183910SDouglas Gilbert int n; 449223183910SDouglas Gilbert 449323183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 449423183910SDouglas Gilbert scsi_debug_vpd_use_hostno = n; 449523183910SDouglas Gilbert return count; 449623183910SDouglas Gilbert } 449723183910SDouglas Gilbert return -EINVAL; 449823183910SDouglas Gilbert } 449982069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 450023183910SDouglas Gilbert 450182069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4502597136abSMartin K. Petersen { 4503597136abSMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_sector_size); 4504597136abSMartin K. Petersen } 450582069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4506597136abSMartin K. Petersen 450782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4508c6a44287SMartin K. Petersen { 4509c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dix); 4510c6a44287SMartin K. Petersen } 451182069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4512c6a44287SMartin K. Petersen 451382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4514c6a44287SMartin K. Petersen { 4515c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dif); 4516c6a44287SMartin K. Petersen } 451782069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4518c6a44287SMartin K. Petersen 451982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4520c6a44287SMartin K. Petersen { 452168aee7baSAkinobu Mita return scnprintf(buf, PAGE_SIZE, "%u\n", scsi_debug_guard); 4522c6a44287SMartin K. Petersen } 452382069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4524c6a44287SMartin K. Petersen 452582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4526c6a44287SMartin K. Petersen { 4527c6a44287SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ato); 4528c6a44287SMartin K. Petersen } 452982069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4530c6a44287SMartin K. Petersen 453182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 453244d92694SMartin K. Petersen { 453344d92694SMartin K. Petersen ssize_t count; 453444d92694SMartin K. Petersen 45355b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 453644d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 453744d92694SMartin K. Petersen sdebug_store_sectors); 453844d92694SMartin K. Petersen 453944d92694SMartin K. Petersen count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size); 454044d92694SMartin K. Petersen 454144d92694SMartin K. Petersen buf[count++] = '\n'; 454244d92694SMartin K. Petersen buf[count++] = 0; 454344d92694SMartin K. Petersen 454444d92694SMartin K. Petersen return count; 454544d92694SMartin K. Petersen } 454682069379SAkinobu Mita static DRIVER_ATTR_RO(map); 454744d92694SMartin K. Petersen 454882069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4549d986788bSMartin Pitt { 4550d986788bSMartin Pitt return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_removable ? 1 : 0); 4551d986788bSMartin Pitt } 455282069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 455382069379SAkinobu Mita size_t count) 4554d986788bSMartin Pitt { 4555d986788bSMartin Pitt int n; 4556d986788bSMartin Pitt 4557d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4558d986788bSMartin Pitt scsi_debug_removable = (n > 0); 4559d986788bSMartin Pitt return count; 4560d986788bSMartin Pitt } 4561d986788bSMartin Pitt return -EINVAL; 4562d986788bSMartin Pitt } 456382069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4564d986788bSMartin Pitt 4565cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4566cbf67842SDouglas Gilbert { 4567cbf67842SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_host_lock); 4568cbf67842SDouglas Gilbert } 4569cbf67842SDouglas Gilbert /* Returns -EBUSY if host_lock is being changed and commands are queued */ 4570cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4571cbf67842SDouglas Gilbert size_t count) 4572cbf67842SDouglas Gilbert { 4573cbf67842SDouglas Gilbert int n, res; 4574cbf67842SDouglas Gilbert 4575cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4576cbf67842SDouglas Gilbert bool new_host_lock = (n > 0); 4577cbf67842SDouglas Gilbert 4578cbf67842SDouglas Gilbert res = count; 4579cbf67842SDouglas Gilbert if (new_host_lock != scsi_debug_host_lock) { 4580cbf67842SDouglas Gilbert unsigned long iflags; 4581cbf67842SDouglas Gilbert int k; 4582cbf67842SDouglas Gilbert 4583cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4584cbf67842SDouglas Gilbert k = find_first_bit(queued_in_use_bm, 4585cbf67842SDouglas Gilbert scsi_debug_max_queue); 4586cbf67842SDouglas Gilbert if (k != scsi_debug_max_queue) 4587cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4588cbf67842SDouglas Gilbert else 4589cbf67842SDouglas Gilbert scsi_debug_host_lock = new_host_lock; 4590cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4591cbf67842SDouglas Gilbert } 4592cbf67842SDouglas Gilbert return res; 4593cbf67842SDouglas Gilbert } 4594cbf67842SDouglas Gilbert return -EINVAL; 4595cbf67842SDouglas Gilbert } 4596cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4597cbf67842SDouglas Gilbert 4598c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4599c2248fc9SDouglas Gilbert { 4600c2248fc9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict); 4601c2248fc9SDouglas Gilbert } 4602c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4603c2248fc9SDouglas Gilbert size_t count) 4604c2248fc9SDouglas Gilbert { 4605c2248fc9SDouglas Gilbert int n; 4606c2248fc9SDouglas Gilbert 4607c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4608c2248fc9SDouglas Gilbert scsi_debug_strict = (n > 0); 4609c2248fc9SDouglas Gilbert return count; 4610c2248fc9SDouglas Gilbert } 4611c2248fc9SDouglas Gilbert return -EINVAL; 4612c2248fc9SDouglas Gilbert } 4613c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4614c2248fc9SDouglas Gilbert 4615cbf67842SDouglas Gilbert 461682069379SAkinobu Mita /* Note: The following array creates attribute files in the 461723183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 461823183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 461923183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 462023183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 462123183910SDouglas Gilbert */ 46226ecaff7fSRandy Dunlap 462382069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 462482069379SAkinobu Mita &driver_attr_delay.attr, 462582069379SAkinobu Mita &driver_attr_opts.attr, 462682069379SAkinobu Mita &driver_attr_ptype.attr, 462782069379SAkinobu Mita &driver_attr_dsense.attr, 462882069379SAkinobu Mita &driver_attr_fake_rw.attr, 462982069379SAkinobu Mita &driver_attr_no_lun_0.attr, 463082069379SAkinobu Mita &driver_attr_num_tgts.attr, 463182069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 463282069379SAkinobu Mita &driver_attr_num_parts.attr, 463382069379SAkinobu Mita &driver_attr_every_nth.attr, 463482069379SAkinobu Mita &driver_attr_max_luns.attr, 463582069379SAkinobu Mita &driver_attr_max_queue.attr, 463682069379SAkinobu Mita &driver_attr_no_uld.attr, 463782069379SAkinobu Mita &driver_attr_scsi_level.attr, 463882069379SAkinobu Mita &driver_attr_virtual_gb.attr, 463982069379SAkinobu Mita &driver_attr_add_host.attr, 464082069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 464182069379SAkinobu Mita &driver_attr_sector_size.attr, 464282069379SAkinobu Mita &driver_attr_dix.attr, 464382069379SAkinobu Mita &driver_attr_dif.attr, 464482069379SAkinobu Mita &driver_attr_guard.attr, 464582069379SAkinobu Mita &driver_attr_ato.attr, 464682069379SAkinobu Mita &driver_attr_map.attr, 464782069379SAkinobu Mita &driver_attr_removable.attr, 4648cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4649cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4650c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 465182069379SAkinobu Mita NULL, 465282069379SAkinobu Mita }; 465382069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 46541da177e4SLinus Torvalds 465511ddcecaSAkinobu Mita static struct device *pseudo_primary; 46568dea0d02SFUJITA Tomonori 46571da177e4SLinus Torvalds static int __init scsi_debug_init(void) 46581da177e4SLinus Torvalds { 46595f2578e5SFUJITA Tomonori unsigned long sz; 46601da177e4SLinus Torvalds int host_to_add; 46611da177e4SLinus Torvalds int k; 46626ecaff7fSRandy Dunlap int ret; 46631da177e4SLinus Torvalds 4664cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4665cbf67842SDouglas Gilbert atomic_set(&sdebug_completions, 0); 4666cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4667cbf67842SDouglas Gilbert 4668cbf67842SDouglas Gilbert if (scsi_debug_ndelay >= 1000000000) { 4669cbf67842SDouglas Gilbert pr_warn("%s: ndelay must be less than 1 second, ignored\n", 4670cbf67842SDouglas Gilbert __func__); 4671cbf67842SDouglas Gilbert scsi_debug_ndelay = 0; 4672cbf67842SDouglas Gilbert } else if (scsi_debug_ndelay > 0) 4673cbf67842SDouglas Gilbert scsi_debug_delay = DELAY_OVERRIDDEN; 4674cbf67842SDouglas Gilbert 4675597136abSMartin K. Petersen switch (scsi_debug_sector_size) { 4676597136abSMartin K. Petersen case 512: 4677597136abSMartin K. Petersen case 1024: 4678597136abSMartin K. Petersen case 2048: 4679597136abSMartin K. Petersen case 4096: 4680597136abSMartin K. Petersen break; 4681597136abSMartin K. Petersen default: 4682cbf67842SDouglas Gilbert pr_err("%s: invalid sector_size %d\n", __func__, 4683597136abSMartin K. Petersen scsi_debug_sector_size); 4684597136abSMartin K. Petersen return -EINVAL; 4685597136abSMartin K. Petersen } 4686597136abSMartin K. Petersen 4687c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 4688c6a44287SMartin K. Petersen 4689c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 4690c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4691395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4692c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4693c6a44287SMartin K. Petersen break; 4694c6a44287SMartin K. Petersen 4695c6a44287SMartin K. Petersen default: 4696cbf67842SDouglas Gilbert pr_err("%s: dif must be 0, 1, 2 or 3\n", __func__); 4697c6a44287SMartin K. Petersen return -EINVAL; 4698c6a44287SMartin K. Petersen } 4699c6a44287SMartin K. Petersen 4700c6a44287SMartin K. Petersen if (scsi_debug_guard > 1) { 4701cbf67842SDouglas Gilbert pr_err("%s: guard must be 0 or 1\n", __func__); 4702c6a44287SMartin K. Petersen return -EINVAL; 4703c6a44287SMartin K. Petersen } 4704c6a44287SMartin K. Petersen 4705c6a44287SMartin K. Petersen if (scsi_debug_ato > 1) { 4706cbf67842SDouglas Gilbert pr_err("%s: ato must be 0 or 1\n", __func__); 4707c6a44287SMartin K. Petersen return -EINVAL; 4708c6a44287SMartin K. Petersen } 4709c6a44287SMartin K. Petersen 4710ea61fca5SMartin K. Petersen if (scsi_debug_physblk_exp > 15) { 4711cbf67842SDouglas Gilbert pr_err("%s: invalid physblk_exp %u\n", __func__, 4712ea61fca5SMartin K. Petersen scsi_debug_physblk_exp); 4713ea61fca5SMartin K. Petersen return -EINVAL; 4714ea61fca5SMartin K. Petersen } 4715ea61fca5SMartin K. Petersen 4716ea61fca5SMartin K. Petersen if (scsi_debug_lowest_aligned > 0x3fff) { 4717cbf67842SDouglas Gilbert pr_err("%s: lowest_aligned too big: %u\n", __func__, 4718ea61fca5SMartin K. Petersen scsi_debug_lowest_aligned); 4719ea61fca5SMartin K. Petersen return -EINVAL; 4720ea61fca5SMartin K. Petersen } 4721ea61fca5SMartin K. Petersen 47221da177e4SLinus Torvalds if (scsi_debug_dev_size_mb < 1) 47231da177e4SLinus Torvalds scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 47245f2578e5SFUJITA Tomonori sz = (unsigned long)scsi_debug_dev_size_mb * 1048576; 4725597136abSMartin K. Petersen sdebug_store_sectors = sz / scsi_debug_sector_size; 472628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 47271da177e4SLinus Torvalds 47281da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 47291da177e4SLinus Torvalds sdebug_heads = 8; 47301da177e4SLinus Torvalds sdebug_sectors_per = 32; 47311da177e4SLinus Torvalds if (scsi_debug_dev_size_mb >= 16) 47321da177e4SLinus Torvalds sdebug_heads = 32; 47331da177e4SLinus Torvalds else if (scsi_debug_dev_size_mb >= 256) 47341da177e4SLinus Torvalds sdebug_heads = 64; 47351da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 47361da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 47371da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 47381da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 47391da177e4SLinus Torvalds sdebug_heads = 255; 47401da177e4SLinus Torvalds sdebug_sectors_per = 63; 47411da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 47421da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 47431da177e4SLinus Torvalds } 47441da177e4SLinus Torvalds 4745cbf67842SDouglas Gilbert if (0 == scsi_debug_fake_rw) { 47461da177e4SLinus Torvalds fake_storep = vmalloc(sz); 47471da177e4SLinus Torvalds if (NULL == fake_storep) { 4748cbf67842SDouglas Gilbert pr_err("%s: out of memory, 1\n", __func__); 47491da177e4SLinus Torvalds return -ENOMEM; 47501da177e4SLinus Torvalds } 47511da177e4SLinus Torvalds memset(fake_storep, 0, sz); 47521da177e4SLinus Torvalds if (scsi_debug_num_parts > 0) 4753f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 4754cbf67842SDouglas Gilbert } 47551da177e4SLinus Torvalds 47567cb69d03SAkinobu Mita if (scsi_debug_dix) { 4757c6a44287SMartin K. Petersen int dif_size; 4758c6a44287SMartin K. Petersen 4759c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 4760c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 4761c6a44287SMartin K. Petersen 4762cbf67842SDouglas Gilbert pr_err("%s: dif_storep %u bytes @ %p\n", __func__, dif_size, 4763cbf67842SDouglas Gilbert dif_storep); 4764c6a44287SMartin K. Petersen 4765c6a44287SMartin K. Petersen if (dif_storep == NULL) { 4766cbf67842SDouglas Gilbert pr_err("%s: out of mem. (DIX)\n", __func__); 4767c6a44287SMartin K. Petersen ret = -ENOMEM; 4768c6a44287SMartin K. Petersen goto free_vm; 4769c6a44287SMartin K. Petersen } 4770c6a44287SMartin K. Petersen 4771c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 4772c6a44287SMartin K. Petersen } 4773c6a44287SMartin K. Petersen 47745b94e232SMartin K. Petersen /* Logical Block Provisioning */ 47755b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 47766014759cSMartin K. Petersen scsi_debug_unmap_max_blocks = 47776014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_blocks, 0U, 0xffffffffU); 47786014759cSMartin K. Petersen 47796014759cSMartin K. Petersen scsi_debug_unmap_max_desc = 47806014759cSMartin K. Petersen clamp(scsi_debug_unmap_max_desc, 0U, 256U); 47816014759cSMartin K. Petersen 47826014759cSMartin K. Petersen scsi_debug_unmap_granularity = 47836014759cSMartin K. Petersen clamp(scsi_debug_unmap_granularity, 1U, 0xffffffffU); 47846014759cSMartin K. Petersen 47856014759cSMartin K. Petersen if (scsi_debug_unmap_alignment && 4786ac17078aSAkinobu Mita scsi_debug_unmap_granularity <= 4787ac17078aSAkinobu Mita scsi_debug_unmap_alignment) { 4788cbf67842SDouglas Gilbert pr_err("%s: ERR: unmap_granularity <= unmap_alignment\n", 478944d92694SMartin K. Petersen __func__); 479044d92694SMartin K. Petersen return -EINVAL; 479144d92694SMartin K. Petersen } 479244d92694SMartin K. Petersen 4793b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 4794b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 479544d92694SMartin K. Petersen 4796cbf67842SDouglas Gilbert pr_info("%s: %lu provisioning blocks\n", __func__, map_size); 479744d92694SMartin K. Petersen 479844d92694SMartin K. Petersen if (map_storep == NULL) { 4799cbf67842SDouglas Gilbert pr_err("%s: out of mem. (MAP)\n", __func__); 480044d92694SMartin K. Petersen ret = -ENOMEM; 480144d92694SMartin K. Petersen goto free_vm; 480244d92694SMartin K. Petersen } 480344d92694SMartin K. Petersen 4804b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 480544d92694SMartin K. Petersen 480644d92694SMartin K. Petersen /* Map first 1KB for partition table */ 480744d92694SMartin K. Petersen if (scsi_debug_num_parts) 480844d92694SMartin K. Petersen map_region(0, 2); 480944d92694SMartin K. Petersen } 481044d92694SMartin K. Petersen 48119b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 48129b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 4813cbf67842SDouglas Gilbert pr_warn("%s: root_device_register() error\n", __func__); 48149b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 48156ecaff7fSRandy Dunlap goto free_vm; 48166ecaff7fSRandy Dunlap } 48176ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 48186ecaff7fSRandy Dunlap if (ret < 0) { 4819cbf67842SDouglas Gilbert pr_warn("%s: bus_register error: %d\n", __func__, ret); 48206ecaff7fSRandy Dunlap goto dev_unreg; 48216ecaff7fSRandy Dunlap } 48226ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 48236ecaff7fSRandy Dunlap if (ret < 0) { 4824cbf67842SDouglas Gilbert pr_warn("%s: driver_register error: %d\n", __func__, ret); 48256ecaff7fSRandy Dunlap goto bus_unreg; 48266ecaff7fSRandy Dunlap } 48271da177e4SLinus Torvalds 48281da177e4SLinus Torvalds host_to_add = scsi_debug_add_host; 48291da177e4SLinus Torvalds scsi_debug_add_host = 0; 48301da177e4SLinus Torvalds 48311da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 48321da177e4SLinus Torvalds if (sdebug_add_adapter()) { 4833cbf67842SDouglas Gilbert pr_err("%s: sdebug_add_adapter failed k=%d\n", 4834cbf67842SDouglas Gilbert __func__, k); 48351da177e4SLinus Torvalds break; 48361da177e4SLinus Torvalds } 48371da177e4SLinus Torvalds } 48381da177e4SLinus Torvalds 48391da177e4SLinus Torvalds if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { 4840cbf67842SDouglas Gilbert pr_info("%s: built %d host(s)\n", __func__, 48411da177e4SLinus Torvalds scsi_debug_add_host); 48421da177e4SLinus Torvalds } 48431da177e4SLinus Torvalds return 0; 48446ecaff7fSRandy Dunlap 48456ecaff7fSRandy Dunlap bus_unreg: 48466ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 48476ecaff7fSRandy Dunlap dev_unreg: 48489b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 48496ecaff7fSRandy Dunlap free_vm: 485044d92694SMartin K. Petersen if (map_storep) 485144d92694SMartin K. Petersen vfree(map_storep); 4852c6a44287SMartin K. Petersen if (dif_storep) 4853c6a44287SMartin K. Petersen vfree(dif_storep); 48546ecaff7fSRandy Dunlap vfree(fake_storep); 48556ecaff7fSRandy Dunlap 48566ecaff7fSRandy Dunlap return ret; 48571da177e4SLinus Torvalds } 48581da177e4SLinus Torvalds 48591da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 48601da177e4SLinus Torvalds { 48611da177e4SLinus Torvalds int k = scsi_debug_add_host; 48621da177e4SLinus Torvalds 48631da177e4SLinus Torvalds stop_all_queued(); 4864cbf67842SDouglas Gilbert free_all_queued(); 48651da177e4SLinus Torvalds for (; k; k--) 48661da177e4SLinus Torvalds sdebug_remove_adapter(); 48671da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 48681da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 48699b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 48701da177e4SLinus Torvalds 4871c6a44287SMartin K. Petersen if (dif_storep) 4872c6a44287SMartin K. Petersen vfree(dif_storep); 4873c6a44287SMartin K. Petersen 48741da177e4SLinus Torvalds vfree(fake_storep); 48751da177e4SLinus Torvalds } 48761da177e4SLinus Torvalds 48771da177e4SLinus Torvalds device_initcall(scsi_debug_init); 48781da177e4SLinus Torvalds module_exit(scsi_debug_exit); 48791da177e4SLinus Torvalds 48801da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 48811da177e4SLinus Torvalds { 48821da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 48831da177e4SLinus Torvalds 48841da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 48851da177e4SLinus Torvalds kfree(sdbg_host); 48861da177e4SLinus Torvalds } 48871da177e4SLinus Torvalds 48881da177e4SLinus Torvalds static int sdebug_add_adapter(void) 48891da177e4SLinus Torvalds { 48901da177e4SLinus Torvalds int k, devs_per_host; 48911da177e4SLinus Torvalds int error = 0; 48921da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 48938b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 48941da177e4SLinus Torvalds 489524669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 48961da177e4SLinus Torvalds if (NULL == sdbg_host) { 48971da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 4898cadbd4a5SHarvey Harrison __func__, __LINE__); 48991da177e4SLinus Torvalds return -ENOMEM; 49001da177e4SLinus Torvalds } 49011da177e4SLinus Torvalds 49021da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 49031da177e4SLinus Torvalds 49041da177e4SLinus Torvalds devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; 49051da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 49065cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 49075cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 49081da177e4SLinus Torvalds printk(KERN_ERR "%s: out of memory at line %d\n", 4909cadbd4a5SHarvey Harrison __func__, __LINE__); 49101da177e4SLinus Torvalds error = -ENOMEM; 49111da177e4SLinus Torvalds goto clean; 49121da177e4SLinus Torvalds } 49131da177e4SLinus Torvalds } 49141da177e4SLinus Torvalds 49151da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 49161da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 49171da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 49181da177e4SLinus Torvalds 49191da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 49209b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 49211da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 492271610f55SKay Sievers dev_set_name(&sdbg_host->dev, "adapter%d", scsi_debug_add_host); 49231da177e4SLinus Torvalds 49241da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 49251da177e4SLinus Torvalds 49261da177e4SLinus Torvalds if (error) 49271da177e4SLinus Torvalds goto clean; 49281da177e4SLinus Torvalds 49291da177e4SLinus Torvalds ++scsi_debug_add_host; 49301da177e4SLinus Torvalds return error; 49311da177e4SLinus Torvalds 49321da177e4SLinus Torvalds clean: 49338b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 49348b40228fSFUJITA Tomonori dev_list) { 49351da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 49361da177e4SLinus Torvalds kfree(sdbg_devinfo); 49371da177e4SLinus Torvalds } 49381da177e4SLinus Torvalds 49391da177e4SLinus Torvalds kfree(sdbg_host); 49401da177e4SLinus Torvalds return error; 49411da177e4SLinus Torvalds } 49421da177e4SLinus Torvalds 49431da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 49441da177e4SLinus Torvalds { 49451da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 49461da177e4SLinus Torvalds 49471da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 49481da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 49491da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 49501da177e4SLinus Torvalds struct sdebug_host_info, host_list); 49511da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 49521da177e4SLinus Torvalds } 49531da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 49541da177e4SLinus Torvalds 49551da177e4SLinus Torvalds if (!sdbg_host) 49561da177e4SLinus Torvalds return; 49571da177e4SLinus Torvalds 49581da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 49591da177e4SLinus Torvalds --scsi_debug_add_host; 49601da177e4SLinus Torvalds } 49611da177e4SLinus Torvalds 4962cbf67842SDouglas Gilbert static int 4963db5ed4dfSChristoph Hellwig sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 4964cbf67842SDouglas Gilbert { 4965cbf67842SDouglas Gilbert int num_in_q = 0; 4966cbf67842SDouglas Gilbert unsigned long iflags; 4967cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4968cbf67842SDouglas Gilbert 4969cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4970cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 4971cbf67842SDouglas Gilbert if (NULL == devip) { 4972cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4973cbf67842SDouglas Gilbert return -ENODEV; 4974cbf67842SDouglas Gilbert } 4975cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 4976cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4977c40ecc12SChristoph Hellwig 4978cbf67842SDouglas Gilbert if (qdepth < 1) 4979cbf67842SDouglas Gilbert qdepth = 1; 4980cbf67842SDouglas Gilbert /* allow to exceed max host queued_arr elements for testing */ 4981cbf67842SDouglas Gilbert if (qdepth > SCSI_DEBUG_CANQUEUE + 10) 4982cbf67842SDouglas Gilbert qdepth = SCSI_DEBUG_CANQUEUE + 10; 4983db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 4984cbf67842SDouglas Gilbert 4985c40ecc12SChristoph Hellwig if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) { 4986cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdev, 4987c40ecc12SChristoph Hellwig "%s: qdepth=%d, num_in_q=%d\n", 4988c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 4989cbf67842SDouglas Gilbert } 4990cbf67842SDouglas Gilbert return sdev->queue_depth; 4991cbf67842SDouglas Gilbert } 4992cbf67842SDouglas Gilbert 4993cbf67842SDouglas Gilbert static int 4994817fd66bSDouglas Gilbert check_inject(struct scsi_cmnd *scp) 4995817fd66bSDouglas Gilbert { 4996817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 4997817fd66bSDouglas Gilbert 4998817fd66bSDouglas Gilbert memset(ep, 0, sizeof(struct sdebug_scmd_extra_t)); 4999817fd66bSDouglas Gilbert 5000817fd66bSDouglas Gilbert if (atomic_inc_return(&sdebug_cmnd_count) >= 5001817fd66bSDouglas Gilbert abs(scsi_debug_every_nth)) { 5002817fd66bSDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5003817fd66bSDouglas Gilbert if (scsi_debug_every_nth < -1) 5004817fd66bSDouglas Gilbert scsi_debug_every_nth = -1; 5005817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts) 5006817fd66bSDouglas Gilbert return 1; /* ignore command causing timeout */ 5007817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts && 5008817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5009817fd66bSDouglas Gilbert return 1; /* time out reads and writes */ 5010817fd66bSDouglas Gilbert if (sdebug_any_injecting_opt) { 5011817fd66bSDouglas Gilbert int opts = scsi_debug_opts; 5012817fd66bSDouglas Gilbert 5013817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 5014817fd66bSDouglas Gilbert ep->inj_recovered = true; 5015817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 5016817fd66bSDouglas Gilbert ep->inj_transport = true; 5017817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 5018817fd66bSDouglas Gilbert ep->inj_dif = true; 5019817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 5020817fd66bSDouglas Gilbert ep->inj_dix = true; 5021817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 5022817fd66bSDouglas Gilbert ep->inj_short = true; 5023817fd66bSDouglas Gilbert } 5024817fd66bSDouglas Gilbert } 5025817fd66bSDouglas Gilbert return 0; 5026817fd66bSDouglas Gilbert } 5027817fd66bSDouglas Gilbert 5028c2248fc9SDouglas Gilbert static int 5029c2248fc9SDouglas Gilbert scsi_debug_queuecommand(struct scsi_cmnd *scp) 5030c2248fc9SDouglas Gilbert { 5031c2248fc9SDouglas Gilbert u8 sdeb_i; 5032c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5033c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5034c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5035c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5036c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5037c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5038c2248fc9SDouglas Gilbert int k, na; 5039c2248fc9SDouglas Gilbert int errsts = 0; 5040c2248fc9SDouglas Gilbert int errsts_no_connect = DID_NO_CONNECT << 16; 5041c2248fc9SDouglas Gilbert u32 flags; 5042c2248fc9SDouglas Gilbert u16 sa; 5043c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5044c2248fc9SDouglas Gilbert bool has_wlun_rl; 5045c2248fc9SDouglas Gilbert bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts); 5046c2248fc9SDouglas Gilbert 5047c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5048c2248fc9SDouglas Gilbert if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) { 5049c2248fc9SDouglas Gilbert char b[120]; 5050c2248fc9SDouglas Gilbert int n, len, sb; 5051c2248fc9SDouglas Gilbert 5052c2248fc9SDouglas Gilbert len = scp->cmd_len; 5053c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5054c2248fc9SDouglas Gilbert if (len > 32) 5055c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5056c2248fc9SDouglas Gilbert else { 5057c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5058c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5059c2248fc9SDouglas Gilbert (u32)cmd[k]); 5060c2248fc9SDouglas Gilbert } 5061c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b); 5062c2248fc9SDouglas Gilbert } 5063c2248fc9SDouglas Gilbert has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS); 5064c2248fc9SDouglas Gilbert if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl) 5065c2248fc9SDouglas Gilbert return schedule_resp(scp, NULL, errsts_no_connect, 0); 5066c2248fc9SDouglas Gilbert 5067c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5068c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5069c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5070c2248fc9SDouglas Gilbert if (!devip) { 5071c2248fc9SDouglas Gilbert devip = devInfoReg(sdp); 5072c2248fc9SDouglas Gilbert if (NULL == devip) 5073c2248fc9SDouglas Gilbert return schedule_resp(scp, NULL, errsts_no_connect, 0); 5074c2248fc9SDouglas Gilbert } 5075c2248fc9SDouglas Gilbert na = oip->num_attached; 5076c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5077c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5078c2248fc9SDouglas Gilbert r_oip = oip; 5079c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5080c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5081c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5082c2248fc9SDouglas Gilbert else 5083c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5084c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5085c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5086c2248fc9SDouglas Gilbert break; 5087c2248fc9SDouglas Gilbert } 5088c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5089c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5090c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5091c2248fc9SDouglas Gilbert break; 5092c2248fc9SDouglas Gilbert } 5093c2248fc9SDouglas Gilbert } 5094c2248fc9SDouglas Gilbert if (k > na) { 5095c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5096c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5097c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5098c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5099c2248fc9SDouglas Gilbert else 5100c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5101c2248fc9SDouglas Gilbert goto check_cond; 5102c2248fc9SDouglas Gilbert } 5103c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5104c2248fc9SDouglas Gilbert flags = oip->flags; 5105c2248fc9SDouglas Gilbert if (F_INV_OP & flags) { 5106c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5107c2248fc9SDouglas Gilbert goto check_cond; 5108c2248fc9SDouglas Gilbert } 5109c2248fc9SDouglas Gilbert if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) { 5110c2248fc9SDouglas Gilbert if (debug) 5111c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: " 5112c2248fc9SDouglas Gilbert "0x%x not supported for wlun\n", opcode); 5113c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5114c2248fc9SDouglas Gilbert goto check_cond; 5115c2248fc9SDouglas Gilbert } 5116c2248fc9SDouglas Gilbert if (scsi_debug_strict) { /* check cdb against mask */ 5117c2248fc9SDouglas Gilbert u8 rem; 5118c2248fc9SDouglas Gilbert int j; 5119c2248fc9SDouglas Gilbert 5120c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5121c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5122c2248fc9SDouglas Gilbert if (rem) { 5123c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5124c2248fc9SDouglas Gilbert if (0x80 & rem) 5125c2248fc9SDouglas Gilbert break; 5126c2248fc9SDouglas Gilbert } 5127c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5128c2248fc9SDouglas Gilbert goto check_cond; 5129c2248fc9SDouglas Gilbert } 5130c2248fc9SDouglas Gilbert } 5131c2248fc9SDouglas Gilbert } 5132c2248fc9SDouglas Gilbert if (!(F_SKIP_UA & flags) && 5133c2248fc9SDouglas Gilbert SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) { 5134c2248fc9SDouglas Gilbert errsts = check_readiness(scp, UAS_ONLY, devip); 5135c2248fc9SDouglas Gilbert if (errsts) 5136c2248fc9SDouglas Gilbert goto check_cond; 5137c2248fc9SDouglas Gilbert } 5138c2248fc9SDouglas Gilbert if ((F_M_ACCESS & flags) && devip->stopped) { 5139c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5140c2248fc9SDouglas Gilbert if (debug) 5141c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5142c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5143c2248fc9SDouglas Gilbert "required"); 5144c2248fc9SDouglas Gilbert errsts = check_condition_result; 5145c2248fc9SDouglas Gilbert goto fini; 5146c2248fc9SDouglas Gilbert } 5147c2248fc9SDouglas Gilbert if (scsi_debug_fake_rw && (F_FAKE_RW & flags)) 5148c2248fc9SDouglas Gilbert goto fini; 5149c2248fc9SDouglas Gilbert if (scsi_debug_every_nth) { 5150c2248fc9SDouglas Gilbert if (check_inject(scp)) 5151c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5152c2248fc9SDouglas Gilbert } 5153c2248fc9SDouglas Gilbert if (oip->pfp) /* if this command has a resp_* function, call it */ 5154c2248fc9SDouglas Gilbert errsts = oip->pfp(scp, devip); 5155c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5156c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5157c2248fc9SDouglas Gilbert 5158c2248fc9SDouglas Gilbert fini: 5159c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5160c2248fc9SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay)); 5161c2248fc9SDouglas Gilbert check_cond: 5162c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5163c2248fc9SDouglas Gilbert } 5164c2248fc9SDouglas Gilbert 516538d5c833SDouglas Gilbert static int 516638d5c833SDouglas Gilbert sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 516738d5c833SDouglas Gilbert { 516838d5c833SDouglas Gilbert if (scsi_debug_host_lock) { 516938d5c833SDouglas Gilbert unsigned long iflags; 517038d5c833SDouglas Gilbert int rc; 517138d5c833SDouglas Gilbert 517238d5c833SDouglas Gilbert spin_lock_irqsave(shost->host_lock, iflags); 517338d5c833SDouglas Gilbert rc = scsi_debug_queuecommand(cmd); 517438d5c833SDouglas Gilbert spin_unlock_irqrestore(shost->host_lock, iflags); 517538d5c833SDouglas Gilbert return rc; 517638d5c833SDouglas Gilbert } else 517738d5c833SDouglas Gilbert return scsi_debug_queuecommand(cmd); 517838d5c833SDouglas Gilbert } 517938d5c833SDouglas Gilbert 51809e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5181c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5182c8ed555aSAl Viro .write_info = scsi_debug_write_info, 51839e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 51849e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 51859e603ca0SFUJITA Tomonori .info = scsi_debug_info, 51869e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 51879e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 51889e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 51899e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5190cbf67842SDouglas Gilbert .queuecommand = sdebug_queuecommand_lock_or_not, 5191cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 51929e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 51939e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5194cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5195cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 51969e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 51979e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 51989e603ca0SFUJITA Tomonori .this_id = 7, 51996bb5e6e7SAkinobu Mita .sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS, 5200cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 52016bb5e6e7SAkinobu Mita .max_sectors = -1U, 52029e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 52039e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5204c40ecc12SChristoph Hellwig .track_queue_depth = 1, 5205817fd66bSDouglas Gilbert .cmd_size = sizeof(struct sdebug_scmd_extra_t), 52069e603ca0SFUJITA Tomonori }; 52079e603ca0SFUJITA Tomonori 52081da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 52091da177e4SLinus Torvalds { 52101da177e4SLinus Torvalds int error = 0; 5211817fd66bSDouglas Gilbert int opts; 52121da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 52131da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5214c6a44287SMartin K. Petersen int host_prot; 52151da177e4SLinus Torvalds 52161da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 52171da177e4SLinus Torvalds 521878d4e5a0SDouglas Gilbert sdebug_driver_template.can_queue = scsi_debug_max_queue; 52190759c666SAkinobu Mita if (scsi_debug_clustering) 52200759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 52211da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 52221da177e4SLinus Torvalds if (NULL == hpnt) { 522317c9ff52SFinn Thain pr_err("%s: scsi_host_alloc failed\n", __func__); 52241da177e4SLinus Torvalds error = -ENODEV; 52251da177e4SLinus Torvalds return error; 52261da177e4SLinus Torvalds } 52271da177e4SLinus Torvalds 52281da177e4SLinus Torvalds sdbg_host->shost = hpnt; 52291da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 52301da177e4SLinus Torvalds if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) 52311da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts + 1; 52321da177e4SLinus Torvalds else 52331da177e4SLinus Torvalds hpnt->max_id = scsi_debug_num_tgts; 5234c65b1445SDouglas Gilbert hpnt->max_lun = SAM2_WLUN_REPORT_LUNS; /* = scsi_debug_max_luns; */ 52351da177e4SLinus Torvalds 5236c6a44287SMartin K. Petersen host_prot = 0; 5237c6a44287SMartin K. Petersen 5238c6a44287SMartin K. Petersen switch (scsi_debug_dif) { 5239c6a44287SMartin K. Petersen 5240c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 5241c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE1_PROTECTION; 5242c6a44287SMartin K. Petersen if (scsi_debug_dix) 5243c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE1_PROTECTION; 5244c6a44287SMartin K. Petersen break; 5245c6a44287SMartin K. Petersen 5246c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 5247c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE2_PROTECTION; 5248c6a44287SMartin K. Petersen if (scsi_debug_dix) 5249c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE2_PROTECTION; 5250c6a44287SMartin K. Petersen break; 5251c6a44287SMartin K. Petersen 5252c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 5253c6a44287SMartin K. Petersen host_prot = SHOST_DIF_TYPE3_PROTECTION; 5254c6a44287SMartin K. Petersen if (scsi_debug_dix) 5255c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE3_PROTECTION; 5256c6a44287SMartin K. Petersen break; 5257c6a44287SMartin K. Petersen 5258c6a44287SMartin K. Petersen default: 5259c6a44287SMartin K. Petersen if (scsi_debug_dix) 5260c6a44287SMartin K. Petersen host_prot |= SHOST_DIX_TYPE0_PROTECTION; 5261c6a44287SMartin K. Petersen break; 5262c6a44287SMartin K. Petersen } 5263c6a44287SMartin K. Petersen 5264c6a44287SMartin K. Petersen scsi_host_set_prot(hpnt, host_prot); 5265c6a44287SMartin K. Petersen 5266c6a44287SMartin K. Petersen printk(KERN_INFO "scsi_debug: host protection%s%s%s%s%s%s%s\n", 5267c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5268c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5269c6a44287SMartin K. Petersen (host_prot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5270c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5271c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5272c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5273c6a44287SMartin K. Petersen (host_prot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5274c6a44287SMartin K. Petersen 5275c6a44287SMartin K. Petersen if (scsi_debug_guard == 1) 5276c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5277c6a44287SMartin K. Petersen else 5278c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5279c6a44287SMartin K. Petersen 5280817fd66bSDouglas Gilbert opts = scsi_debug_opts; 5281817fd66bSDouglas Gilbert if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts) 5282817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5283817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts) 5284817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5285817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIF_ERR & opts) 5286817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5287817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_DIX_ERR & opts) 5288817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5289817fd66bSDouglas Gilbert else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts) 5290817fd66bSDouglas Gilbert sdebug_any_injecting_opt = true; 5291817fd66bSDouglas Gilbert 52921da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 52931da177e4SLinus Torvalds if (error) { 5294cadbd4a5SHarvey Harrison printk(KERN_ERR "%s: scsi_add_host failed\n", __func__); 52951da177e4SLinus Torvalds error = -ENODEV; 52961da177e4SLinus Torvalds scsi_host_put(hpnt); 52971da177e4SLinus Torvalds } else 52981da177e4SLinus Torvalds scsi_scan_host(hpnt); 52991da177e4SLinus Torvalds 53001da177e4SLinus Torvalds return error; 53011da177e4SLinus Torvalds } 53021da177e4SLinus Torvalds 53031da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 53041da177e4SLinus Torvalds { 53051da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 53068b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 53071da177e4SLinus Torvalds 53081da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 53091da177e4SLinus Torvalds 53101da177e4SLinus Torvalds if (!sdbg_host) { 53111da177e4SLinus Torvalds printk(KERN_ERR "%s: Unable to locate host info\n", 5312cadbd4a5SHarvey Harrison __func__); 53131da177e4SLinus Torvalds return -ENODEV; 53141da177e4SLinus Torvalds } 53151da177e4SLinus Torvalds 53161da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 53171da177e4SLinus Torvalds 53188b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 53198b40228fSFUJITA Tomonori dev_list) { 53201da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 53211da177e4SLinus Torvalds kfree(sdbg_devinfo); 53221da177e4SLinus Torvalds } 53231da177e4SLinus Torvalds 53241da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 53251da177e4SLinus Torvalds return 0; 53261da177e4SLinus Torvalds } 53271da177e4SLinus Torvalds 53288dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 53298dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 53301da177e4SLinus Torvalds { 53318dea0d02SFUJITA Tomonori return 1; 53328dea0d02SFUJITA Tomonori } 53331da177e4SLinus Torvalds 53348dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 53358dea0d02SFUJITA Tomonori .name = "pseudo", 53368dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 53378dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 53388dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 533982069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 53408dea0d02SFUJITA Tomonori }; 5341