18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 41da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 51da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 61da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 71da177e4SLinus Torvalds * anything out of the ordinary is seen. 81da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 91da177e4SLinus Torvalds * 1048e3bf16SDouglas Gilbert * Copyright (C) 2001 - 2020 Douglas Gilbert 111da177e4SLinus Torvalds * 1278d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 15c1287970STomas Winkler 16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 17c1287970STomas Winkler 181da177e4SLinus Torvalds #include <linux/module.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include <linux/kernel.h> 211da177e4SLinus Torvalds #include <linux/errno.h> 22b333a819SDouglas Gilbert #include <linux/jiffies.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 241da177e4SLinus Torvalds #include <linux/types.h> 251da177e4SLinus Torvalds #include <linux/string.h> 261da177e4SLinus Torvalds #include <linux/genhd.h> 271da177e4SLinus Torvalds #include <linux/fs.h> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <linux/proc_fs.h> 301da177e4SLinus Torvalds #include <linux/vmalloc.h> 311da177e4SLinus Torvalds #include <linux/moduleparam.h> 32852e034dSJens Axboe #include <linux/scatterlist.h> 331da177e4SLinus Torvalds #include <linux/blkdev.h> 34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 35cbf67842SDouglas Gilbert #include <linux/spinlock.h> 36cbf67842SDouglas Gilbert #include <linux/interrupt.h> 37cbf67842SDouglas Gilbert #include <linux/atomic.h> 38cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 3909ba24c1SDouglas Gilbert #include <linux/uuid.h> 406ebf105cSChristoph Hellwig #include <linux/t10-pi.h> 411442f76dSChristoph Hellwig #include <linux/msdos_partition.h> 420c4bc91dSDouglas Gilbert #include <linux/random.h> 4387c715dcSDouglas Gilbert #include <linux/xarray.h> 44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h> 45c6a44287SMartin K. Petersen 46c6a44287SMartin K. Petersen #include <net/checksum.h> 479ff26eefSFUJITA Tomonori 4844d92694SMartin K. Petersen #include <asm/unaligned.h> 4944d92694SMartin K. Petersen 509ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 531da177e4SLinus Torvalds #include <scsi/scsi_host.h> 541da177e4SLinus Torvalds #include <scsi/scsicam.h> 55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 581da177e4SLinus Torvalds 59c6a44287SMartin K. Petersen #include "sd.h" 601da177e4SLinus Torvalds #include "scsi_logging.h" 611da177e4SLinus Torvalds 62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 6348e3bf16SDouglas Gilbert #define SDEBUG_VERSION "0189" /* format to fit INQUIRY revision field */ 6448e3bf16SDouglas Gilbert static const char *sdebug_version_date = "20200421"; 65cbf67842SDouglas Gilbert 66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 671da177e4SLinus Torvalds 686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27 79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 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 94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc 97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4 98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5 99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6 100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7 101f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe 1021da177e4SLinus Torvalds 1036f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 1046f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 1056f3cbf55SDouglas Gilbert 1061da177e4SLinus Torvalds /* Default values for driver parameters */ 1071da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1081da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1091da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1101da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1111da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1121da177e4SLinus Torvalds */ 1135b94e232SMartin K. Petersen #define DEF_ATO 1 1149b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10 115c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1169267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT 0 1171da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1189267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB 128 1195b94e232SMartin K. Petersen #define DEF_DIF 0 1205b94e232SMartin K. Petersen #define DEF_DIX 0 12187c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false 1225b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1231da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1245b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1255b94e232SMartin K. Petersen #define DEF_GUARD 0 126cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1275b94e232SMartin K. Petersen #define DEF_LBPU 0 1285b94e232SMartin K. Petersen #define DEF_LBPWS 0 1295b94e232SMartin K. Petersen #define DEF_LBPWS10 0 130be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1315b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 132cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1335b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1341da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1351da177e4SLinus Torvalds #define DEF_OPTS 0 13632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1375b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 13886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 139b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 1400c4bc91dSDouglas Gilbert #define DEF_RANDOM false 141d986788bSMartin Pitt #define DEF_REMOVABLE false 142760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1435b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1445b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1455b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1466014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1485b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1495b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1505b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 151c2248fc9SDouglas Gilbert #define DEF_STRICT 0 152c4837394SDouglas Gilbert #define DEF_STATISTICS false 153c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 15409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 155c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1561da177e4SLinus Torvalds 157f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */ 158f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB 128 159f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES 8 160aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES 1 161f0d1cf93SDouglas Gilbert 162b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 163b01f6f83SDouglas Gilbert 164773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 165773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 166773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 167773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 168773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 169773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 172773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 173773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 174773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 175773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 176773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 177773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 178773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 179773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1807ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 1817382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT 0x10000 182773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 183773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 185773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 186773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1877ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1887382f9d8SDouglas Gilbert SDEBUG_OPT_HOST_BUSY | \ 1897382f9d8SDouglas Gilbert SDEBUG_OPT_CMD_ABORT) 1901da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 191fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1921da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 193773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1946f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 195773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1967382f9d8SDouglas Gilbert * - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and 1977382f9d8SDouglas Gilbert * CMD_ABORT 1981da177e4SLinus Torvalds * 1997382f9d8SDouglas Gilbert * When "every_nth" < 0 then after "- every_nth" commands the selected 2007382f9d8SDouglas Gilbert * error will be injected. The error will be injected on every subsequent 2017382f9d8SDouglas Gilbert * command until some other action occurs; for example, the user writing 2027382f9d8SDouglas Gilbert * a new value (other than -1 or 1) to every_nth: 2037382f9d8SDouglas Gilbert * echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth 2041da177e4SLinus Torvalds */ 2051da177e4SLinus Torvalds 206cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 207cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 208cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 209cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 210cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 211cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 212cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 2130d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 21419c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 215acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 216acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 217acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 218cbf67842SDouglas Gilbert 219773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2201da177e4SLinus Torvalds * sector on read commands: */ 2211da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 22232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2251da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2261da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2271da177e4SLinus Torvalds 228c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 229c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 230c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 231c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 232c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 233c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 234c4837394SDouglas Gilbert */ 235c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 236c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 237cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 238cbf67842SDouglas Gilbert 239b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */ 240b6ff8ca7SDouglas Gilbert #define F_D_IN 1 /* Data-in command (e.g. READ) */ 241b6ff8ca7SDouglas Gilbert #define F_D_OUT 2 /* Data-out command (e.g. WRITE) */ 242fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 243fd32119bSDouglas Gilbert #define F_D_UNKN 8 244b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK 0x10 /* allowed with REPORT LUNS W-LUN */ 245b6ff8ca7SDouglas Gilbert #define F_SKIP_UA 0x20 /* bypass UAs (e.g. INQUIRY command) */ 246b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR 0x40 /* for commands like INQUIRY */ 247b6ff8ca7SDouglas Gilbert #define F_SA_LOW 0x80 /* SA is in cdb byte 1, bits 4 to 0 */ 248b6ff8ca7SDouglas Gilbert #define F_SA_HIGH 0x100 /* SA is in cdb bytes 8 and 9 */ 249b6ff8ca7SDouglas Gilbert #define F_INV_OP 0x200 /* invalid opcode (not supported) */ 250b6ff8ca7SDouglas Gilbert #define F_FAKE_RW 0x400 /* bypass resp_*() when fake_rw set */ 251b6ff8ca7SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access, reacts to SSU state */ 252b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY 0x1000 /* SSU command delay (long-ish) */ 253b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY 0x2000 /* SYNCHRONIZE CACHE delay */ 254fd32119bSDouglas Gilbert 255b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */ 256fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 25746f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 258fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2594f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 260fd32119bSDouglas Gilbert 261fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 262fd32119bSDouglas Gilbert 263b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 264fd32119bSDouglas Gilbert 26587c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 26687c715dcSDouglas Gilbert 26764e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */ 26864e14eceSDamien Le Moal enum sdebug_z_type { 26964e14eceSDamien Le Moal ZBC_ZONE_TYPE_CNV = 0x1, 27064e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWR = 0x2, 27164e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWP = 0x3, 27264e14eceSDamien Le Moal }; 27364e14eceSDamien Le Moal 274f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 275f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 276f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 277f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 278f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 279f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 280f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 281f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 282f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 283f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 284f0d1cf93SDouglas Gilbert }; 285f0d1cf93SDouglas Gilbert 286f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 28764e14eceSDamien Le Moal enum sdebug_z_type z_type; 288f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 28964e14eceSDamien Le Moal bool z_non_seq_resource; 290f0d1cf93SDouglas Gilbert unsigned int z_size; 291f0d1cf93SDouglas Gilbert sector_t z_start; 292f0d1cf93SDouglas Gilbert sector_t z_wp; 293f0d1cf93SDouglas Gilbert }; 294fd32119bSDouglas Gilbert 295fd32119bSDouglas Gilbert struct sdebug_dev_info { 296fd32119bSDouglas Gilbert struct list_head dev_list; 297fd32119bSDouglas Gilbert unsigned int channel; 298fd32119bSDouglas Gilbert unsigned int target; 299fd32119bSDouglas Gilbert u64 lun; 300bf476433SChristoph Hellwig uuid_t lu_name; 301fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 302fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 303fd32119bSDouglas Gilbert atomic_t num_in_q; 304c4837394SDouglas Gilbert atomic_t stopped; 305fd32119bSDouglas Gilbert bool used; 306f0d1cf93SDouglas Gilbert 307f0d1cf93SDouglas Gilbert /* For ZBC devices */ 30864e14eceSDamien Le Moal enum blk_zoned_model zmodel; 309f0d1cf93SDouglas Gilbert unsigned int zsize; 310f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 311f0d1cf93SDouglas Gilbert unsigned int nr_zones; 312aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 313f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 314f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 315f0d1cf93SDouglas Gilbert unsigned int nr_closed; 316f0d1cf93SDouglas Gilbert unsigned int max_open; 317f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 318fd32119bSDouglas Gilbert }; 319fd32119bSDouglas Gilbert 320fd32119bSDouglas Gilbert struct sdebug_host_info { 321fd32119bSDouglas Gilbert struct list_head host_list; 32287c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 323fd32119bSDouglas Gilbert struct Scsi_Host *shost; 324fd32119bSDouglas Gilbert struct device dev; 325fd32119bSDouglas Gilbert struct list_head dev_info_list; 326fd32119bSDouglas Gilbert }; 327fd32119bSDouglas Gilbert 32887c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 32987c715dcSDouglas Gilbert struct sdeb_store_info { 33087c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 33187c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 33287c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 33387c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 33487c715dcSDouglas Gilbert }; 33587c715dcSDouglas Gilbert 336fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 337fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 338fd32119bSDouglas Gilbert 33910bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 34010bde980SDouglas Gilbert SDEB_DEFER_WQ = 2}; 34110bde980SDouglas Gilbert 342fd32119bSDouglas Gilbert struct sdebug_defer { 343fd32119bSDouglas Gilbert struct hrtimer hrt; 344fd32119bSDouglas Gilbert struct execute_work ew; 345c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 346c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 347c4837394SDouglas Gilbert int issuing_cpu; 34810bde980SDouglas Gilbert bool init_hrt; 34910bde980SDouglas Gilbert bool init_wq; 3507382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 35110bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 352fd32119bSDouglas Gilbert }; 353fd32119bSDouglas Gilbert 354fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 355c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 356c4837394SDouglas Gilbert * instance indicates this slot is in use. 357c4837394SDouglas Gilbert */ 358fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 359fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 360c4837394SDouglas Gilbert unsigned int inj_recovered:1; 361c4837394SDouglas Gilbert unsigned int inj_transport:1; 362c4837394SDouglas Gilbert unsigned int inj_dif:1; 363c4837394SDouglas Gilbert unsigned int inj_dix:1; 364c4837394SDouglas Gilbert unsigned int inj_short:1; 3657ee6d1b4SBart Van Assche unsigned int inj_host_busy:1; 3667382f9d8SDouglas Gilbert unsigned int inj_cmd_abort:1; 367fd32119bSDouglas Gilbert }; 368fd32119bSDouglas Gilbert 369c4837394SDouglas Gilbert struct sdebug_queue { 370c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 371c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 372c4837394SDouglas Gilbert spinlock_t qc_lock; 373c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 374fd32119bSDouglas Gilbert }; 375fd32119bSDouglas Gilbert 376c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 377c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 378c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 379c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 380c4837394SDouglas Gilbert 381fd32119bSDouglas Gilbert struct opcode_info_t { 382b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 383b01f6f83SDouglas Gilbert /* for terminating element */ 384fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 385fd32119bSDouglas Gilbert u16 sa; /* service action */ 386fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 387fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 388fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3899a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3909a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 391fd32119bSDouglas Gilbert }; 392fd32119bSDouglas Gilbert 393fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 394c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 395c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 396c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 397c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 398c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 399c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 400c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 401c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 402c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 403c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 404c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 405c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 406c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 40746f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 40846f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 409c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 410c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 411c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 412481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 413c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 414c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 415c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 416c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 417c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 418c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 419c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 420c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 421c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 422c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 423c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 424ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 425f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 426f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 427f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 428c2248fc9SDouglas Gilbert }; 429c2248fc9SDouglas Gilbert 430c4837394SDouglas Gilbert 431c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 432c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 433c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 434c2248fc9SDouglas Gilbert 0, 0, 0, 0, 435c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 436c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 437c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 438c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 439c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 440c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 441c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 442c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 443ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 444c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 445c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 446c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 447c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 448c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 449c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 450c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 451fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 452c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 453c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 455c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 456c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 457c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 458c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 459f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 460f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 46146f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 462c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 463c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 464c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 46546f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 46646f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 467c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 468c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 469c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 470c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 471c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 472c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 473c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 474c2248fc9SDouglas Gilbert }; 475c2248fc9SDouglas Gilbert 47680c49563SDouglas Gilbert /* 47780c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 47880c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 47980c49563SDouglas Gilbert * command completion, they can mask their return value with 48080c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 48180c49563SDouglas Gilbert */ 48280c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 48380c49563SDouglas Gilbert 484c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 485c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 486c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 487c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 488c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 489c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 490c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 491c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 492c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 493481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 494c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 495c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 496c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 497c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 498c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 49938d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 50038d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 501c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 502c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 503c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 50438d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 505acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 50680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 507ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 508f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 509f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 510f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 511f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 512f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 513c2248fc9SDouglas Gilbert 51487c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 51587c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 51687c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 51787c715dcSDouglas Gilbert static int sdebug_add_store(void); 51887c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 51987c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 52087c715dcSDouglas Gilbert 52146f64e70SDouglas Gilbert /* 52246f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 52346f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 52446f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 52546f64e70SDouglas Gilbert */ 52646f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 527c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 528c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 529c2248fc9SDouglas Gilbert }; 530c2248fc9SDouglas Gilbert 53146f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 532c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 533c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 534c2248fc9SDouglas Gilbert }; 535c2248fc9SDouglas Gilbert 53646f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 53746f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 538b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 539c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 54046f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 541c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 54246f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 543b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 544c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 545c2248fc9SDouglas Gilbert }; 546c2248fc9SDouglas Gilbert 54746f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 54846f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 54946f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 55046f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 55146f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 55246f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 55346f64e70SDouglas Gilbert 0, 0, 0} }, 55446f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 55546f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55646f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 557c2248fc9SDouglas Gilbert }; 558c2248fc9SDouglas Gilbert 559c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 560c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 561c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 562c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 563c3e2fe92SDouglas Gilbert }; 564c3e2fe92SDouglas Gilbert 56546f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 566c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 567c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 56846f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 569c2248fc9SDouglas Gilbert }; 570c2248fc9SDouglas Gilbert 57146f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 57246f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 573b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 574c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 575481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 576481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 577481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 578c2248fc9SDouglas Gilbert }; 579c2248fc9SDouglas Gilbert 58046f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 58138d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 582c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 58346f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 58438d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 585c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 58646f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 587c2248fc9SDouglas Gilbert }; 588c2248fc9SDouglas Gilbert 58946f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 59046f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 591c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59246f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 593c2248fc9SDouglas Gilbert }; 594c2248fc9SDouglas Gilbert 59546f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 596c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 597c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 598c2248fc9SDouglas Gilbert }; 599c2248fc9SDouglas Gilbert 60046f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 601c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 602c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 603c2248fc9SDouglas Gilbert }; 604c2248fc9SDouglas Gilbert 60580c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 6064f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 60780c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 60880c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 60980c49563SDouglas Gilbert }; 61080c49563SDouglas Gilbert 611ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 612b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 613ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 614ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 615ed9f3e25SDouglas Gilbert }; 616ed9f3e25SDouglas Gilbert 617f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 618b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 619f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 620f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 621b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 622f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 623f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 624b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 625f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 626f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 627f0d1cf93SDouglas Gilbert }; 628f0d1cf93SDouglas Gilbert 629f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 630b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 631f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 632f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 633f0d1cf93SDouglas Gilbert }; 634f0d1cf93SDouglas Gilbert 635c2248fc9SDouglas Gilbert 636c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 637c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 638c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 639ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 640c2248fc9SDouglas Gilbert /* 0 */ 64146f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 642c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 64346f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 644c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 645c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 646c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 64746f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 648c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 649c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 650c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 651c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 65246f64e70SDouglas Gilbert /* 5 */ 65346f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 65446f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 65546f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 65646f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 65746f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 65846f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 65946f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 660c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 661c2248fc9SDouglas Gilbert 0, 0, 0} }, 66246f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 663c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 664c2248fc9SDouglas Gilbert 0, 0} }, 66546f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 66646f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 66746f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 668c2248fc9SDouglas Gilbert /* 10 */ 66946f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 67046f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 67146f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 67280c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6734f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 674c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 67546f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 67646f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 67746f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 67846f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 679481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 680481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 681481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 68246f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 68346f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 68446f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 68546f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 68646f64e70SDouglas Gilbert /* 15 */ 687c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 688c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 689c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 690c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 691c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 692c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 69346f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 69446f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 69546f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 69646f64e70SDouglas Gilbert 0xff, 0xff} }, 69746f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 69846f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 699c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 700c2248fc9SDouglas Gilbert 0} }, 70146f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 70246f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 703c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 704c2248fc9SDouglas Gilbert 0} }, 705c2248fc9SDouglas Gilbert /* 20 */ 706f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 707f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 708c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 709c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 710c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 711c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 712c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 713c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 71446f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 715b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 71646f64e70SDouglas Gilbert /* 25 */ 717acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 718acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 719acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 72046f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 72146f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 72246f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 72346f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7244f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 72580c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 726b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 72780c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 72846f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 729c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 730b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 731b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 732ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 733ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 734ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 735c2248fc9SDouglas Gilbert 736ed9f3e25SDouglas Gilbert /* 30 */ 737b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 738f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 739f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 740f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 741b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 742f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 743f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 744f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 745f0d1cf93SDouglas Gilbert /* sentinel */ 746c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 747c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 748c2248fc9SDouglas Gilbert }; 749c2248fc9SDouglas Gilbert 75087c715dcSDouglas Gilbert static int sdebug_num_hosts; 75187c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 752773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7539b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 754c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7559267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 756773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 757773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 758773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 759773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 760773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 761773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 762773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 763773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 764c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 765d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 766d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 767cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 768c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 769773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 770773642d9SDouglas Gilbert static int sdebug_no_uld; 771773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 772773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 773773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 774773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 775773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 77686e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 777b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 778773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 779773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 780773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 781773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 782773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 783773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 784773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 785773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 786773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 787773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 788773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 789773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 790773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 79109ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7920c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 79387c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 794773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 795773642d9SDouglas Gilbert static bool sdebug_clustering; 796773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 797773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 798817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 799773642d9SDouglas Gilbert static bool sdebug_verbose; 800f46eb0e9SDouglas Gilbert static bool have_dif_prot; 8014f2c8bf6SDouglas Gilbert static bool write_since_sync; 802c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 8039447b6ceSMartin K. Petersen static bool sdebug_wp; 8049267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 8059267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 8069267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 8071da177e4SLinus Torvalds 808c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8091da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8101da177e4SLinus Torvalds 8111da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8121da177e4SLinus Torvalds may still need them */ 8131da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8141da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8151da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8161da177e4SLinus Torvalds 8171da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8181da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8191da177e4SLinus Torvalds 82087c715dcSDouglas Gilbert static struct xarray per_store_arr; 82187c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 82287c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 82387c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 82487c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8251da177e4SLinus Torvalds 82644d92694SMartin K. Petersen static unsigned long map_size; 827cbf67842SDouglas Gilbert static int num_aborts; 828cbf67842SDouglas Gilbert static int num_dev_resets; 829cbf67842SDouglas Gilbert static int num_target_resets; 830cbf67842SDouglas Gilbert static int num_bus_resets; 831cbf67842SDouglas Gilbert static int num_host_resets; 832c6a44287SMartin K. Petersen static int dix_writes; 833c6a44287SMartin K. Petersen static int dix_reads; 834c6a44287SMartin K. Petersen static int dif_errors; 8351da177e4SLinus Torvalds 836f0d1cf93SDouglas Gilbert /* ZBC global data */ 83764e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 83898e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 839380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 840aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 841f0d1cf93SDouglas Gilbert 842c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 843c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 844fd32119bSDouglas Gilbert 8451da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 84687c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 84787c715dcSDouglas Gilbert 84887c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8491da177e4SLinus Torvalds 850cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 851cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8541da177e4SLinus Torvalds 8551da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8561da177e4SLinus Torvalds .name = sdebug_proc_name, 8571da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8581da177e4SLinus Torvalds }; 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds static const int check_condition_result = 8611da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 8621da177e4SLinus Torvalds 863c6a44287SMartin K. Petersen static const int illegal_condition_result = 864c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 865c6a44287SMartin K. Petersen 866cbf67842SDouglas Gilbert static const int device_qfull_result = 867cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 868cbf67842SDouglas Gilbert 869ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 870ed9f3e25SDouglas Gilbert 871fd32119bSDouglas Gilbert 872760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 873760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 874760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 875760f3b03SDouglas Gilbert */ 876760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 877fd32119bSDouglas Gilbert { 878fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 879fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 880fd32119bSDouglas Gilbert } 881c65b1445SDouglas Gilbert 88287c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 88387c715dcSDouglas Gilbert unsigned long long lba) 88414faa944SAkinobu Mita { 88587c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 88614faa944SAkinobu Mita 88787c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 88887c715dcSDouglas Gilbert if (!sip || !sip->storep) { 88987c715dcSDouglas Gilbert WARN_ON_ONCE(true); 89087c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 89187c715dcSDouglas Gilbert } 89287c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 89314faa944SAkinobu Mita } 89414faa944SAkinobu Mita 89587c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 89687c715dcSDouglas Gilbert sector_t sector) 89714faa944SAkinobu Mita { 89849413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 89914faa944SAkinobu Mita 90087c715dcSDouglas Gilbert return sip->dif_storep + sector; 90114faa944SAkinobu Mita } 90214faa944SAkinobu Mita 9038dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 9048dea0d02SFUJITA Tomonori { 9058dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 9068dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9078dea0d02SFUJITA Tomonori 9088dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 9098dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9108dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9118dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 912773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 913773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9148dea0d02SFUJITA Tomonori else 915773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 916773642d9SDouglas Gilbert /* sdebug_max_luns; */ 917f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9188dea0d02SFUJITA Tomonori } 9198dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9208dea0d02SFUJITA Tomonori } 9218dea0d02SFUJITA Tomonori 92222017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 92322017ed2SDouglas Gilbert 92422017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 925fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 926fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 92722017ed2SDouglas Gilbert int in_byte, int in_bit) 92822017ed2SDouglas Gilbert { 92922017ed2SDouglas Gilbert unsigned char *sbuff; 93022017ed2SDouglas Gilbert u8 sks[4]; 93122017ed2SDouglas Gilbert int sl, asc; 93222017ed2SDouglas Gilbert 93322017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 93422017ed2SDouglas Gilbert if (!sbuff) { 93522017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 93622017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 93722017ed2SDouglas Gilbert return; 93822017ed2SDouglas Gilbert } 93922017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 94022017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 941773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 94222017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 94322017ed2SDouglas Gilbert sks[0] = 0x80; 94422017ed2SDouglas Gilbert if (c_d) 94522017ed2SDouglas Gilbert sks[0] |= 0x40; 94622017ed2SDouglas Gilbert if (in_bit >= 0) { 94722017ed2SDouglas Gilbert sks[0] |= 0x8; 94822017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 94922017ed2SDouglas Gilbert } 95022017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 951773642d9SDouglas Gilbert if (sdebug_dsense) { 95222017ed2SDouglas Gilbert sl = sbuff[7] + 8; 95322017ed2SDouglas Gilbert sbuff[7] = sl; 95422017ed2SDouglas Gilbert sbuff[sl] = 0x2; 95522017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 95622017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 95722017ed2SDouglas Gilbert } else 95822017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 959773642d9SDouglas Gilbert if (sdebug_verbose) 96022017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 96122017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 96222017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 96322017ed2SDouglas Gilbert } 96422017ed2SDouglas Gilbert 965cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9668dea0d02SFUJITA Tomonori { 9678dea0d02SFUJITA Tomonori unsigned char *sbuff; 9688dea0d02SFUJITA Tomonori 969cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 970cbf67842SDouglas Gilbert if (!sbuff) { 971cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 972cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 973cbf67842SDouglas Gilbert return; 974cbf67842SDouglas Gilbert } 975cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 9768dea0d02SFUJITA Tomonori 977773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 9788dea0d02SFUJITA Tomonori 979773642d9SDouglas Gilbert if (sdebug_verbose) 980cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 981cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 982cbf67842SDouglas Gilbert my_name, key, asc, asq); 9838dea0d02SFUJITA Tomonori } 9841da177e4SLinus Torvalds 985fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 98622017ed2SDouglas Gilbert { 98722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 98822017ed2SDouglas Gilbert } 98922017ed2SDouglas Gilbert 9906f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9916f4e626fSNathan Chancellor void __user *arg) 9921da177e4SLinus Torvalds { 993773642d9SDouglas Gilbert if (sdebug_verbose) { 994cbf67842SDouglas Gilbert if (0x1261 == cmd) 995cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 996cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 997cbf67842SDouglas Gilbert else if (0x5331 == cmd) 998cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 999cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 1000cbf67842SDouglas Gilbert __func__); 1001cbf67842SDouglas Gilbert else 1002cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 1003cbf67842SDouglas Gilbert __func__, cmd); 10041da177e4SLinus Torvalds } 10051da177e4SLinus Torvalds return -EINVAL; 10061da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 10071da177e4SLinus Torvalds } 10081da177e4SLinus Torvalds 10099b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10109b760fd8SDouglas Gilbert { 10119b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10129b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10139b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10149b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10159b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10169b760fd8SDouglas Gilbert break; 10179b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10189b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10199b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10209b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10219b760fd8SDouglas Gilbert break; 10229b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10239b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10249b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10259b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10269b760fd8SDouglas Gilbert break; 10279b760fd8SDouglas Gilbert case 16: 10289b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10299b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10309b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10319b760fd8SDouglas Gilbert break; 10329b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10339b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10349b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10359b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10369b760fd8SDouglas Gilbert break; 10379b760fd8SDouglas Gilbert default: 10389b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10399b760fd8SDouglas Gilbert sdebug_cdb_len); 10409b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10419b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10429b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10439b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10449b760fd8SDouglas Gilbert break; 10459b760fd8SDouglas Gilbert } 10469b760fd8SDouglas Gilbert } 10479b760fd8SDouglas Gilbert 10489b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10499b760fd8SDouglas Gilbert { 10509b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10519b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10529b760fd8SDouglas Gilbert struct scsi_device *sdev; 10539b760fd8SDouglas Gilbert 10549b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10559b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10569b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10579b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10589b760fd8SDouglas Gilbert config_cdb_len(sdev); 10599b760fd8SDouglas Gilbert } 10609b760fd8SDouglas Gilbert } 10619b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10629b760fd8SDouglas Gilbert } 10639b760fd8SDouglas Gilbert 106419c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 106519c8ead7SEwan D. Milne { 106619c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 106719c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 106819c8ead7SEwan D. Milne 106919c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 107019c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 107119c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 107219c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 107319c8ead7SEwan D. Milne (devip->target == dp->target)) 107419c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 107519c8ead7SEwan D. Milne } 107619c8ead7SEwan D. Milne } 107719c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 107819c8ead7SEwan D. Milne } 107919c8ead7SEwan D. Milne 1080f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10811da177e4SLinus Torvalds { 1082cbf67842SDouglas Gilbert int k; 1083cbf67842SDouglas Gilbert 1084cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1085cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1086cbf67842SDouglas Gilbert const char *cp = NULL; 1087cbf67842SDouglas Gilbert 1088cbf67842SDouglas Gilbert switch (k) { 1089cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1090f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1091f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1092773642d9SDouglas Gilbert if (sdebug_verbose) 1093cbf67842SDouglas Gilbert cp = "power on reset"; 1094cbf67842SDouglas Gilbert break; 1095cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1096f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1097f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1098773642d9SDouglas Gilbert if (sdebug_verbose) 1099cbf67842SDouglas Gilbert cp = "bus reset"; 1100cbf67842SDouglas Gilbert break; 1101cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1102f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1103f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1104773642d9SDouglas Gilbert if (sdebug_verbose) 1105cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1106cbf67842SDouglas Gilbert break; 11070d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1108f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1109f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1110773642d9SDouglas Gilbert if (sdebug_verbose) 11110d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1112f49accf1SEwan D. Milne break; 1113acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1114f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1115b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1116b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1117773642d9SDouglas Gilbert if (sdebug_verbose) 1118acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1119acafd0b9SEwan D. Milne break; 1120acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1121f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1122acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1123acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1124773642d9SDouglas Gilbert if (sdebug_verbose) 1125acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1126acafd0b9SEwan D. Milne break; 112719c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 112819c8ead7SEwan D. Milne /* 112919c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 113019c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 113119c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 113219c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1133773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 113419c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 113519c8ead7SEwan D. Milne */ 1136773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 113719c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1138f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 113919c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 114019c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1141773642d9SDouglas Gilbert if (sdebug_verbose) 114219c8ead7SEwan D. Milne cp = "reported luns data has changed"; 114319c8ead7SEwan D. Milne break; 1144cbf67842SDouglas Gilbert default: 1145773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1146773642d9SDouglas Gilbert if (sdebug_verbose) 1147cbf67842SDouglas Gilbert cp = "unknown"; 1148cbf67842SDouglas Gilbert break; 1149cbf67842SDouglas Gilbert } 1150cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1151773642d9SDouglas Gilbert if (sdebug_verbose) 1152f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1153cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1154cbf67842SDouglas Gilbert my_name, cp); 11551da177e4SLinus Torvalds return check_condition_result; 11561da177e4SLinus Torvalds } 11571da177e4SLinus Torvalds return 0; 11581da177e4SLinus Torvalds } 11591da177e4SLinus Torvalds 1160fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11611da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11621da177e4SLinus Torvalds int arr_len) 11631da177e4SLinus Torvalds { 116421a61829SFUJITA Tomonori int act_len; 1165ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11661da177e4SLinus Torvalds 1167072d0bb3SFUJITA Tomonori if (!sdb->length) 11681da177e4SLinus Torvalds return 0; 1169ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1170773642d9SDouglas Gilbert return DID_ERROR << 16; 117121a61829SFUJITA Tomonori 117221a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 117321a61829SFUJITA Tomonori arr, arr_len); 117442d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 117521a61829SFUJITA Tomonori 11761da177e4SLinus Torvalds return 0; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds 1179fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1180fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1181fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1182fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1183fb0cc8d1SDouglas Gilbert */ 1184fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1185fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1186fb0cc8d1SDouglas Gilbert { 11879237f04eSDamien Le Moal unsigned int act_len, n; 1188ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1189fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1190fb0cc8d1SDouglas Gilbert 1191fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1192fb0cc8d1SDouglas Gilbert return 0; 1193ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1194fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1195fb0cc8d1SDouglas Gilbert 1196fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1197fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1198fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 119942d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 120042d387beSBart Van Assche scsi_get_resid(scp)); 12019237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 120287c715dcSDouglas Gilbert scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n)); 1203fb0cc8d1SDouglas Gilbert return 0; 1204fb0cc8d1SDouglas Gilbert } 1205fb0cc8d1SDouglas Gilbert 1206fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1207fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1208fb0cc8d1SDouglas Gilbert */ 12091da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 121021a61829SFUJITA Tomonori int arr_len) 12111da177e4SLinus Torvalds { 121221a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12131da177e4SLinus Torvalds return 0; 1214ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12151da177e4SLinus Torvalds return -1; 121621a61829SFUJITA Tomonori 121721a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12181da177e4SLinus Torvalds } 12191da177e4SLinus Torvalds 12201da177e4SLinus Torvalds 1221e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1222e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12239b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12241b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12251b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12261b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12271b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12281da177e4SLinus Torvalds 1229cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1230760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12315a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 123209ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1233bf476433SChristoph Hellwig const uuid_t *lu_name) 12341da177e4SLinus Torvalds { 1235c65b1445SDouglas Gilbert int num, port_a; 1236c65b1445SDouglas Gilbert char b[32]; 12371da177e4SLinus Torvalds 1238c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12391da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12401da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12411da177e4SLinus Torvalds arr[1] = 0x1; 12421da177e4SLinus Torvalds arr[2] = 0x0; 1243e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1244e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12451da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12461da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12471da177e4SLinus Torvalds arr[3] = num; 12481da177e4SLinus Torvalds num += 4; 1249c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 125009ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 125109ba24c1SDouglas Gilbert /* Locally assigned UUID */ 125209ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 125309ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 125409ba24c1SDouglas Gilbert arr[num++] = 0x0; 125509ba24c1SDouglas Gilbert arr[num++] = 0x12; 125609ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 125709ba24c1SDouglas Gilbert arr[num++] = 0x0; 125809ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 125909ba24c1SDouglas Gilbert num += 16; 126009ba24c1SDouglas Gilbert } else { 12611b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1262c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1263c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1264c65b1445SDouglas Gilbert arr[num++] = 0x0; 1265c65b1445SDouglas Gilbert arr[num++] = 0x8; 12661b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1267773642d9SDouglas Gilbert num += 8; 126809ba24c1SDouglas Gilbert } 1269c65b1445SDouglas Gilbert /* Target relative port number */ 1270c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1271c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1272c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1273c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1274c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1275c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1276c65b1445SDouglas Gilbert arr[num++] = 0x0; 1277c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1278c65b1445SDouglas Gilbert } 12791b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1280c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1281c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1282c65b1445SDouglas Gilbert arr[num++] = 0x0; 1283c65b1445SDouglas Gilbert arr[num++] = 0x8; 12841b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1285773642d9SDouglas Gilbert num += 8; 12861b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12875a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12885a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12895a09e398SHannes Reinecke arr[num++] = 0x0; 12905a09e398SHannes Reinecke arr[num++] = 0x4; 12915a09e398SHannes Reinecke arr[num++] = 0; 12925a09e398SHannes Reinecke arr[num++] = 0; 1293773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1294773642d9SDouglas Gilbert num += 2; 12951b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1296c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1297c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1298c65b1445SDouglas Gilbert arr[num++] = 0x0; 1299c65b1445SDouglas Gilbert arr[num++] = 0x8; 13001b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1301773642d9SDouglas Gilbert num += 8; 1302c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1303c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1304c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1305c65b1445SDouglas Gilbert arr[num++] = 0x0; 1306c65b1445SDouglas Gilbert arr[num++] = 24; 13071b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1308c65b1445SDouglas Gilbert num += 12; 1309c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1310c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1311c65b1445SDouglas Gilbert num += 8; 1312c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1313c65b1445SDouglas Gilbert num += 4; 1314c65b1445SDouglas Gilbert return num; 1315c65b1445SDouglas Gilbert } 1316c65b1445SDouglas Gilbert 1317c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1318c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1319c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1320c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1321c65b1445SDouglas Gilbert }; 1322c65b1445SDouglas Gilbert 1323cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1324760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1325c65b1445SDouglas Gilbert { 1326c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1327c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1328c65b1445SDouglas Gilbert } 1329c65b1445SDouglas Gilbert 1330cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1331760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1332c65b1445SDouglas Gilbert { 1333c65b1445SDouglas Gilbert int num = 0; 1334c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1335c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1336c65b1445SDouglas Gilbert int plen, olen; 1337c65b1445SDouglas Gilbert 1338c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1339c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1340c65b1445SDouglas Gilbert arr[num++] = 0x0; 1341c65b1445SDouglas Gilbert olen = strlen(na1); 1342c65b1445SDouglas Gilbert plen = olen + 1; 1343c65b1445SDouglas Gilbert if (plen % 4) 1344c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1345c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1346c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1347c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1348c65b1445SDouglas Gilbert num += plen; 1349c65b1445SDouglas Gilbert 1350c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1351c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1352c65b1445SDouglas Gilbert arr[num++] = 0x0; 1353c65b1445SDouglas Gilbert olen = strlen(na2); 1354c65b1445SDouglas Gilbert plen = olen + 1; 1355c65b1445SDouglas Gilbert if (plen % 4) 1356c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1357c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1358c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1359c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1360c65b1445SDouglas Gilbert num += plen; 1361c65b1445SDouglas Gilbert 1362c65b1445SDouglas Gilbert return num; 1363c65b1445SDouglas Gilbert } 1364c65b1445SDouglas Gilbert 1365c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1366760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1367c65b1445SDouglas Gilbert { 1368c65b1445SDouglas Gilbert int num = 0; 1369c65b1445SDouglas Gilbert int port_a, port_b; 1370c65b1445SDouglas Gilbert 1371c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1372c65b1445SDouglas Gilbert port_b = port_a + 1; 1373c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1374c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1375c65b1445SDouglas Gilbert arr[num++] = 0x0; 1376c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1377c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1378c65b1445SDouglas Gilbert num += 6; 1379c65b1445SDouglas Gilbert arr[num++] = 0x0; 1380c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1381c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1382c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1383c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1384c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1385c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13861b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1387773642d9SDouglas Gilbert num += 8; 1388c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1389c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1390c65b1445SDouglas Gilbert arr[num++] = 0x0; 1391c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1392c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1393c65b1445SDouglas Gilbert num += 6; 1394c65b1445SDouglas Gilbert arr[num++] = 0x0; 1395c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1396c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1397c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1398c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1399c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1400c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 14011b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1402773642d9SDouglas Gilbert num += 8; 1403c65b1445SDouglas Gilbert 1404c65b1445SDouglas Gilbert return num; 1405c65b1445SDouglas Gilbert } 1406c65b1445SDouglas Gilbert 1407c65b1445SDouglas Gilbert 1408c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1409c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1410c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1411c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1412c65b1445SDouglas Gilbert '1','2','3','4', 1413c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1414c65b1445SDouglas Gilbert 0xec,0,0,0, 1415c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1416c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1417c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1418c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1419c65b1445SDouglas Gilbert 0x53,0x41, 1420c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1421c65b1445SDouglas Gilbert 0x20,0x20, 1422c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1423c65b1445SDouglas Gilbert 0x10,0x80, 1424c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1425c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1426c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1428c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1429c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1434c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1435c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1436c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1437c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1443c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1444c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1450c65b1445SDouglas Gilbert }; 1451c65b1445SDouglas Gilbert 1452cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1453760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1454c65b1445SDouglas Gilbert { 1455c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1456c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1457c65b1445SDouglas Gilbert } 1458c65b1445SDouglas Gilbert 1459c65b1445SDouglas Gilbert 1460c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14611e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14621e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14631e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14641e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1465c65b1445SDouglas Gilbert }; 1466c65b1445SDouglas Gilbert 1467cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1468760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1469c65b1445SDouglas Gilbert { 1470ea61fca5SMartin K. Petersen unsigned int gran; 1471ea61fca5SMartin K. Petersen 1472c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1473e308b3d1SMartin K. Petersen 1474e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 147586e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 147686e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 147786e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 147886e6828aSLukas Herbolt else 1479773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1480773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1481e308b3d1SMartin K. Petersen 1482e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1483773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1484773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 148544d92694SMartin K. Petersen 1486e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1487773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1488e308b3d1SMartin K. Petersen 1489773642d9SDouglas Gilbert if (sdebug_lbpu) { 1490e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1491773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1492e308b3d1SMartin K. Petersen 1493e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1494773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 149544d92694SMartin K. Petersen } 149644d92694SMartin K. Petersen 1497e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1498773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1499773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 150044d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 150144d92694SMartin K. Petersen } 150244d92694SMartin K. Petersen 1503e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1504773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 15056014759cSMartin K. Petersen 15065b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1507773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 15085b94e232SMartin K. Petersen 15095b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 151044d92694SMartin K. Petersen 1511c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 15121da177e4SLinus Torvalds } 15131da177e4SLinus Torvalds 15141e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 151564e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1516eac6e8e4SMatthew Wilcox { 1517eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1518eac6e8e4SMatthew Wilcox arr[0] = 0; 15191e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15201e49f785SDouglas Gilbert arr[2] = 0; 15211e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 152264e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 152364e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1524eac6e8e4SMatthew Wilcox 1525eac6e8e4SMatthew Wilcox return 0x3c; 1526eac6e8e4SMatthew Wilcox } 15271da177e4SLinus Torvalds 1528760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1529760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15306014759cSMartin K. Petersen { 15313f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15326014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1533773642d9SDouglas Gilbert if (sdebug_lbpu) 15346014759cSMartin K. Petersen arr[1] = 1 << 7; 1535773642d9SDouglas Gilbert if (sdebug_lbpws) 15366014759cSMartin K. Petersen arr[1] |= 1 << 6; 1537773642d9SDouglas Gilbert if (sdebug_lbpws10) 15385b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1539760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1540760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1541760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1542760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1543760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15443f0bc3b3SMartin K. Petersen return 0x4; 15456014759cSMartin K. Petersen } 15466014759cSMartin K. Petersen 1547d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1548f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1549d36da305SDouglas Gilbert { 1550d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1551d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1552d36da305SDouglas Gilbert /* 1553d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1554d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1555f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1556f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1557d36da305SDouglas Gilbert */ 1558d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1559d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 156064e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1561f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1562f0d1cf93SDouglas Gilbert else 1563d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 1564d36da305SDouglas Gilbert return 0x3c; 1565d36da305SDouglas Gilbert } 1566d36da305SDouglas Gilbert 15671da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1568c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15691da177e4SLinus Torvalds 1570c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15711da177e4SLinus Torvalds { 15721da177e4SLinus Torvalds unsigned char pq_pdt; 15735a09e398SHannes Reinecke unsigned char *arr; 157401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15755a09e398SHannes Reinecke int alloc_len, n, ret; 1576d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15771da177e4SLinus Torvalds 1578773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15796f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15806f3cbf55SDouglas Gilbert if (! arr) 15816f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1582760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 158364e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1584d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1585b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1586c2248fc9SDouglas Gilbert if (have_wlun) 1587b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1588b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1589b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1590c65b1445SDouglas Gilbert else 1591773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 15921da177e4SLinus Torvalds arr[0] = pq_pdt; 15931da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 159422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 15955a09e398SHannes Reinecke kfree(arr); 15961da177e4SLinus Torvalds return check_condition_result; 15971da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 15985a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1599c65b1445SDouglas Gilbert char lu_id_str[6]; 1600c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 16011da177e4SLinus Torvalds 16025a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 16035a09e398SHannes Reinecke (devip->channel & 0x7f); 1604b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 160523183910SDouglas Gilbert host_no = 0; 1606c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1607c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1608c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1609c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1610c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16111da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1612c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1613c65b1445SDouglas Gilbert n = 4; 1614c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1615c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1616c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1617c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1618c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1619c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1620c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1621c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1622d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1623c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1624760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1625760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1626d36da305SDouglas Gilbert if (is_disk) 1627d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 162864e14eceSDamien Le Moal if (is_zbc) 1629d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1630760f3b03SDouglas Gilbert } 1631c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16321da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1633c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16341da177e4SLinus Torvalds arr[3] = len; 1635c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16361da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1637c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1638760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16395a09e398SHannes Reinecke target_dev_id, lu_id_num, 164009ba24c1SDouglas Gilbert lu_id_str, len, 164109ba24c1SDouglas Gilbert &devip->lu_name); 1642c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1643c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1644760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1645c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1646c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1647760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1648c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1649c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1650c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16518475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1652c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1653760f3b03SDouglas Gilbert else if (have_dif_prot) 1654c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1655c6a44287SMartin K. Petersen else 1656c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1657c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1658c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1659c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1660c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1661c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1662c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1663c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1664c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1665c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1666c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1667760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1668d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1669c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1670760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1671773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1672d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1673c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1674760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1675d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1676eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 167764e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1678760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16796014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1680760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1681d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1682d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1683f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16841da177e4SLinus Torvalds } else { 168522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16865a09e398SHannes Reinecke kfree(arr); 16871da177e4SLinus Torvalds return check_condition_result; 16881da177e4SLinus Torvalds } 1689773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 16905a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1691c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 16925a09e398SHannes Reinecke kfree(arr); 16935a09e398SHannes Reinecke return ret; 16941da177e4SLinus Torvalds } 16951da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1696773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1697773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 16981da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 16991da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1700f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1701b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 170270bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1703c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 17041da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1705c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1706e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1707e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1708e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 17099b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17109b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17111da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1712760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1713760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1714c65b1445SDouglas Gilbert n = 62; 1715760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1716760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1717760f3b03SDouglas Gilbert n += 2; 1718760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1719760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1720760f3b03SDouglas Gilbert n += 2; 1721d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1722d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1723d36da305SDouglas Gilbert n += 2; 17241da177e4SLinus Torvalds } 1725760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17265a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 172787c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ)); 17285a09e398SHannes Reinecke kfree(arr); 17295a09e398SHannes Reinecke return ret; 17301da177e4SLinus Torvalds } 17311da177e4SLinus Torvalds 1732fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1733fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1734fd32119bSDouglas Gilbert 17351da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17361da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17371da177e4SLinus Torvalds { 17381da177e4SLinus Torvalds unsigned char *sbuff; 173901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1740cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 17412492fc09STomas Winkler bool dsense; 17421da177e4SLinus Torvalds int len = 18; 17431da177e4SLinus Torvalds 1744c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1745c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1746cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1747c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1748c2248fc9SDouglas Gilbert if (dsense) { 1749c65b1445SDouglas Gilbert arr[0] = 0x72; 1750c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1751c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1752c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1753c2248fc9SDouglas Gilbert len = 8; 1754c65b1445SDouglas Gilbert } else { 1755c65b1445SDouglas Gilbert arr[0] = 0x70; 1756c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1757c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1758c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1759c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1760c65b1445SDouglas Gilbert } 1761c65b1445SDouglas Gilbert } else { 1762cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1763773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1764c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1765c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1766c2248fc9SDouglas Gilbert if (dsense) { 1767c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1768c2248fc9SDouglas Gilbert arr[0] = 0x72; 1769c2248fc9SDouglas Gilbert len = 8; 1770c2248fc9SDouglas Gilbert } else { 1771c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1772c2248fc9SDouglas Gilbert arr[0] = 0x70; 1773c2248fc9SDouglas Gilbert arr[7] = 0xa; 1774c2248fc9SDouglas Gilbert } 1775c2248fc9SDouglas Gilbert } else if (dsense) { 1776c2248fc9SDouglas Gilbert memset(arr, 0, 8); 17771da177e4SLinus Torvalds arr[0] = 0x72; 17781da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 17791da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 17801da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 17811da177e4SLinus Torvalds len = 8; 1782c2248fc9SDouglas Gilbert } else { 1783c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1784c2248fc9SDouglas Gilbert arr[0] = 0x70; 1785c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1786c2248fc9SDouglas Gilbert arr[7] = 0xa; 1787c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1788c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1789c65b1445SDouglas Gilbert } 1790c2248fc9SDouglas Gilbert 1791c65b1445SDouglas Gilbert } 1792cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 17931da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 17941da177e4SLinus Torvalds } 17951da177e4SLinus Torvalds 1796c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, 1797c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1798c65b1445SDouglas Gilbert { 179901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1800c4837394SDouglas Gilbert int power_cond, stop; 18014f2c8bf6SDouglas Gilbert bool changing; 1802c65b1445SDouglas Gilbert 1803c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1804c65b1445SDouglas Gilbert if (power_cond) { 180522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1806c65b1445SDouglas Gilbert return check_condition_result; 1807c65b1445SDouglas Gilbert } 1808c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 18094f2c8bf6SDouglas Gilbert changing = atomic_read(&devip->stopped) == !stop; 1810c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 18114f2c8bf6SDouglas Gilbert if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */ 18124f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18134f2c8bf6SDouglas Gilbert else 18144f2c8bf6SDouglas Gilbert return 0; 1815c65b1445SDouglas Gilbert } 1816c65b1445SDouglas Gilbert 181728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 181828898873SFUJITA Tomonori { 1819773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1820773642d9SDouglas Gilbert 1821773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1822773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1823773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 182428898873SFUJITA Tomonori else 182528898873SFUJITA Tomonori return sdebug_store_sectors; 182628898873SFUJITA Tomonori } 182728898873SFUJITA Tomonori 18281da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18291da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18301da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18311da177e4SLinus Torvalds { 18321da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1833c65b1445SDouglas Gilbert unsigned int capac; 18341da177e4SLinus Torvalds 1835c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 183628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18371da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1838c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1839c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1840773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1841773642d9SDouglas Gilbert } else 1842773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1843773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18441da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18451da177e4SLinus Torvalds } 18461da177e4SLinus Torvalds 1847c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1848c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1849c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1850c65b1445SDouglas Gilbert { 185101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1852c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1853773642d9SDouglas Gilbert int alloc_len; 1854c65b1445SDouglas Gilbert 1855773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1856c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 185728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1858c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1859773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1860773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1861773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1862773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 186344d92694SMartin K. Petersen 1864be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18655b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1866760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1867760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1868760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1869760f3b03SDouglas Gilbert */ 1870760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1871760f3b03SDouglas Gilbert arr[14] |= 0x40; 1872be1dd78dSEric Sandeen } 187344d92694SMartin K. Petersen 1874773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1875c6a44287SMartin K. Petersen 1876760f3b03SDouglas Gilbert if (have_dif_prot) { 1877773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1878c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1879c6a44287SMartin K. Petersen } 1880c6a44287SMartin K. Petersen 1881c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 188287c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1883c65b1445SDouglas Gilbert } 1884c65b1445SDouglas Gilbert 18855a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 18865a09e398SHannes Reinecke 18875a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 18885a09e398SHannes Reinecke struct sdebug_dev_info *devip) 18895a09e398SHannes Reinecke { 189001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 18915a09e398SHannes Reinecke unsigned char *arr; 18925a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 18935a09e398SHannes Reinecke int n, ret, alen, rlen; 18945a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 18955a09e398SHannes Reinecke 1896773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 18976f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 18986f3cbf55SDouglas Gilbert if (! arr) 18996f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19005a09e398SHannes Reinecke /* 19015a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19025a09e398SHannes Reinecke * real and a fake port with no device connected. 19035a09e398SHannes Reinecke * So we create two port groups with one port each 19045a09e398SHannes Reinecke * and set the group with port B to unavailable. 19055a09e398SHannes Reinecke */ 19065a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19075a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19085a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19095a09e398SHannes Reinecke (devip->channel & 0x7f); 19105a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19115a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19125a09e398SHannes Reinecke 19135a09e398SHannes Reinecke /* 19145a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19155a09e398SHannes Reinecke */ 19165a09e398SHannes Reinecke n = 4; 1917b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19185a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19195a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19205a09e398SHannes Reinecke } else { 19215a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1922773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19235a09e398SHannes Reinecke } 1924773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1925773642d9SDouglas Gilbert n += 2; 19265a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19275a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19285a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19295a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19305a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19315a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1932773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1933773642d9SDouglas Gilbert n += 2; 19345a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19355a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1936773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1937773642d9SDouglas Gilbert n += 2; 19385a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19395a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19405a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19415a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19425a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19435a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1944773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1945773642d9SDouglas Gilbert n += 2; 19465a09e398SHannes Reinecke 19475a09e398SHannes Reinecke rlen = n - 4; 1948773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19495a09e398SHannes Reinecke 19505a09e398SHannes Reinecke /* 19515a09e398SHannes Reinecke * Return the smallest value of either 19525a09e398SHannes Reinecke * - The allocated length 19535a09e398SHannes Reinecke * - The constructed command length 19545a09e398SHannes Reinecke * - The maximum array size 19555a09e398SHannes Reinecke */ 195687c715dcSDouglas Gilbert rlen = min_t(int, alen, n); 19575a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 195887c715dcSDouglas Gilbert min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19595a09e398SHannes Reinecke kfree(arr); 19605a09e398SHannes Reinecke return ret; 19615a09e398SHannes Reinecke } 19625a09e398SHannes Reinecke 1963fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1964fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 196538d5c833SDouglas Gilbert { 196638d5c833SDouglas Gilbert bool rctd; 196738d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 196838d5c833SDouglas Gilbert u16 req_sa, u; 196938d5c833SDouglas Gilbert u32 alloc_len, a_len; 197038d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 197138d5c833SDouglas Gilbert const struct opcode_info_t *oip; 197238d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 197338d5c833SDouglas Gilbert u8 *arr; 197438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 197538d5c833SDouglas Gilbert 197638d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 197738d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 197838d5c833SDouglas Gilbert req_opcode = cmd[3]; 197938d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 198038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 19816d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 198238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 198338d5c833SDouglas Gilbert return check_condition_result; 198438d5c833SDouglas Gilbert } 198538d5c833SDouglas Gilbert if (alloc_len > 8192) 198638d5c833SDouglas Gilbert a_len = 8192; 198738d5c833SDouglas Gilbert else 198838d5c833SDouglas Gilbert a_len = alloc_len; 198999531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 199038d5c833SDouglas Gilbert if (NULL == arr) { 199138d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 199238d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 199338d5c833SDouglas Gilbert return check_condition_result; 199438d5c833SDouglas Gilbert } 199538d5c833SDouglas Gilbert switch (reporting_opts) { 199638d5c833SDouglas Gilbert case 0: /* all commands */ 199738d5c833SDouglas Gilbert /* count number of commands */ 199838d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 199938d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 200038d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 200138d5c833SDouglas Gilbert continue; 200238d5c833SDouglas Gilbert count += (oip->num_attached + 1); 200338d5c833SDouglas Gilbert } 200438d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 200538d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 200638d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 200738d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 200838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 200938d5c833SDouglas Gilbert continue; 201038d5c833SDouglas Gilbert na = oip->num_attached; 201138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 201238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 201338d5c833SDouglas Gilbert if (rctd) 201438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 201538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 201638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 201738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 201838d5c833SDouglas Gilbert if (rctd) 201938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 202038d5c833SDouglas Gilbert r_oip = oip; 202138d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 202238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 202338d5c833SDouglas Gilbert continue; 202438d5c833SDouglas Gilbert offset += bump; 202538d5c833SDouglas Gilbert arr[offset] = oip->opcode; 202638d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 202738d5c833SDouglas Gilbert if (rctd) 202838d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 202938d5c833SDouglas Gilbert if (FF_SA & oip->flags) 203038d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 203138d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 203238d5c833SDouglas Gilbert arr + offset + 6); 203338d5c833SDouglas Gilbert if (rctd) 203438d5c833SDouglas Gilbert put_unaligned_be16(0xa, 203538d5c833SDouglas Gilbert arr + offset + 8); 203638d5c833SDouglas Gilbert } 203738d5c833SDouglas Gilbert oip = r_oip; 203838d5c833SDouglas Gilbert offset += bump; 203938d5c833SDouglas Gilbert } 204038d5c833SDouglas Gilbert break; 204138d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 204238d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 204338d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 204438d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 204538d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 204638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 204738d5c833SDouglas Gilbert supp = 1; 204838d5c833SDouglas Gilbert offset = 4; 204938d5c833SDouglas Gilbert } else { 205038d5c833SDouglas Gilbert if (1 == reporting_opts) { 205138d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 205238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 205338d5c833SDouglas Gilbert 2, 2); 205438d5c833SDouglas Gilbert kfree(arr); 205538d5c833SDouglas Gilbert return check_condition_result; 205638d5c833SDouglas Gilbert } 205738d5c833SDouglas Gilbert req_sa = 0; 205838d5c833SDouglas Gilbert } else if (2 == reporting_opts && 205938d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 206038d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 206138d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 206238d5c833SDouglas Gilbert return check_condition_result; 206338d5c833SDouglas Gilbert } 206438d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 206538d5c833SDouglas Gilbert req_opcode == oip->opcode) 206638d5c833SDouglas Gilbert supp = 3; 206738d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 206838d5c833SDouglas Gilbert na = oip->num_attached; 206938d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 207038d5c833SDouglas Gilbert ++k, ++oip) { 207138d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 207238d5c833SDouglas Gilbert break; 207338d5c833SDouglas Gilbert } 207438d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 207538d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 207638d5c833SDouglas Gilbert na = oip->num_attached; 207738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 207838d5c833SDouglas Gilbert ++k, ++oip) { 207938d5c833SDouglas Gilbert if (req_sa == oip->sa) 208038d5c833SDouglas Gilbert break; 208138d5c833SDouglas Gilbert } 208238d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 208338d5c833SDouglas Gilbert } else 208438d5c833SDouglas Gilbert supp = 3; 208538d5c833SDouglas Gilbert if (3 == supp) { 208638d5c833SDouglas Gilbert u = oip->len_mask[0]; 208738d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 208838d5c833SDouglas Gilbert arr[4] = oip->opcode; 208938d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 209038d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 209138d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 209238d5c833SDouglas Gilbert offset = 4 + u; 209338d5c833SDouglas Gilbert } else 209438d5c833SDouglas Gilbert offset = 4; 209538d5c833SDouglas Gilbert } 209638d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 209738d5c833SDouglas Gilbert if (rctd) { 209838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 209938d5c833SDouglas Gilbert offset += 12; 210038d5c833SDouglas Gilbert } 210138d5c833SDouglas Gilbert break; 210238d5c833SDouglas Gilbert default: 210338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 210438d5c833SDouglas Gilbert kfree(arr); 210538d5c833SDouglas Gilbert return check_condition_result; 210638d5c833SDouglas Gilbert } 210738d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 210838d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 210938d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 211038d5c833SDouglas Gilbert kfree(arr); 211138d5c833SDouglas Gilbert return errsts; 211238d5c833SDouglas Gilbert } 211338d5c833SDouglas Gilbert 2114fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2115fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 211638d5c833SDouglas Gilbert { 211738d5c833SDouglas Gilbert bool repd; 211838d5c833SDouglas Gilbert u32 alloc_len, len; 211938d5c833SDouglas Gilbert u8 arr[16]; 212038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 212138d5c833SDouglas Gilbert 212238d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 212338d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 212438d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 212538d5c833SDouglas Gilbert if (alloc_len < 4) { 212638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 212738d5c833SDouglas Gilbert return check_condition_result; 212838d5c833SDouglas Gilbert } 212938d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 213038d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 213138d5c833SDouglas Gilbert if (repd) { 213238d5c833SDouglas Gilbert arr[3] = 0xc; 213338d5c833SDouglas Gilbert len = 16; 213438d5c833SDouglas Gilbert } else 213538d5c833SDouglas Gilbert len = 4; 213638d5c833SDouglas Gilbert 213738d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 213838d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 213938d5c833SDouglas Gilbert } 214038d5c833SDouglas Gilbert 21411da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21421da177e4SLinus Torvalds 21431da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21441da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21451da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21461da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21471da177e4SLinus Torvalds 21481da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21491da177e4SLinus Torvalds if (1 == pcontrol) 21501da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21511da177e4SLinus Torvalds return sizeof(err_recov_pg); 21521da177e4SLinus Torvalds } 21531da177e4SLinus Torvalds 21541da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21551da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21561da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21571da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21581da177e4SLinus Torvalds 21591da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21601da177e4SLinus Torvalds if (1 == pcontrol) 21611da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21621da177e4SLinus Torvalds return sizeof(disconnect_pg); 21631da177e4SLinus Torvalds } 21641da177e4SLinus Torvalds 21651da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21661da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21671da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21681da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21691da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2172773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2173773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2174773642d9SDouglas Gilbert if (sdebug_removable) 21751da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 21761da177e4SLinus Torvalds if (1 == pcontrol) 21771da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 21781da177e4SLinus Torvalds return sizeof(format_pg); 21791da177e4SLinus Torvalds } 21801da177e4SLinus Torvalds 2181fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2182fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2183fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2184fd32119bSDouglas Gilbert 21851da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 21861da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2187cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2188cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2189cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 21901da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 21911da177e4SLinus Torvalds 2192773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2193cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 21941da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 21951da177e4SLinus Torvalds if (1 == pcontrol) 2196cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2197cbf67842SDouglas Gilbert else if (2 == pcontrol) 2198cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 21991da177e4SLinus Torvalds return sizeof(caching_pg); 22001da177e4SLinus Torvalds } 22011da177e4SLinus Torvalds 2202fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2203fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2204fd32119bSDouglas Gilbert 22051da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22061da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2207c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2208c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2209c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22101da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22111da177e4SLinus Torvalds 2212773642d9SDouglas Gilbert if (sdebug_dsense) 22131da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2214c65b1445SDouglas Gilbert else 2215c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2216c6a44287SMartin K. Petersen 2217773642d9SDouglas Gilbert if (sdebug_ato) 2218c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2219c6a44287SMartin K. Petersen 22201da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22211da177e4SLinus Torvalds if (1 == pcontrol) 2222c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2223c65b1445SDouglas Gilbert else if (2 == pcontrol) 2224c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22251da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22261da177e4SLinus Torvalds } 22271da177e4SLinus Torvalds 2228c65b1445SDouglas Gilbert 22291da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22301da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2231c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22321da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2233c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2234c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2235c65b1445SDouglas Gilbert 22361da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22371da177e4SLinus Torvalds if (1 == pcontrol) 2238c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2239c65b1445SDouglas Gilbert else if (2 == pcontrol) 2240c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22411da177e4SLinus Torvalds return sizeof(iec_m_pg); 22421da177e4SLinus Torvalds } 22431da177e4SLinus Torvalds 2244c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2245c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2246c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2247c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2248c65b1445SDouglas Gilbert 2249c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2250c65b1445SDouglas Gilbert if (1 == pcontrol) 2251c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2252c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2253c65b1445SDouglas Gilbert } 2254c65b1445SDouglas Gilbert 2255c65b1445SDouglas Gilbert 2256c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2257c65b1445SDouglas Gilbert int target_dev_id) 2258c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2259c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2260c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2261773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2262773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2263c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2264c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2265c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2266c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2267773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2268773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2269c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2270c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2271c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2272c65b1445SDouglas Gilbert }; 2273c65b1445SDouglas Gilbert int port_a, port_b; 2274c65b1445SDouglas Gilbert 22751b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 22761b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 22771b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 22781b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2279c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2280c65b1445SDouglas Gilbert port_b = port_a + 1; 2281c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2282773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2283773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2284c65b1445SDouglas Gilbert if (1 == pcontrol) 2285c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2286c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2287c65b1445SDouglas Gilbert } 2288c65b1445SDouglas Gilbert 2289c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2290c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2291c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2292c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2293c65b1445SDouglas Gilbert }; 2294c65b1445SDouglas Gilbert 2295c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2296c65b1445SDouglas Gilbert if (1 == pcontrol) 2297c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2298c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2299c65b1445SDouglas Gilbert } 2300c65b1445SDouglas Gilbert 23011da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23021da177e4SLinus Torvalds 2303fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2304fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23051da177e4SLinus Torvalds { 230623183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23071da177e4SLinus Torvalds unsigned char dev_spec; 2308760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2309c2248fc9SDouglas Gilbert int target = scp->device->id; 23101da177e4SLinus Torvalds unsigned char *ap; 23111da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 231201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2313d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23141da177e4SLinus Torvalds 2315760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23161da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23171da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23181da177e4SLinus Torvalds subpcode = cmd[3]; 23191da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2320760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2321760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 232264e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2323d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 232423183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 232523183910SDouglas Gilbert else 232623183910SDouglas Gilbert bd_len = 0; 2327773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23281da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23291da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2330cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23311da177e4SLinus Torvalds return check_condition_result; 23321da177e4SLinus Torvalds } 2333c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2334c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2335d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2336d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2337b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23389447b6ceSMartin K. Petersen if (sdebug_wp) 23399447b6ceSMartin K. Petersen dev_spec |= 0x80; 23409447b6ceSMartin K. Petersen } else 234123183910SDouglas Gilbert dev_spec = 0x0; 23421da177e4SLinus Torvalds if (msense_6) { 23431da177e4SLinus Torvalds arr[2] = dev_spec; 234423183910SDouglas Gilbert arr[3] = bd_len; 23451da177e4SLinus Torvalds offset = 4; 23461da177e4SLinus Torvalds } else { 23471da177e4SLinus Torvalds arr[3] = dev_spec; 234823183910SDouglas Gilbert if (16 == bd_len) 234923183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 235023183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23511da177e4SLinus Torvalds offset = 8; 23521da177e4SLinus Torvalds } 23531da177e4SLinus Torvalds ap = arr + offset; 235428898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 235528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 235628898873SFUJITA Tomonori 235723183910SDouglas Gilbert if (8 == bd_len) { 2358773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2359773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2360773642d9SDouglas Gilbert else 2361773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2362773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 236323183910SDouglas Gilbert offset += bd_len; 236423183910SDouglas Gilbert ap = arr + offset; 236523183910SDouglas Gilbert } else if (16 == bd_len) { 2366773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2367773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 236823183910SDouglas Gilbert offset += bd_len; 236923183910SDouglas Gilbert ap = arr + offset; 237023183910SDouglas Gilbert } 23711da177e4SLinus Torvalds 2372c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2373c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 237422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 23751da177e4SLinus Torvalds return check_condition_result; 23761da177e4SLinus Torvalds } 2377760f3b03SDouglas Gilbert bad_pcode = false; 2378760f3b03SDouglas Gilbert 23791da177e4SLinus Torvalds switch (pcode) { 23801da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 23811da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 23821da177e4SLinus Torvalds offset += len; 23831da177e4SLinus Torvalds break; 23841da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 23851da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 23861da177e4SLinus Torvalds offset += len; 23871da177e4SLinus Torvalds break; 23881da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2389760f3b03SDouglas Gilbert if (is_disk) { 23901da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 23911da177e4SLinus Torvalds offset += len; 2392760f3b03SDouglas Gilbert } else 2393760f3b03SDouglas Gilbert bad_pcode = true; 23941da177e4SLinus Torvalds break; 23951da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2396d36da305SDouglas Gilbert if (is_disk || is_zbc) { 23971da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 23981da177e4SLinus Torvalds offset += len; 2399760f3b03SDouglas Gilbert } else 2400760f3b03SDouglas Gilbert bad_pcode = true; 24011da177e4SLinus Torvalds break; 24021da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24031da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24041da177e4SLinus Torvalds offset += len; 24051da177e4SLinus Torvalds break; 2406c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2407c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 240822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2409c65b1445SDouglas Gilbert return check_condition_result; 2410c65b1445SDouglas Gilbert } 2411c65b1445SDouglas Gilbert len = 0; 2412c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2413c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2414c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2415c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2416c65b1445SDouglas Gilbert target_dev_id); 2417c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2418c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2419c65b1445SDouglas Gilbert offset += len; 2420c65b1445SDouglas Gilbert break; 24211da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24221da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24231da177e4SLinus Torvalds offset += len; 24241da177e4SLinus Torvalds break; 24251da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2426c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24271da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24281da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2429760f3b03SDouglas Gilbert if (is_disk) { 2430760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2431760f3b03SDouglas Gilbert target); 2432760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2433760f3b03SDouglas Gilbert target); 2434d36da305SDouglas Gilbert } else if (is_zbc) { 2435d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2436d36da305SDouglas Gilbert target); 2437760f3b03SDouglas Gilbert } 24381da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2439c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2440c65b1445SDouglas Gilbert if (0xff == subpcode) { 2441c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2442c65b1445SDouglas Gilbert target, target_dev_id); 2443c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2444c65b1445SDouglas Gilbert } 24451da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2446760f3b03SDouglas Gilbert offset += len; 2447c65b1445SDouglas Gilbert } else { 244822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2449c65b1445SDouglas Gilbert return check_condition_result; 2450c65b1445SDouglas Gilbert } 24511da177e4SLinus Torvalds break; 24521da177e4SLinus Torvalds default: 2453760f3b03SDouglas Gilbert bad_pcode = true; 2454760f3b03SDouglas Gilbert break; 2455760f3b03SDouglas Gilbert } 2456760f3b03SDouglas Gilbert if (bad_pcode) { 245722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24581da177e4SLinus Torvalds return check_condition_result; 24591da177e4SLinus Torvalds } 24601da177e4SLinus Torvalds if (msense_6) 24611da177e4SLinus Torvalds arr[0] = offset - 1; 2462773642d9SDouglas Gilbert else 2463773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 246487c715dcSDouglas Gilbert return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset)); 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds 2467c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2468c65b1445SDouglas Gilbert 2469fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2470fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2471c65b1445SDouglas Gilbert { 2472c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2473c2248fc9SDouglas Gilbert int param_len, res, mpage; 2474c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 247501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2476c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2477c65b1445SDouglas Gilbert 2478c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2479c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2480c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2481773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2482c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 248322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2484c65b1445SDouglas Gilbert return check_condition_result; 2485c65b1445SDouglas Gilbert } 2486c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2487c65b1445SDouglas Gilbert if (-1 == res) 2488773642d9SDouglas Gilbert return DID_ERROR << 16; 2489773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2490cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2491cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2492cbf67842SDouglas Gilbert __func__, param_len, res); 2493773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2494773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 249523183910SDouglas Gilbert if (md_len > 2) { 249622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2497c65b1445SDouglas Gilbert return check_condition_result; 2498c65b1445SDouglas Gilbert } 2499c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2500c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2501c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2502c65b1445SDouglas Gilbert if (ps) { 250322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2504c65b1445SDouglas Gilbert return check_condition_result; 2505c65b1445SDouglas Gilbert } 2506c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2507773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2508c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2509c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2510cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2511c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2512c65b1445SDouglas Gilbert return check_condition_result; 2513c65b1445SDouglas Gilbert } 2514c65b1445SDouglas Gilbert switch (mpage) { 2515cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2516cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2517cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2518cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2519cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2520cbf67842SDouglas Gilbert } 2521cbf67842SDouglas Gilbert break; 2522c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2523c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2524c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2525c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25269447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25279447b6ceSMartin K. Petersen sdebug_wp = true; 25289447b6ceSMartin K. Petersen else 25299447b6ceSMartin K. Petersen sdebug_wp = false; 2530773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2531cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2532c65b1445SDouglas Gilbert } 2533c65b1445SDouglas Gilbert break; 2534c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2535c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2536c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2537c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2538cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2539c65b1445SDouglas Gilbert } 2540c65b1445SDouglas Gilbert break; 2541c65b1445SDouglas Gilbert default: 2542c65b1445SDouglas Gilbert break; 2543c65b1445SDouglas Gilbert } 254422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2545c65b1445SDouglas Gilbert return check_condition_result; 2546cbf67842SDouglas Gilbert set_mode_changed_ua: 2547cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2548cbf67842SDouglas Gilbert return 0; 2549c65b1445SDouglas Gilbert } 2550c65b1445SDouglas Gilbert 2551c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2552c65b1445SDouglas Gilbert { 2553c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2554c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2555c65b1445SDouglas Gilbert }; 2556c65b1445SDouglas Gilbert 2557c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2558c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2559c65b1445SDouglas Gilbert } 2560c65b1445SDouglas Gilbert 2561c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2562c65b1445SDouglas Gilbert { 2563c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2564c65b1445SDouglas Gilbert }; 2565c65b1445SDouglas Gilbert 2566c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2567c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2568c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2569c65b1445SDouglas Gilbert arr[5] = 0xff; 2570c65b1445SDouglas Gilbert } 2571c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2572c65b1445SDouglas Gilbert } 2573c65b1445SDouglas Gilbert 2574c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2575c65b1445SDouglas Gilbert 2576c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2577c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2578c65b1445SDouglas Gilbert { 2579ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2580c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 258101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2582c65b1445SDouglas Gilbert 2583c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2584c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2585c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2586c65b1445SDouglas Gilbert if (ppc || sp) { 258722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2588c65b1445SDouglas Gilbert return check_condition_result; 2589c65b1445SDouglas Gilbert } 2590c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 259123183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2592773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2593c65b1445SDouglas Gilbert arr[0] = pcode; 259423183910SDouglas Gilbert if (0 == subpcode) { 2595c65b1445SDouglas Gilbert switch (pcode) { 2596c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2597c65b1445SDouglas Gilbert n = 4; 2598c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2599c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2600c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2601c65b1445SDouglas Gilbert arr[3] = n - 4; 2602c65b1445SDouglas Gilbert break; 2603c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2604c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2605c65b1445SDouglas Gilbert break; 2606c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2607c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2608c65b1445SDouglas Gilbert break; 2609c65b1445SDouglas Gilbert default: 261022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2611c65b1445SDouglas Gilbert return check_condition_result; 2612c65b1445SDouglas Gilbert } 261323183910SDouglas Gilbert } else if (0xff == subpcode) { 261423183910SDouglas Gilbert arr[0] |= 0x40; 261523183910SDouglas Gilbert arr[1] = subpcode; 261623183910SDouglas Gilbert switch (pcode) { 261723183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 261823183910SDouglas Gilbert n = 4; 261923183910SDouglas Gilbert arr[n++] = 0x0; 262023183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 262123183910SDouglas Gilbert arr[n++] = 0x0; 262223183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 262323183910SDouglas Gilbert arr[n++] = 0xd; 262423183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 262523183910SDouglas Gilbert arr[n++] = 0x2f; 262623183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 262723183910SDouglas Gilbert arr[3] = n - 4; 262823183910SDouglas Gilbert break; 262923183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 263023183910SDouglas Gilbert n = 4; 263123183910SDouglas Gilbert arr[n++] = 0xd; 263223183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 263323183910SDouglas Gilbert arr[3] = n - 4; 263423183910SDouglas Gilbert break; 263523183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 263623183910SDouglas Gilbert n = 4; 263723183910SDouglas Gilbert arr[n++] = 0x2f; 263823183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 263923183910SDouglas Gilbert arr[3] = n - 4; 264023183910SDouglas Gilbert break; 264123183910SDouglas Gilbert default: 264222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 264323183910SDouglas Gilbert return check_condition_result; 264423183910SDouglas Gilbert } 264523183910SDouglas Gilbert } else { 264622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 264723183910SDouglas Gilbert return check_condition_result; 264823183910SDouglas Gilbert } 264987c715dcSDouglas Gilbert len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len); 2650c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 265187c715dcSDouglas Gilbert min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ)); 2652c65b1445SDouglas Gilbert } 2653c65b1445SDouglas Gilbert 2654f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2655f0d1cf93SDouglas Gilbert { 2656f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2657f0d1cf93SDouglas Gilbert } 2658f0d1cf93SDouglas Gilbert 2659f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2660f0d1cf93SDouglas Gilbert unsigned long long lba) 2661f0d1cf93SDouglas Gilbert { 2662108e36f0SDamien Le Moal return &devip->zstate[lba >> devip->zsize_shift]; 2663f0d1cf93SDouglas Gilbert } 2664f0d1cf93SDouglas Gilbert 2665f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2666f0d1cf93SDouglas Gilbert { 266764e14eceSDamien Le Moal return zsp->z_type == ZBC_ZONE_TYPE_CNV; 2668f0d1cf93SDouglas Gilbert } 2669f0d1cf93SDouglas Gilbert 2670f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2671f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2672f0d1cf93SDouglas Gilbert { 2673f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2674f0d1cf93SDouglas Gilbert 2675f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2676f0d1cf93SDouglas Gilbert return; 2677f0d1cf93SDouglas Gilbert 2678f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2679f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2680f0d1cf93SDouglas Gilbert return; 2681f0d1cf93SDouglas Gilbert 2682f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2683f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2684f0d1cf93SDouglas Gilbert else 2685f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2686f0d1cf93SDouglas Gilbert 2687f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2688f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2689f0d1cf93SDouglas Gilbert } else { 2690f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2691f0d1cf93SDouglas Gilbert devip->nr_closed++; 2692f0d1cf93SDouglas Gilbert } 2693f0d1cf93SDouglas Gilbert } 2694f0d1cf93SDouglas Gilbert 2695f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2696f0d1cf93SDouglas Gilbert { 2697f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2698f0d1cf93SDouglas Gilbert unsigned int i; 2699f0d1cf93SDouglas Gilbert 2700f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2701f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2702f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2703f0d1cf93SDouglas Gilbert return; 2704f0d1cf93SDouglas Gilbert } 2705f0d1cf93SDouglas Gilbert } 2706f0d1cf93SDouglas Gilbert } 2707f0d1cf93SDouglas Gilbert 2708f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2709f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2710f0d1cf93SDouglas Gilbert { 2711f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2712f0d1cf93SDouglas Gilbert 2713f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2714f0d1cf93SDouglas Gilbert return; 2715f0d1cf93SDouglas Gilbert 2716f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2717f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2718f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2719f0d1cf93SDouglas Gilbert return; 2720f0d1cf93SDouglas Gilbert 2721f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2722f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2723f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2724f0d1cf93SDouglas Gilbert else if (devip->max_open && 2725f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2726f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2727f0d1cf93SDouglas Gilbert 2728f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2729f0d1cf93SDouglas Gilbert devip->nr_closed--; 2730f0d1cf93SDouglas Gilbert if (explicit) { 2731f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2732f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2733f0d1cf93SDouglas Gilbert } else { 2734f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2735f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2736f0d1cf93SDouglas Gilbert } 2737f0d1cf93SDouglas Gilbert } 2738f0d1cf93SDouglas Gilbert 2739f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2740f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2741f0d1cf93SDouglas Gilbert { 2742f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 274364e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2744f0d1cf93SDouglas Gilbert 2745f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2746f0d1cf93SDouglas Gilbert return; 2747f0d1cf93SDouglas Gilbert 274864e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2749f0d1cf93SDouglas Gilbert zsp->z_wp += num; 275064e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2751f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 275264e14eceSDamien Le Moal return; 275364e14eceSDamien Le Moal } 275464e14eceSDamien Le Moal 275564e14eceSDamien Le Moal while (num) { 275664e14eceSDamien Le Moal if (lba != zsp->z_wp) 275764e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 275864e14eceSDamien Le Moal 275964e14eceSDamien Le Moal end = lba + num; 276064e14eceSDamien Le Moal if (end >= zend) { 276164e14eceSDamien Le Moal n = zend - lba; 276264e14eceSDamien Le Moal zsp->z_wp = zend; 276364e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 276464e14eceSDamien Le Moal n = num; 276564e14eceSDamien Le Moal zsp->z_wp = end; 276664e14eceSDamien Le Moal } else { 276764e14eceSDamien Le Moal n = num; 276864e14eceSDamien Le Moal } 276964e14eceSDamien Le Moal if (zsp->z_wp >= zend) 277064e14eceSDamien Le Moal zsp->z_cond = ZC5_FULL; 277164e14eceSDamien Le Moal 277264e14eceSDamien Le Moal num -= n; 277364e14eceSDamien Le Moal lba += n; 277464e14eceSDamien Le Moal if (num) { 277564e14eceSDamien Le Moal zsp++; 277664e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 277764e14eceSDamien Le Moal } 277864e14eceSDamien Le Moal } 2779f0d1cf93SDouglas Gilbert } 2780f0d1cf93SDouglas Gilbert 2781f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 27829447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 27831da177e4SLinus Torvalds { 2784f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2785f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2786f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2787f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2788f0d1cf93SDouglas Gilbert 2789f0d1cf93SDouglas Gilbert if (!write) { 279064e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 279164e14eceSDamien Le Moal return 0; 279264e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 2793f0d1cf93SDouglas Gilbert if (zsp_end != zsp && 2794f0d1cf93SDouglas Gilbert zbc_zone_is_conv(zsp) && 2795f0d1cf93SDouglas Gilbert !zbc_zone_is_conv(zsp_end)) { 2796f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2797f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2798f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2799f0d1cf93SDouglas Gilbert return check_condition_result; 2800f0d1cf93SDouglas Gilbert } 2801f0d1cf93SDouglas Gilbert return 0; 2802f0d1cf93SDouglas Gilbert } 2803f0d1cf93SDouglas Gilbert 2804f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2805f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2806f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2807f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2808f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2809f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2810f0d1cf93SDouglas Gilbert return check_condition_result; 2811f0d1cf93SDouglas Gilbert } 2812f0d1cf93SDouglas Gilbert return 0; 2813f0d1cf93SDouglas Gilbert } 2814f0d1cf93SDouglas Gilbert 281564e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2816f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2817f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2818f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2819f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2820f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2821f0d1cf93SDouglas Gilbert return check_condition_result; 2822f0d1cf93SDouglas Gilbert } 2823f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2824f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2825f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2826f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2827f0d1cf93SDouglas Gilbert return check_condition_result; 2828f0d1cf93SDouglas Gilbert } 2829f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2830f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2831f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2832f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2833f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2834f0d1cf93SDouglas Gilbert return check_condition_result; 2835f0d1cf93SDouglas Gilbert } 283664e14eceSDamien Le Moal } 2837f0d1cf93SDouglas Gilbert 2838f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2839f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2840f0d1cf93SDouglas Gilbert if (devip->max_open && 2841f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2842f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2843f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2844f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2845f0d1cf93SDouglas Gilbert return check_condition_result; 2846f0d1cf93SDouglas Gilbert } 2847f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2848f0d1cf93SDouglas Gilbert } 2849f0d1cf93SDouglas Gilbert 2850f0d1cf93SDouglas Gilbert return 0; 2851f0d1cf93SDouglas Gilbert } 2852f0d1cf93SDouglas Gilbert 2853f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2854f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2855f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2856f0d1cf93SDouglas Gilbert { 2857f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2858f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2859f0d1cf93SDouglas Gilbert 2860c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 286122017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 28621da177e4SLinus Torvalds return check_condition_result; 28631da177e4SLinus Torvalds } 2864c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2865c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 286622017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2867cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2868c65b1445SDouglas Gilbert return check_condition_result; 2869c65b1445SDouglas Gilbert } 28709447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 28719447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 28729447b6ceSMartin K. Petersen return check_condition_result; 28739447b6ceSMartin K. Petersen } 2874f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2875f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2876f0d1cf93SDouglas Gilbert 287719789100SFUJITA Tomonori return 0; 287819789100SFUJITA Tomonori } 287919789100SFUJITA Tomonori 2880b6ff8ca7SDouglas Gilbert /* 2881b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 2882b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 2883b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 2884b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 2885b6ff8ca7SDouglas Gilbert */ 2886b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 2887b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 288887c715dcSDouglas Gilbert { 2889b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 2890b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 2891b6ff8ca7SDouglas Gilbert return NULL; 2892b6ff8ca7SDouglas Gilbert } 2893b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 289487c715dcSDouglas Gilbert } 289587c715dcSDouglas Gilbert 2896a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 289787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 289887c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 289919789100SFUJITA Tomonori { 290019789100SFUJITA Tomonori int ret; 2901c2248fc9SDouglas Gilbert u64 block, rest = 0; 2902a4517511SAkinobu Mita enum dma_data_direction dir; 290387c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 290487c715dcSDouglas Gilbert u8 *fsp; 290519789100SFUJITA Tomonori 2906c2248fc9SDouglas Gilbert if (do_write) { 2907a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 29084f2c8bf6SDouglas Gilbert write_since_sync = true; 2909a4517511SAkinobu Mita } else { 2910a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2911a4517511SAkinobu Mita } 2912a4517511SAkinobu Mita 291387c715dcSDouglas Gilbert if (!sdb->length || !sip) 2914a4517511SAkinobu Mita return 0; 291587c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2916a4517511SAkinobu Mita return -1; 291787c715dcSDouglas Gilbert fsp = sip->storep; 291819789100SFUJITA Tomonori 291919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 292019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 292119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 292219789100SFUJITA Tomonori 2923386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 292487c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 29250a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2926773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2927a4517511SAkinobu Mita return ret; 2928a4517511SAkinobu Mita 2929a4517511SAkinobu Mita if (rest) { 2930386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 293187c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 29320a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 29330a7e69c7SDouglas Gilbert do_write); 2934a4517511SAkinobu Mita } 293519789100SFUJITA Tomonori 293619789100SFUJITA Tomonori return ret; 293719789100SFUJITA Tomonori } 293819789100SFUJITA Tomonori 293987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 294087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 294187c715dcSDouglas Gilbert { 294287c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 294387c715dcSDouglas Gilbert 294487c715dcSDouglas Gilbert if (!sdb->length) 294587c715dcSDouglas Gilbert return 0; 294687c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 294787c715dcSDouglas Gilbert return -1; 294887c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 294987c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 295087c715dcSDouglas Gilbert } 295187c715dcSDouglas Gilbert 295287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 295387c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 295438d5c833SDouglas Gilbert * return false. */ 295587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 2956c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 295738d5c833SDouglas Gilbert { 295838d5c833SDouglas Gilbert bool res; 295938d5c833SDouglas Gilbert u64 block, rest = 0; 296038d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2961773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 296287c715dcSDouglas Gilbert u8 *fsp = sip->storep; 296338d5c833SDouglas Gilbert 296438d5c833SDouglas Gilbert block = do_div(lba, store_blks); 296538d5c833SDouglas Gilbert if (block + num > store_blks) 296638d5c833SDouglas Gilbert rest = block + num - store_blks; 296738d5c833SDouglas Gilbert 296887c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 296938d5c833SDouglas Gilbert if (!res) 297038d5c833SDouglas Gilbert return res; 297138d5c833SDouglas Gilbert if (rest) 297287c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 297338d5c833SDouglas Gilbert rest * lb_size); 297438d5c833SDouglas Gilbert if (!res) 297538d5c833SDouglas Gilbert return res; 2976c3e2fe92SDouglas Gilbert if (compare_only) 2977c3e2fe92SDouglas Gilbert return true; 297838d5c833SDouglas Gilbert arr += num * lb_size; 297987c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 298038d5c833SDouglas Gilbert if (rest) 298187c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 298238d5c833SDouglas Gilbert return res; 298338d5c833SDouglas Gilbert } 298438d5c833SDouglas Gilbert 298551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2986beb40ea4SAkinobu Mita { 298751d648afSAkinobu Mita __be16 csum; 2988beb40ea4SAkinobu Mita 2989773642d9SDouglas Gilbert if (sdebug_guard) 299051d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 299151d648afSAkinobu Mita else 2992beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 299351d648afSAkinobu Mita 2994beb40ea4SAkinobu Mita return csum; 2995beb40ea4SAkinobu Mita } 2996beb40ea4SAkinobu Mita 29976ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 2998beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2999beb40ea4SAkinobu Mita { 3000773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3001beb40ea4SAkinobu Mita 3002beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3003c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3004beb40ea4SAkinobu Mita (unsigned long)sector, 3005beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3006beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3007beb40ea4SAkinobu Mita return 0x01; 3008beb40ea4SAkinobu Mita } 30098475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3010beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3011c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3012c1287970STomas Winkler (unsigned long)sector); 3013beb40ea4SAkinobu Mita return 0x03; 3014beb40ea4SAkinobu Mita } 30158475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3016beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3017c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3018c1287970STomas Winkler (unsigned long)sector); 3019beb40ea4SAkinobu Mita return 0x03; 3020beb40ea4SAkinobu Mita } 3021beb40ea4SAkinobu Mita return 0; 3022beb40ea4SAkinobu Mita } 3023beb40ea4SAkinobu Mita 302487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 302565f72f2aSAkinobu Mita unsigned int sectors, bool read) 3026c6a44287SMartin K. Petersen { 3027be4e11beSAkinobu Mita size_t resid; 3028c6a44287SMartin K. Petersen void *paddr; 302987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3030b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 303187c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 303214faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3033be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3034c6a44287SMartin K. Petersen 3035e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3036e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3037c6a44287SMartin K. Petersen 303887c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 303987c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3040be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3041be4e11beSAkinobu Mita 3042be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 304387c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 304487c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3045be4e11beSAkinobu Mita size_t rest = 0; 304614faa944SAkinobu Mita 304714faa944SAkinobu Mita if (dif_store_end < start + len) 304814faa944SAkinobu Mita rest = start + len - dif_store_end; 3049c6a44287SMartin K. Petersen 3050be4e11beSAkinobu Mita paddr = miter.addr; 305114faa944SAkinobu Mita 305265f72f2aSAkinobu Mita if (read) 305365f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 305465f72f2aSAkinobu Mita else 305565f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 305665f72f2aSAkinobu Mita 305765f72f2aSAkinobu Mita if (rest) { 305865f72f2aSAkinobu Mita if (read) 305914faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 306065f72f2aSAkinobu Mita else 306165f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 306265f72f2aSAkinobu Mita } 3063c6a44287SMartin K. Petersen 3064e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3065c6a44287SMartin K. Petersen resid -= len; 3066c6a44287SMartin K. Petersen } 3067be4e11beSAkinobu Mita sg_miter_stop(&miter); 3068bb8c063cSAkinobu Mita } 3069c6a44287SMartin K. Petersen 307087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3071bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3072bb8c063cSAkinobu Mita { 3073bb8c063cSAkinobu Mita unsigned int i; 3074bb8c063cSAkinobu Mita sector_t sector; 307587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3076b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 307787c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3078bb8c063cSAkinobu Mita 3079c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3080bb8c063cSAkinobu Mita int ret; 3081bb8c063cSAkinobu Mita 3082bb8c063cSAkinobu Mita sector = start_sec + i; 308387c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3084bb8c063cSAkinobu Mita 308551d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3086bb8c063cSAkinobu Mita continue; 3087bb8c063cSAkinobu Mita 308887c715dcSDouglas Gilbert ret = dif_verify(sdt, lba2fake_store(sip, sector), sector, 308987c715dcSDouglas Gilbert ei_lba); 3090bb8c063cSAkinobu Mita if (ret) { 3091bb8c063cSAkinobu Mita dif_errors++; 3092bb8c063cSAkinobu Mita return ret; 3093bb8c063cSAkinobu Mita } 3094bb8c063cSAkinobu Mita } 3095bb8c063cSAkinobu Mita 309687c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3097c6a44287SMartin K. Petersen dix_reads++; 3098c6a44287SMartin K. Petersen 3099c6a44287SMartin K. Petersen return 0; 3100c6a44287SMartin K. Petersen } 3101c6a44287SMartin K. Petersen 3102fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 310319789100SFUJITA Tomonori { 310487c715dcSDouglas Gilbert bool check_prot; 3105c2248fc9SDouglas Gilbert u32 num; 3106c2248fc9SDouglas Gilbert u32 ei_lba; 310719789100SFUJITA Tomonori int ret; 310887c715dcSDouglas Gilbert u64 lba; 3109b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 311087c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 311187c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 311287c715dcSDouglas Gilbert struct sdebug_queued_cmd *sqcp; 311319789100SFUJITA Tomonori 3114c2248fc9SDouglas Gilbert switch (cmd[0]) { 3115c2248fc9SDouglas Gilbert case READ_16: 3116c2248fc9SDouglas Gilbert ei_lba = 0; 3117c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3118c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3119c2248fc9SDouglas Gilbert check_prot = true; 3120c2248fc9SDouglas Gilbert break; 3121c2248fc9SDouglas Gilbert case READ_10: 3122c2248fc9SDouglas Gilbert ei_lba = 0; 3123c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3124c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3125c2248fc9SDouglas Gilbert check_prot = true; 3126c2248fc9SDouglas Gilbert break; 3127c2248fc9SDouglas Gilbert case READ_6: 3128c2248fc9SDouglas Gilbert ei_lba = 0; 3129c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3130c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3131c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3132c2248fc9SDouglas Gilbert check_prot = true; 3133c2248fc9SDouglas Gilbert break; 3134c2248fc9SDouglas Gilbert case READ_12: 3135c2248fc9SDouglas Gilbert ei_lba = 0; 3136c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3137c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3138c2248fc9SDouglas Gilbert check_prot = true; 3139c2248fc9SDouglas Gilbert break; 3140c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3141c2248fc9SDouglas Gilbert ei_lba = 0; 3142c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3143c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3144c2248fc9SDouglas Gilbert check_prot = false; 3145c2248fc9SDouglas Gilbert break; 3146c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3147c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3148c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3149c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3150c2248fc9SDouglas Gilbert check_prot = false; 3151c2248fc9SDouglas Gilbert break; 3152c2248fc9SDouglas Gilbert } 3153f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 31548475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3155c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3156c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3157c2248fc9SDouglas Gilbert return check_condition_result; 3158c2248fc9SDouglas Gilbert } 31598475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31608475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3161c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3162c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3163c2248fc9SDouglas Gilbert "to DIF device\n"); 3164c2248fc9SDouglas Gilbert } 3165f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3166c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 3167c2248fc9SDouglas Gilbert 3168c4837394SDouglas Gilbert if (sqcp) { 3169c4837394SDouglas Gilbert if (sqcp->inj_short) 3170c2248fc9SDouglas Gilbert num /= 2; 3171c2248fc9SDouglas Gilbert } 3172c4837394SDouglas Gilbert } else 3173c4837394SDouglas Gilbert sqcp = NULL; 3174c2248fc9SDouglas Gilbert 31759447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 31769447b6ceSMartin K. Petersen if (ret) 31779447b6ceSMartin K. Petersen return ret; 3178f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3179d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3180d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3181c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3182c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3183c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3184c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3185c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 318632f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 318732f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3188c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3189c65b1445SDouglas Gilbert } 3190c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 31911da177e4SLinus Torvalds return check_condition_result; 31921da177e4SLinus Torvalds } 3193c6a44287SMartin K. Petersen 319467da413fSDouglas Gilbert read_lock(macc_lckp); 31956c78cc06SAkinobu Mita 3196c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3197f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3198c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 3199c6a44287SMartin K. Petersen 3200c6a44287SMartin K. Petersen if (prot_ret) { 320167da413fSDouglas Gilbert read_unlock(macc_lckp); 3202c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 3203c6a44287SMartin K. Petersen return illegal_condition_result; 3204c6a44287SMartin K. Petersen } 3205c6a44287SMartin K. Petersen } 3206c6a44287SMartin K. Petersen 320787c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 320867da413fSDouglas Gilbert read_unlock(macc_lckp); 3209f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3210a4517511SAkinobu Mita return DID_ERROR << 16; 3211a4517511SAkinobu Mita 321242d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3213a4517511SAkinobu Mita 3214c4837394SDouglas Gilbert if (unlikely(sqcp)) { 3215c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3216c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3217c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3218c2248fc9SDouglas Gilbert return check_condition_result; 3219c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 3220c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 3221c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 3222c2248fc9SDouglas Gilbert return check_condition_result; 3223c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3224c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3225c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3226c2248fc9SDouglas Gilbert return illegal_condition_result; 3227c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3228c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3229c2248fc9SDouglas Gilbert return illegal_condition_result; 3230c2248fc9SDouglas Gilbert } 3231c2248fc9SDouglas Gilbert } 3232a4517511SAkinobu Mita return 0; 32331da177e4SLinus Torvalds } 32341da177e4SLinus Torvalds 323558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 3236c6a44287SMartin K. Petersen { 3237cbf67842SDouglas Gilbert int i, j, n; 3238c6a44287SMartin K. Petersen 3239cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 3240c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 3241cbf67842SDouglas Gilbert char b[128]; 3242c6a44287SMartin K. Petersen 3243cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 3244c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 3245c6a44287SMartin K. Petersen 3246cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 3247cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 3248cbf67842SDouglas Gilbert " %c ", buf[i+j]); 3249cbf67842SDouglas Gilbert else 3250cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 3251cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 3252cbf67842SDouglas Gilbert } 3253cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 3254c6a44287SMartin K. Petersen } 3255c6a44287SMartin K. Petersen } 3256c6a44287SMartin K. Petersen 3257c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3258395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3259c6a44287SMartin K. Petersen { 3260be4e11beSAkinobu Mita int ret; 32616ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3262be4e11beSAkinobu Mita void *daddr; 326365f72f2aSAkinobu Mita sector_t sector = start_sec; 3264c6a44287SMartin K. Petersen int ppage_offset; 3265be4e11beSAkinobu Mita int dpage_offset; 3266be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3267be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3268c6a44287SMartin K. Petersen 3269c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3270c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3271c6a44287SMartin K. Petersen 3272be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3273be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3274be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3275be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3276be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3277c6a44287SMartin K. Petersen 3278be4e11beSAkinobu Mita /* For each protection page */ 3279be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3280be4e11beSAkinobu Mita dpage_offset = 0; 3281be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3282be4e11beSAkinobu Mita ret = 0x01; 3283be4e11beSAkinobu Mita goto out; 3284c6a44287SMartin K. Petersen } 3285c6a44287SMartin K. Petersen 3286be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 32876ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3288be4e11beSAkinobu Mita /* If we're at the end of the current 3289be4e11beSAkinobu Mita * data page advance to the next one 3290be4e11beSAkinobu Mita */ 3291be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3292be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3293be4e11beSAkinobu Mita ret = 0x01; 3294be4e11beSAkinobu Mita goto out; 3295be4e11beSAkinobu Mita } 3296be4e11beSAkinobu Mita dpage_offset = 0; 3297be4e11beSAkinobu Mita } 3298c6a44287SMartin K. Petersen 3299be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3300be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3301be4e11beSAkinobu Mita 3302be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3303beb40ea4SAkinobu Mita if (ret) { 3304773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 3305395cef03SMartin K. Petersen goto out; 3306395cef03SMartin K. Petersen } 3307395cef03SMartin K. Petersen 3308c6a44287SMartin K. Petersen sector++; 3309395cef03SMartin K. Petersen ei_lba++; 3310773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3311c6a44287SMartin K. Petersen } 3312be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3313be4e11beSAkinobu Mita sg_miter_stop(&diter); 3314c6a44287SMartin K. Petersen } 3315be4e11beSAkinobu Mita sg_miter_stop(&piter); 3316c6a44287SMartin K. Petersen 331765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3318c6a44287SMartin K. Petersen dix_writes++; 3319c6a44287SMartin K. Petersen 3320c6a44287SMartin K. Petersen return 0; 3321c6a44287SMartin K. Petersen 3322c6a44287SMartin K. Petersen out: 3323c6a44287SMartin K. Petersen dif_errors++; 3324be4e11beSAkinobu Mita sg_miter_stop(&diter); 3325be4e11beSAkinobu Mita sg_miter_stop(&piter); 3326c6a44287SMartin K. Petersen return ret; 3327c6a44287SMartin K. Petersen } 3328c6a44287SMartin K. Petersen 3329b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3330b90ebc3dSAkinobu Mita { 3331773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3332773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3333773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3334b90ebc3dSAkinobu Mita return lba; 3335b90ebc3dSAkinobu Mita } 3336b90ebc3dSAkinobu Mita 3337b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3338b90ebc3dSAkinobu Mita { 3339773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3340a027b5b9SAkinobu Mita 3341773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3342773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3343a027b5b9SAkinobu Mita return lba; 3344a027b5b9SAkinobu Mita } 3345a027b5b9SAkinobu Mita 334687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 334787c715dcSDouglas Gilbert unsigned int *num) 334844d92694SMartin K. Petersen { 3349b90ebc3dSAkinobu Mita sector_t end; 3350b90ebc3dSAkinobu Mita unsigned int mapped; 3351b90ebc3dSAkinobu Mita unsigned long index; 3352b90ebc3dSAkinobu Mita unsigned long next; 335344d92694SMartin K. Petersen 3354b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 335587c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 335644d92694SMartin K. Petersen 335744d92694SMartin K. Petersen if (mapped) 335887c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 335944d92694SMartin K. Petersen else 336087c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 336144d92694SMartin K. Petersen 3362b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 336344d92694SMartin K. Petersen *num = end - lba; 336444d92694SMartin K. Petersen return mapped; 336544d92694SMartin K. Petersen } 336644d92694SMartin K. Petersen 336787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 336887c715dcSDouglas Gilbert unsigned int len) 336944d92694SMartin K. Petersen { 337044d92694SMartin K. Petersen sector_t end = lba + len; 337144d92694SMartin K. Petersen 337244d92694SMartin K. Petersen while (lba < end) { 3373b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 337444d92694SMartin K. Petersen 3375b90ebc3dSAkinobu Mita if (index < map_size) 337687c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 337744d92694SMartin K. Petersen 3378b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 337944d92694SMartin K. Petersen } 338044d92694SMartin K. Petersen } 338144d92694SMartin K. Petersen 338287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 338387c715dcSDouglas Gilbert unsigned int len) 338444d92694SMartin K. Petersen { 338544d92694SMartin K. Petersen sector_t end = lba + len; 338687c715dcSDouglas Gilbert u8 *fsp = sip->storep; 338744d92694SMartin K. Petersen 338844d92694SMartin K. Petersen while (lba < end) { 3389b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 339044d92694SMartin K. Petersen 3391b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3392773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3393b90ebc3dSAkinobu Mita index < map_size) { 339487c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3395760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 339687c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3397760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3398773642d9SDouglas Gilbert sdebug_sector_size * 3399773642d9SDouglas Gilbert sdebug_unmap_granularity); 3400be1dd78dSEric Sandeen } 340187c715dcSDouglas Gilbert if (sip->dif_storep) { 340287c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 340387c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3404773642d9SDouglas Gilbert sdebug_unmap_granularity); 3405e9926b43SAkinobu Mita } 3406b90ebc3dSAkinobu Mita } 3407b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 340844d92694SMartin K. Petersen } 340944d92694SMartin K. Petersen } 341044d92694SMartin K. Petersen 3411fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 34121da177e4SLinus Torvalds { 341387c715dcSDouglas Gilbert bool check_prot; 3414c2248fc9SDouglas Gilbert u32 num; 3415c2248fc9SDouglas Gilbert u32 ei_lba; 341619789100SFUJITA Tomonori int ret; 341787c715dcSDouglas Gilbert u64 lba; 3418b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3419b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 342087c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 34211da177e4SLinus Torvalds 3422c2248fc9SDouglas Gilbert switch (cmd[0]) { 3423c2248fc9SDouglas Gilbert case WRITE_16: 3424c2248fc9SDouglas Gilbert ei_lba = 0; 3425c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3426c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3427c2248fc9SDouglas Gilbert check_prot = true; 3428c2248fc9SDouglas Gilbert break; 3429c2248fc9SDouglas Gilbert case WRITE_10: 3430c2248fc9SDouglas Gilbert ei_lba = 0; 3431c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3432c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3433c2248fc9SDouglas Gilbert check_prot = true; 3434c2248fc9SDouglas Gilbert break; 3435c2248fc9SDouglas Gilbert case WRITE_6: 3436c2248fc9SDouglas Gilbert ei_lba = 0; 3437c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3438c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3439c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3440c2248fc9SDouglas Gilbert check_prot = true; 3441c2248fc9SDouglas Gilbert break; 3442c2248fc9SDouglas Gilbert case WRITE_12: 3443c2248fc9SDouglas Gilbert ei_lba = 0; 3444c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3445c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3446c2248fc9SDouglas Gilbert check_prot = true; 3447c2248fc9SDouglas Gilbert break; 3448c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3449c2248fc9SDouglas Gilbert ei_lba = 0; 3450c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3451c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3452c2248fc9SDouglas Gilbert check_prot = false; 3453c2248fc9SDouglas Gilbert break; 3454c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3455c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3456c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3457c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3458c2248fc9SDouglas Gilbert check_prot = false; 3459c2248fc9SDouglas Gilbert break; 3460c2248fc9SDouglas Gilbert } 3461f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 34628475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3463c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3464c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3465c2248fc9SDouglas Gilbert return check_condition_result; 3466c2248fc9SDouglas Gilbert } 34678475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 34688475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3469c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3470c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3471c2248fc9SDouglas Gilbert "to DIF device\n"); 3472c2248fc9SDouglas Gilbert } 3473f0d1cf93SDouglas Gilbert 347467da413fSDouglas Gilbert write_lock(macc_lckp); 3475f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3476f0d1cf93SDouglas Gilbert if (ret) { 3477f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3478f0d1cf93SDouglas Gilbert return ret; 3479f0d1cf93SDouglas Gilbert } 34806c78cc06SAkinobu Mita 3481c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3482f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3483c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 3484c6a44287SMartin K. Petersen 3485c6a44287SMartin K. Petersen if (prot_ret) { 348667da413fSDouglas Gilbert write_unlock(macc_lckp); 3487c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 3488c6a44287SMartin K. Petersen return illegal_condition_result; 3489c6a44287SMartin K. Petersen } 3490c6a44287SMartin K. Petersen } 3491c6a44287SMartin K. Petersen 349287c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3493f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 349487c715dcSDouglas Gilbert map_region(sip, lba, num); 3495f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3496f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3497f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 349867da413fSDouglas Gilbert write_unlock(macc_lckp); 3499f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3500773642d9SDouglas Gilbert return DID_ERROR << 16; 3501c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3502c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3503c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3504cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3505773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 350644d92694SMartin K. Petersen 3507f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3508c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3509c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3510c2248fc9SDouglas Gilbert 3511c4837394SDouglas Gilbert if (sqcp) { 3512c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3513c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3514c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3515c2248fc9SDouglas Gilbert return check_condition_result; 3516c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3517c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3518c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3519c2248fc9SDouglas Gilbert return illegal_condition_result; 3520c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3521c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3522c2248fc9SDouglas Gilbert return illegal_condition_result; 3523c2248fc9SDouglas Gilbert } 3524c2248fc9SDouglas Gilbert } 3525c4837394SDouglas Gilbert } 35261da177e4SLinus Torvalds return 0; 35271da177e4SLinus Torvalds } 35281da177e4SLinus Torvalds 3529481b5e5cSDouglas Gilbert /* 3530481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3531481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3532481b5e5cSDouglas Gilbert */ 3533481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3534481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3535481b5e5cSDouglas Gilbert { 3536481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3537481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3538481b5e5cSDouglas Gilbert u8 *up; 3539b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3540b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 3541481b5e5cSDouglas Gilbert u8 wrprotect; 3542481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3543481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3544481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3545481b5e5cSDouglas Gilbert u32 ei_lba; 3546481b5e5cSDouglas Gilbert u64 lba; 3547481b5e5cSDouglas Gilbert int ret, res; 3548481b5e5cSDouglas Gilbert bool is_16; 3549481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3550481b5e5cSDouglas Gilbert 3551481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3552481b5e5cSDouglas Gilbert is_16 = false; 3553481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3554481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3555481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3556481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3557481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3558481b5e5cSDouglas Gilbert is_16 = true; 3559481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3560481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3561481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3562481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3563481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3564481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3565481b5e5cSDouglas Gilbert wrprotect) { 3566481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3567481b5e5cSDouglas Gilbert return illegal_condition_result; 3568481b5e5cSDouglas Gilbert } 3569481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3570481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3571481b5e5cSDouglas Gilbert wrprotect == 0) 3572481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3573481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3574481b5e5cSDouglas Gilbert } 3575481b5e5cSDouglas Gilbert } 3576481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3577481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3578481b5e5cSDouglas Gilbert if (lbdof == 0) { 3579481b5e5cSDouglas Gilbert if (sdebug_verbose) 3580481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3581481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3582481b5e5cSDouglas Gilbert my_name, __func__); 3583481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3584481b5e5cSDouglas Gilbert return illegal_condition_result; 3585481b5e5cSDouglas Gilbert } 3586481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3587481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3588481b5e5cSDouglas Gilbert if (sdebug_verbose) 3589481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3590481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3591481b5e5cSDouglas Gilbert my_name, __func__); 3592481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3593481b5e5cSDouglas Gilbert return illegal_condition_result; 3594481b5e5cSDouglas Gilbert } 3595481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3596481b5e5cSDouglas Gilbert if (lrdp == NULL) 3597481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3598481b5e5cSDouglas Gilbert if (sdebug_verbose) 3599481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3600481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3601481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3602481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3603481b5e5cSDouglas Gilbert if (res == -1) { 3604481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3605481b5e5cSDouglas Gilbert goto err_out; 3606481b5e5cSDouglas Gilbert } 3607481b5e5cSDouglas Gilbert 360867da413fSDouglas Gilbert write_lock(macc_lckp); 3609481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3610481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3611481b5e5cSDouglas Gilbert cum_lb = 0; 3612481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3613481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3614481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3615481b5e5cSDouglas Gilbert if (sdebug_verbose) 3616481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3617481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3618481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3619481b5e5cSDouglas Gilbert if (num == 0) 3620481b5e5cSDouglas Gilbert continue; 36219447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3622481b5e5cSDouglas Gilbert if (ret) 3623481b5e5cSDouglas Gilbert goto err_out_unlock; 3624481b5e5cSDouglas Gilbert num_by = num * lb_size; 3625481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3626481b5e5cSDouglas Gilbert 3627481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3628481b5e5cSDouglas Gilbert if (sdebug_verbose) 3629481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3630481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3631481b5e5cSDouglas Gilbert my_name, __func__); 3632481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3633481b5e5cSDouglas Gilbert 0); 3634481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3635481b5e5cSDouglas Gilbert goto err_out_unlock; 3636481b5e5cSDouglas Gilbert } 3637481b5e5cSDouglas Gilbert 3638481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3639481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3640481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3641481b5e5cSDouglas Gilbert ei_lba); 3642481b5e5cSDouglas Gilbert 3643481b5e5cSDouglas Gilbert if (prot_ret) { 3644481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3645481b5e5cSDouglas Gilbert prot_ret); 3646481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3647481b5e5cSDouglas Gilbert goto err_out_unlock; 3648481b5e5cSDouglas Gilbert } 3649481b5e5cSDouglas Gilbert } 3650481b5e5cSDouglas Gilbert 365187c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3652f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3653f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3654f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3655481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 365687c715dcSDouglas Gilbert map_region(sip, lba, num); 3657481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3658481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3659481b5e5cSDouglas Gilbert goto err_out_unlock; 3660481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3661481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3662481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3663481b5e5cSDouglas Gilbert my_name, num_by, ret); 3664481b5e5cSDouglas Gilbert 3665481b5e5cSDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3666481b5e5cSDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3667481b5e5cSDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3668481b5e5cSDouglas Gilbert 3669481b5e5cSDouglas Gilbert if (sqcp) { 3670481b5e5cSDouglas Gilbert if (sqcp->inj_recovered) { 3671481b5e5cSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3672481b5e5cSDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3673481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3674481b5e5cSDouglas Gilbert goto err_out_unlock; 3675481b5e5cSDouglas Gilbert } else if (sqcp->inj_dif) { 3676481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 3677481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 3678481b5e5cSDouglas Gilbert 0x10, 1); 3679481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3680481b5e5cSDouglas Gilbert goto err_out_unlock; 3681481b5e5cSDouglas Gilbert } else if (sqcp->inj_dix) { 3682481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 3683481b5e5cSDouglas Gilbert 0x10, 1); 3684481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3685481b5e5cSDouglas Gilbert goto err_out_unlock; 3686481b5e5cSDouglas Gilbert } 3687481b5e5cSDouglas Gilbert } 3688481b5e5cSDouglas Gilbert } 3689481b5e5cSDouglas Gilbert sg_off += num_by; 3690481b5e5cSDouglas Gilbert cum_lb += num; 3691481b5e5cSDouglas Gilbert } 3692481b5e5cSDouglas Gilbert ret = 0; 3693481b5e5cSDouglas Gilbert err_out_unlock: 369467da413fSDouglas Gilbert write_unlock(macc_lckp); 3695481b5e5cSDouglas Gilbert err_out: 3696481b5e5cSDouglas Gilbert kfree(lrdp); 3697481b5e5cSDouglas Gilbert return ret; 3698481b5e5cSDouglas Gilbert } 3699481b5e5cSDouglas Gilbert 3700fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3701fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 370244d92694SMartin K. Petersen { 3703f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3704f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 370544d92694SMartin K. Petersen unsigned long long i; 370640d07b52SDouglas Gilbert u64 block, lbaa; 370787c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 370887c715dcSDouglas Gilbert int ret; 370987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3710b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 3711b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 371240d07b52SDouglas Gilbert u8 *fs1p; 371387c715dcSDouglas Gilbert u8 *fsp; 371444d92694SMartin K. Petersen 371567da413fSDouglas Gilbert write_lock(macc_lckp); 371644d92694SMartin K. Petersen 3717f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3718f0d1cf93SDouglas Gilbert if (ret) { 3719f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3720f0d1cf93SDouglas Gilbert return ret; 3721f0d1cf93SDouglas Gilbert } 3722f0d1cf93SDouglas Gilbert 37239ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 372487c715dcSDouglas Gilbert unmap_region(sip, lba, num); 372544d92694SMartin K. Petersen goto out; 372644d92694SMartin K. Petersen } 372740d07b52SDouglas Gilbert lbaa = lba; 372840d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3729c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 373087c715dcSDouglas Gilbert fsp = sip->storep; 373187c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3732c2248fc9SDouglas Gilbert if (ndob) { 373340d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3734c2248fc9SDouglas Gilbert ret = 0; 3735c2248fc9SDouglas Gilbert } else 373640d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 373744d92694SMartin K. Petersen 373844d92694SMartin K. Petersen if (-1 == ret) { 373967da413fSDouglas Gilbert write_unlock(&sip->macc_lck); 3740773642d9SDouglas Gilbert return DID_ERROR << 16; 374140d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3742c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3743e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 374440d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 374544d92694SMartin K. Petersen 374644d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 374740d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 374840d07b52SDouglas Gilbert lbaa = lba + i; 374940d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 375087c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 375140d07b52SDouglas Gilbert } 37529ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 375387c715dcSDouglas Gilbert map_region(sip, lba, num); 3754f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3755f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3756f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 375744d92694SMartin K. Petersen out: 375867da413fSDouglas Gilbert write_unlock(macc_lckp); 375944d92694SMartin K. Petersen 376044d92694SMartin K. Petersen return 0; 376144d92694SMartin K. Petersen } 376244d92694SMartin K. Petersen 3763fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3764fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3765c2248fc9SDouglas Gilbert { 3766c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3767c2248fc9SDouglas Gilbert u32 lba; 3768c2248fc9SDouglas Gilbert u16 num; 3769c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3770c2248fc9SDouglas Gilbert bool unmap = false; 3771c2248fc9SDouglas Gilbert 3772c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3773773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3774c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3775c2248fc9SDouglas Gilbert return check_condition_result; 3776c2248fc9SDouglas Gilbert } else 3777c2248fc9SDouglas Gilbert unmap = true; 3778c2248fc9SDouglas Gilbert } 3779c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3780c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3781773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3782c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3783c2248fc9SDouglas Gilbert return check_condition_result; 3784c2248fc9SDouglas Gilbert } 3785c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3786c2248fc9SDouglas Gilbert } 3787c2248fc9SDouglas Gilbert 3788fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3789fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3790c2248fc9SDouglas Gilbert { 3791c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3792c2248fc9SDouglas Gilbert u64 lba; 3793c2248fc9SDouglas Gilbert u32 num; 3794c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3795c2248fc9SDouglas Gilbert bool unmap = false; 3796c2248fc9SDouglas Gilbert bool ndob = false; 3797c2248fc9SDouglas Gilbert 3798c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3799773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3800c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3801c2248fc9SDouglas Gilbert return check_condition_result; 3802c2248fc9SDouglas Gilbert } else 3803c2248fc9SDouglas Gilbert unmap = true; 3804c2248fc9SDouglas Gilbert } 3805c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3806c2248fc9SDouglas Gilbert ndob = true; 3807c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3808c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3809773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3810c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3811c2248fc9SDouglas Gilbert return check_condition_result; 3812c2248fc9SDouglas Gilbert } 3813c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3814c2248fc9SDouglas Gilbert } 3815c2248fc9SDouglas Gilbert 3816acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3817acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3818acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3819fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3820fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3821acafd0b9SEwan D. Milne { 3822acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3823acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3824acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3825acafd0b9SEwan D. Milne u8 mode; 3826acafd0b9SEwan D. Milne 3827acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3828acafd0b9SEwan D. Milne switch (mode) { 3829acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3830acafd0b9SEwan D. Milne /* set UAs on this device only */ 3831acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3832acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3833acafd0b9SEwan D. Milne break; 3834acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3835acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3836acafd0b9SEwan D. Milne break; 3837acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3838acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3839acafd0b9SEwan D. Milne list_for_each_entry(dp, 3840acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3841acafd0b9SEwan D. Milne dev_list) 3842acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3843acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3844acafd0b9SEwan D. Milne if (devip != dp) 3845acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3846acafd0b9SEwan D. Milne dp->uas_bm); 3847acafd0b9SEwan D. Milne } 3848acafd0b9SEwan D. Milne break; 3849acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3850acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3851acafd0b9SEwan D. Milne list_for_each_entry(dp, 3852acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3853acafd0b9SEwan D. Milne dev_list) 3854acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3855acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3856acafd0b9SEwan D. Milne dp->uas_bm); 3857acafd0b9SEwan D. Milne break; 3858acafd0b9SEwan D. Milne default: 3859acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3860acafd0b9SEwan D. Milne break; 3861acafd0b9SEwan D. Milne } 3862acafd0b9SEwan D. Milne return 0; 3863acafd0b9SEwan D. Milne } 3864acafd0b9SEwan D. Milne 3865fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3866fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 386738d5c833SDouglas Gilbert { 386838d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 386938d5c833SDouglas Gilbert u8 *arr; 3870b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3871b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 387238d5c833SDouglas Gilbert u64 lba; 387338d5c833SDouglas Gilbert u32 dnum; 3874773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 387538d5c833SDouglas Gilbert u8 num; 387638d5c833SDouglas Gilbert int ret; 3877d467d31fSDouglas Gilbert int retval = 0; 387838d5c833SDouglas Gilbert 3879d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 388038d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 388138d5c833SDouglas Gilbert if (0 == num) 388238d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 38838475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 388438d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 388538d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 388638d5c833SDouglas Gilbert return check_condition_result; 388738d5c833SDouglas Gilbert } 38888475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 38898475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 389038d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 389138d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 389238d5c833SDouglas Gilbert "to DIF device\n"); 38939447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 38949447b6ceSMartin K. Petersen if (ret) 38959447b6ceSMartin K. Petersen return ret; 3896d467d31fSDouglas Gilbert dnum = 2 * num; 38976396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 3898d467d31fSDouglas Gilbert if (NULL == arr) { 3899d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3900d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3901d467d31fSDouglas Gilbert return check_condition_result; 3902d467d31fSDouglas Gilbert } 390338d5c833SDouglas Gilbert 390467da413fSDouglas Gilbert write_lock(macc_lckp); 390538d5c833SDouglas Gilbert 390687c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 390738d5c833SDouglas Gilbert if (ret == -1) { 3908d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3909d467d31fSDouglas Gilbert goto cleanup; 3910773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 391138d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 391238d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 391338d5c833SDouglas Gilbert dnum * lb_size, ret); 3914c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 391538d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3916d467d31fSDouglas Gilbert retval = check_condition_result; 3917d467d31fSDouglas Gilbert goto cleanup; 391838d5c833SDouglas Gilbert } 391938d5c833SDouglas Gilbert if (scsi_debug_lbp()) 392087c715dcSDouglas Gilbert map_region(sip, lba, num); 3921d467d31fSDouglas Gilbert cleanup: 392267da413fSDouglas Gilbert write_unlock(macc_lckp); 3923d467d31fSDouglas Gilbert kfree(arr); 3924d467d31fSDouglas Gilbert return retval; 392538d5c833SDouglas Gilbert } 392638d5c833SDouglas Gilbert 392744d92694SMartin K. Petersen struct unmap_block_desc { 392844d92694SMartin K. Petersen __be64 lba; 392944d92694SMartin K. Petersen __be32 blocks; 393044d92694SMartin K. Petersen __be32 __reserved; 393144d92694SMartin K. Petersen }; 393244d92694SMartin K. Petersen 3933fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 393444d92694SMartin K. Petersen { 393544d92694SMartin K. Petersen unsigned char *buf; 393644d92694SMartin K. Petersen struct unmap_block_desc *desc; 3937b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3938b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 393944d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 394044d92694SMartin K. Petersen int ret; 394144d92694SMartin K. Petersen 3942c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3943c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3944c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3945c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 394644d92694SMartin K. Petersen 394744d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3948773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3949c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 395044d92694SMartin K. Petersen return check_condition_result; 3951c2248fc9SDouglas Gilbert } 395244d92694SMartin K. Petersen 3953b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3954c2248fc9SDouglas Gilbert if (!buf) { 3955c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3956c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3957c2248fc9SDouglas Gilbert return check_condition_result; 3958c2248fc9SDouglas Gilbert } 3959c2248fc9SDouglas Gilbert 3960c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 396144d92694SMartin K. Petersen 396244d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 396344d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 396444d92694SMartin K. Petersen 396544d92694SMartin K. Petersen desc = (void *)&buf[8]; 396644d92694SMartin K. Petersen 396767da413fSDouglas Gilbert write_lock(macc_lckp); 39686c78cc06SAkinobu Mita 396944d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 397044d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 397144d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 397244d92694SMartin K. Petersen 39739447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 397444d92694SMartin K. Petersen if (ret) 397544d92694SMartin K. Petersen goto out; 397644d92694SMartin K. Petersen 397787c715dcSDouglas Gilbert unmap_region(sip, lba, num); 397844d92694SMartin K. Petersen } 397944d92694SMartin K. Petersen 398044d92694SMartin K. Petersen ret = 0; 398144d92694SMartin K. Petersen 398244d92694SMartin K. Petersen out: 398367da413fSDouglas Gilbert write_unlock(macc_lckp); 398444d92694SMartin K. Petersen kfree(buf); 398544d92694SMartin K. Petersen 398644d92694SMartin K. Petersen return ret; 398744d92694SMartin K. Petersen } 398844d92694SMartin K. Petersen 398944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 399044d92694SMartin K. Petersen 3991fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3992fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 399344d92694SMartin K. Petersen { 3994c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3995c2248fc9SDouglas Gilbert u64 lba; 3996c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 399744d92694SMartin K. Petersen int ret; 399887c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 399944d92694SMartin K. Petersen 4000c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4001c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 400244d92694SMartin K. Petersen 400344d92694SMartin K. Petersen if (alloc_len < 24) 400444d92694SMartin K. Petersen return 0; 400544d92694SMartin K. Petersen 40069447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 400744d92694SMartin K. Petersen if (ret) 400844d92694SMartin K. Petersen return ret; 400944d92694SMartin K. Petersen 4010b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4011b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4012b6ff8ca7SDouglas Gilbert 401387c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4014b6ff8ca7SDouglas Gilbert } else { 4015c2248fc9SDouglas Gilbert mapped = 1; 4016c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4017c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4018c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4019c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4020c2248fc9SDouglas Gilbert else 4021c2248fc9SDouglas Gilbert num = 0xffffffff; 4022c2248fc9SDouglas Gilbert } 402344d92694SMartin K. Petersen 402444d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4025c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4026c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4027c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4028c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 402944d92694SMartin K. Petersen 4030c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 403144d92694SMartin K. Petersen } 403244d92694SMartin K. Petersen 403380c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 403480c49563SDouglas Gilbert struct sdebug_dev_info *devip) 403580c49563SDouglas Gilbert { 40364f2c8bf6SDouglas Gilbert int res = 0; 403780c49563SDouglas Gilbert u64 lba; 403880c49563SDouglas Gilbert u32 num_blocks; 403980c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 404080c49563SDouglas Gilbert 404180c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 404280c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 404380c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 404480c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 404580c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 404680c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 404780c49563SDouglas Gilbert } 404880c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 404980c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 405080c49563SDouglas Gilbert return check_condition_result; 405180c49563SDouglas Gilbert } 40524f2c8bf6SDouglas Gilbert if (!write_since_sync || cmd[1] & 0x2) 40534f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 40544f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 40554f2c8bf6SDouglas Gilbert write_since_sync = false; 40564f2c8bf6SDouglas Gilbert return res; 405780c49563SDouglas Gilbert } 405880c49563SDouglas Gilbert 4059ed9f3e25SDouglas Gilbert /* 4060ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4061ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4062ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4063ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4064ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4065ed9f3e25SDouglas Gilbert */ 4066ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4067ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4068ed9f3e25SDouglas Gilbert { 4069ed9f3e25SDouglas Gilbert int res = 0; 4070ed9f3e25SDouglas Gilbert u64 lba; 4071ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4072ed9f3e25SDouglas Gilbert u32 nblks; 4073ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4074b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4075b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4076b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4077ed9f3e25SDouglas Gilbert 4078ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4079ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4080ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4081ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4082ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4083ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4084ed9f3e25SDouglas Gilbert } 4085ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4086ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4087ed9f3e25SDouglas Gilbert return check_condition_result; 4088ed9f3e25SDouglas Gilbert } 4089ed9f3e25SDouglas Gilbert if (!fsp) 4090ed9f3e25SDouglas Gilbert goto fini; 4091ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4092ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4093ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4094ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4095ed9f3e25SDouglas Gilbert 4096ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 4097ed9f3e25SDouglas Gilbert read_lock(macc_lckp); 4098ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4099ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4100ed9f3e25SDouglas Gilbert if (rest) 4101ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 4102ed9f3e25SDouglas Gilbert read_unlock(macc_lckp); 4103ed9f3e25SDouglas Gilbert fini: 4104ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4105ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4106ed9f3e25SDouglas Gilbert return res | condition_met_result; 4107ed9f3e25SDouglas Gilbert } 4108ed9f3e25SDouglas Gilbert 4109fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4110fb0cc8d1SDouglas Gilbert 41118d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 41128d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 41138d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 41148d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 41158d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 41168d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 41178d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 41188d039e22SDouglas Gilbert */ 41191da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 41201da177e4SLinus Torvalds struct sdebug_dev_info *devip) 41211da177e4SLinus Torvalds { 412201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 41238d039e22SDouglas Gilbert unsigned int alloc_len; 41248d039e22SDouglas Gilbert unsigned char select_report; 41258d039e22SDouglas Gilbert u64 lun; 41268d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4127fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 41288d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 41298d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 41308d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 41318d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4132fb0cc8d1SDouglas Gilbert int k, j, n, res; 4133fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4134fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 41351da177e4SLinus Torvalds 413619c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 41378d039e22SDouglas Gilbert 41388d039e22SDouglas Gilbert select_report = cmd[2]; 41398d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 41408d039e22SDouglas Gilbert 41418d039e22SDouglas Gilbert if (alloc_len < 4) { 41428d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 41438d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 41441da177e4SLinus Torvalds return check_condition_result; 41451da177e4SLinus Torvalds } 41468d039e22SDouglas Gilbert 41478d039e22SDouglas Gilbert switch (select_report) { 41488d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4149773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 41508d039e22SDouglas Gilbert wlun_cnt = 0; 41518d039e22SDouglas Gilbert break; 41528d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4153c65b1445SDouglas Gilbert lun_cnt = 0; 41548d039e22SDouglas Gilbert wlun_cnt = 1; 41558d039e22SDouglas Gilbert break; 41568d039e22SDouglas Gilbert case 2: /* all LUNs */ 41578d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 41588d039e22SDouglas Gilbert wlun_cnt = 1; 41598d039e22SDouglas Gilbert break; 41608d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 41618d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 41628d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 41638d039e22SDouglas Gilbert default: 41648d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 41658d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 41668d039e22SDouglas Gilbert return check_condition_result; 41678d039e22SDouglas Gilbert } 41688d039e22SDouglas Gilbert 41698d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4170c65b1445SDouglas Gilbert --lun_cnt; 41718d039e22SDouglas Gilbert 41728d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4173fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4174fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 41758d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 41768d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 41778d039e22SDouglas Gilbert 4178fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 41798d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4180fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4181fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4182fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4183fb0cc8d1SDouglas Gilbert if (k == 0) { 4184fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4185fb0cc8d1SDouglas Gilbert ++lun_p; 4186fb0cc8d1SDouglas Gilbert j = 1; 4187fb0cc8d1SDouglas Gilbert } 4188fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4189fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4190fb0cc8d1SDouglas Gilbert break; 4191fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4192fb0cc8d1SDouglas Gilbert } 4193fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4194fb0cc8d1SDouglas Gilbert break; 4195fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4196fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4197fb0cc8d1SDouglas Gilbert if (res) 4198fb0cc8d1SDouglas Gilbert return res; 4199fb0cc8d1SDouglas Gilbert off_rsp += n; 4200fb0cc8d1SDouglas Gilbert } 4201fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4202fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4203fb0cc8d1SDouglas Gilbert ++j; 4204fb0cc8d1SDouglas Gilbert } 4205fb0cc8d1SDouglas Gilbert if (j > 0) 4206fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 42078d039e22SDouglas Gilbert return res; 42081da177e4SLinus Torvalds } 42091da177e4SLinus Torvalds 4210c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4211c3e2fe92SDouglas Gilbert { 4212c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4213c3e2fe92SDouglas Gilbert u8 bytchk; 4214c3e2fe92SDouglas Gilbert int ret, j; 4215c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4216c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4217c3e2fe92SDouglas Gilbert u64 lba; 4218c3e2fe92SDouglas Gilbert u8 *arr; 4219c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4220b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4221b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4222c3e2fe92SDouglas Gilbert 4223c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4224c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4225c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4226c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4227c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4228c3e2fe92SDouglas Gilbert return check_condition_result; 4229c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4230c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4231c3e2fe92SDouglas Gilbert } 4232c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4233c3e2fe92SDouglas Gilbert case VERIFY_16: 4234c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4235c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4236c3e2fe92SDouglas Gilbert break; 4237c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4238c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4239c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4240c3e2fe92SDouglas Gilbert break; 4241c3e2fe92SDouglas Gilbert default: 4242c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4243c3e2fe92SDouglas Gilbert return check_condition_result; 4244c3e2fe92SDouglas Gilbert } 4245c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4246c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4247c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4248c3e2fe92SDouglas Gilbert if (ret) 4249c3e2fe92SDouglas Gilbert return ret; 4250c3e2fe92SDouglas Gilbert 4251c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4252c3e2fe92SDouglas Gilbert if (!arr) { 4253c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4254c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4255c3e2fe92SDouglas Gilbert return check_condition_result; 4256c3e2fe92SDouglas Gilbert } 4257c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 425867da413fSDouglas Gilbert read_lock(macc_lckp); 4259c3e2fe92SDouglas Gilbert 4260c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4261c3e2fe92SDouglas Gilbert if (ret == -1) { 4262c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4263c3e2fe92SDouglas Gilbert goto cleanup; 4264c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4265c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4266c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4267c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4268c3e2fe92SDouglas Gilbert } 4269c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4270c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4271c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4272c3e2fe92SDouglas Gilbert } 4273c3e2fe92SDouglas Gilbert ret = 0; 4274c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4275c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4276c3e2fe92SDouglas Gilbert ret = check_condition_result; 4277c3e2fe92SDouglas Gilbert goto cleanup; 4278c3e2fe92SDouglas Gilbert } 4279c3e2fe92SDouglas Gilbert cleanup: 428067da413fSDouglas Gilbert read_unlock(macc_lckp); 4281c3e2fe92SDouglas Gilbert kfree(arr); 4282c3e2fe92SDouglas Gilbert return ret; 4283c3e2fe92SDouglas Gilbert } 4284c3e2fe92SDouglas Gilbert 4285f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4286f0d1cf93SDouglas Gilbert 4287f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */ 4288f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4289f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4290f0d1cf93SDouglas Gilbert { 4291f0d1cf93SDouglas Gilbert unsigned int i, max_zones, rep_max_zones, nrz = 0; 4292f0d1cf93SDouglas Gilbert int ret = 0; 4293f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4294f0d1cf93SDouglas Gilbert bool partial; 4295f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4296f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4297f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4298f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4299b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4300f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4301f0d1cf93SDouglas Gilbert 4302f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4303f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4304f0d1cf93SDouglas Gilbert return check_condition_result; 4305f0d1cf93SDouglas Gilbert } 4306f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4307f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 4308f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4309f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4310f0d1cf93SDouglas Gilbert 4311f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4312f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4313f0d1cf93SDouglas Gilbert return check_condition_result; 4314f0d1cf93SDouglas Gilbert } 4315f0d1cf93SDouglas Gilbert 4316108e36f0SDamien Le Moal max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift); 4317f0d1cf93SDouglas Gilbert rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), 4318f0d1cf93SDouglas Gilbert max_zones); 4319f0d1cf93SDouglas Gilbert 4320f0d1cf93SDouglas Gilbert arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC); 4321f0d1cf93SDouglas Gilbert if (!arr) { 4322f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4323f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4324f0d1cf93SDouglas Gilbert return check_condition_result; 4325f0d1cf93SDouglas Gilbert } 4326f0d1cf93SDouglas Gilbert 4327f0d1cf93SDouglas Gilbert read_lock(macc_lckp); 4328f0d1cf93SDouglas Gilbert 4329f0d1cf93SDouglas Gilbert desc = arr + 64; 4330f0d1cf93SDouglas Gilbert for (i = 0; i < max_zones; i++) { 4331f0d1cf93SDouglas Gilbert lba = zs_lba + devip->zsize * i; 4332f0d1cf93SDouglas Gilbert if (lba > sdebug_capacity) 4333f0d1cf93SDouglas Gilbert break; 4334f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4335f0d1cf93SDouglas Gilbert switch (rep_opts) { 4336f0d1cf93SDouglas Gilbert case 0x00: 4337f0d1cf93SDouglas Gilbert /* All zones */ 4338f0d1cf93SDouglas Gilbert break; 4339f0d1cf93SDouglas Gilbert case 0x01: 4340f0d1cf93SDouglas Gilbert /* Empty zones */ 4341f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4342f0d1cf93SDouglas Gilbert continue; 4343f0d1cf93SDouglas Gilbert break; 4344f0d1cf93SDouglas Gilbert case 0x02: 4345f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4346f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4347f0d1cf93SDouglas Gilbert continue; 4348f0d1cf93SDouglas Gilbert break; 4349f0d1cf93SDouglas Gilbert case 0x03: 4350f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4351f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4352f0d1cf93SDouglas Gilbert continue; 4353f0d1cf93SDouglas Gilbert break; 4354f0d1cf93SDouglas Gilbert case 0x04: 4355f0d1cf93SDouglas Gilbert /* Closed zones */ 4356f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4357f0d1cf93SDouglas Gilbert continue; 4358f0d1cf93SDouglas Gilbert break; 4359f0d1cf93SDouglas Gilbert case 0x05: 4360f0d1cf93SDouglas Gilbert /* Full zones */ 4361f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4362f0d1cf93SDouglas Gilbert continue; 4363f0d1cf93SDouglas Gilbert break; 4364f0d1cf93SDouglas Gilbert case 0x06: 4365f0d1cf93SDouglas Gilbert case 0x07: 4366f0d1cf93SDouglas Gilbert case 0x10: 4367f0d1cf93SDouglas Gilbert /* 436864e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 436964e14eceSDamien Le Moal * not emulated: no zones to report; 4370f0d1cf93SDouglas Gilbert */ 4371f0d1cf93SDouglas Gilbert continue; 437264e14eceSDamien Le Moal case 0x11: 437364e14eceSDamien Le Moal /* non-seq-resource set */ 437464e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 437564e14eceSDamien Le Moal continue; 437664e14eceSDamien Le Moal break; 4377f0d1cf93SDouglas Gilbert case 0x3f: 4378f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 4379f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp)) 4380f0d1cf93SDouglas Gilbert continue; 4381f0d1cf93SDouglas Gilbert break; 4382f0d1cf93SDouglas Gilbert default: 4383f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4384f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4385f0d1cf93SDouglas Gilbert ret = check_condition_result; 4386f0d1cf93SDouglas Gilbert goto fini; 4387f0d1cf93SDouglas Gilbert } 4388f0d1cf93SDouglas Gilbert 4389f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4390f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 439164e14eceSDamien Le Moal desc[0] = zsp->z_type; 4392f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 439364e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 439464e14eceSDamien Le Moal desc[1] |= 1 << 1; 4395f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4396f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4397f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4398f0d1cf93SDouglas Gilbert desc += 64; 4399f0d1cf93SDouglas Gilbert } 4400f0d1cf93SDouglas Gilbert 4401f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4402f0d1cf93SDouglas Gilbert break; 4403f0d1cf93SDouglas Gilbert 4404f0d1cf93SDouglas Gilbert nrz++; 4405f0d1cf93SDouglas Gilbert } 4406f0d1cf93SDouglas Gilbert 4407f0d1cf93SDouglas Gilbert /* Report header */ 4408f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 4409f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 4410f0d1cf93SDouglas Gilbert 4411f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 4412f0d1cf93SDouglas Gilbert ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len)); 4413f0d1cf93SDouglas Gilbert 4414f0d1cf93SDouglas Gilbert fini: 4415f0d1cf93SDouglas Gilbert read_unlock(macc_lckp); 4416f0d1cf93SDouglas Gilbert kfree(arr); 4417f0d1cf93SDouglas Gilbert return ret; 4418f0d1cf93SDouglas Gilbert } 4419f0d1cf93SDouglas Gilbert 4420f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4421f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4422f0d1cf93SDouglas Gilbert { 4423f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4424f0d1cf93SDouglas Gilbert unsigned int i; 4425f0d1cf93SDouglas Gilbert 4426f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4427f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4428f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4429f0d1cf93SDouglas Gilbert } 4430f0d1cf93SDouglas Gilbert } 4431f0d1cf93SDouglas Gilbert 4432f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4433f0d1cf93SDouglas Gilbert { 4434f0d1cf93SDouglas Gilbert int res = 0; 4435f0d1cf93SDouglas Gilbert u64 z_id; 4436f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4437f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4438f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4439f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4440b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4441f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4442f0d1cf93SDouglas Gilbert 4443f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4444f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4445f0d1cf93SDouglas Gilbert return check_condition_result; 4446f0d1cf93SDouglas Gilbert } 4447f0d1cf93SDouglas Gilbert 4448f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4449f0d1cf93SDouglas Gilbert 4450f0d1cf93SDouglas Gilbert if (all) { 4451f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4452f0d1cf93SDouglas Gilbert if (devip->max_open && 4453f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4454f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4455f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4456f0d1cf93SDouglas Gilbert res = check_condition_result; 4457f0d1cf93SDouglas Gilbert goto fini; 4458f0d1cf93SDouglas Gilbert } 4459f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4460f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4461f0d1cf93SDouglas Gilbert goto fini; 4462f0d1cf93SDouglas Gilbert } 4463f0d1cf93SDouglas Gilbert 4464f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4465f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4466f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4467f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4468f0d1cf93SDouglas Gilbert res = check_condition_result; 4469f0d1cf93SDouglas Gilbert goto fini; 4470f0d1cf93SDouglas Gilbert } 4471f0d1cf93SDouglas Gilbert 4472f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4473f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4474f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4475f0d1cf93SDouglas Gilbert res = check_condition_result; 4476f0d1cf93SDouglas Gilbert goto fini; 4477f0d1cf93SDouglas Gilbert } 4478f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4479f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4480f0d1cf93SDouglas Gilbert res = check_condition_result; 4481f0d1cf93SDouglas Gilbert goto fini; 4482f0d1cf93SDouglas Gilbert } 4483f0d1cf93SDouglas Gilbert 4484f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4485f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4486f0d1cf93SDouglas Gilbert goto fini; 4487f0d1cf93SDouglas Gilbert 4488f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4489f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4490f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4491f0d1cf93SDouglas Gilbert res = check_condition_result; 4492f0d1cf93SDouglas Gilbert goto fini; 4493f0d1cf93SDouglas Gilbert } 4494f0d1cf93SDouglas Gilbert 4495f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 4496f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4497f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4498f0d1cf93SDouglas Gilbert fini: 4499f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4500f0d1cf93SDouglas Gilbert return res; 4501f0d1cf93SDouglas Gilbert } 4502f0d1cf93SDouglas Gilbert 4503f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4504f0d1cf93SDouglas Gilbert { 4505f0d1cf93SDouglas Gilbert unsigned int i; 4506f0d1cf93SDouglas Gilbert 4507f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4508f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4509f0d1cf93SDouglas Gilbert } 4510f0d1cf93SDouglas Gilbert 4511f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4512f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4513f0d1cf93SDouglas Gilbert { 4514f0d1cf93SDouglas Gilbert int res = 0; 4515f0d1cf93SDouglas Gilbert u64 z_id; 4516f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4517f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4518f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4519b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4520f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4521f0d1cf93SDouglas Gilbert 4522f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4523f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4524f0d1cf93SDouglas Gilbert return check_condition_result; 4525f0d1cf93SDouglas Gilbert } 4526f0d1cf93SDouglas Gilbert 4527f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4528f0d1cf93SDouglas Gilbert 4529f0d1cf93SDouglas Gilbert if (all) { 4530f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4531f0d1cf93SDouglas Gilbert goto fini; 4532f0d1cf93SDouglas Gilbert } 4533f0d1cf93SDouglas Gilbert 4534f0d1cf93SDouglas Gilbert /* Close specified zone */ 4535f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4536f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4537f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4538f0d1cf93SDouglas Gilbert res = check_condition_result; 4539f0d1cf93SDouglas Gilbert goto fini; 4540f0d1cf93SDouglas Gilbert } 4541f0d1cf93SDouglas Gilbert 4542f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4543f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4544f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4545f0d1cf93SDouglas Gilbert res = check_condition_result; 4546f0d1cf93SDouglas Gilbert goto fini; 4547f0d1cf93SDouglas Gilbert } 4548f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4549f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4550f0d1cf93SDouglas Gilbert res = check_condition_result; 4551f0d1cf93SDouglas Gilbert goto fini; 4552f0d1cf93SDouglas Gilbert } 4553f0d1cf93SDouglas Gilbert 4554f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4555f0d1cf93SDouglas Gilbert fini: 4556f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4557f0d1cf93SDouglas Gilbert return res; 4558f0d1cf93SDouglas Gilbert } 4559f0d1cf93SDouglas Gilbert 4560f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4561f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4562f0d1cf93SDouglas Gilbert { 4563f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4564f0d1cf93SDouglas Gilbert 4565f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4566f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4567f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4568f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4569f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4570f0d1cf93SDouglas Gilbert devip->nr_closed--; 4571f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4572f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4573f0d1cf93SDouglas Gilbert } 4574f0d1cf93SDouglas Gilbert } 4575f0d1cf93SDouglas Gilbert 4576f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4577f0d1cf93SDouglas Gilbert { 4578f0d1cf93SDouglas Gilbert unsigned int i; 4579f0d1cf93SDouglas Gilbert 4580f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4581f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4582f0d1cf93SDouglas Gilbert } 4583f0d1cf93SDouglas Gilbert 4584f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4585f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4586f0d1cf93SDouglas Gilbert { 4587f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4588f0d1cf93SDouglas Gilbert int res = 0; 4589f0d1cf93SDouglas Gilbert u64 z_id; 4590f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4591f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4592b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4593f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4594f0d1cf93SDouglas Gilbert 4595f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4596f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4597f0d1cf93SDouglas Gilbert return check_condition_result; 4598f0d1cf93SDouglas Gilbert } 4599f0d1cf93SDouglas Gilbert 4600f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4601f0d1cf93SDouglas Gilbert 4602f0d1cf93SDouglas Gilbert if (all) { 4603f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4604f0d1cf93SDouglas Gilbert goto fini; 4605f0d1cf93SDouglas Gilbert } 4606f0d1cf93SDouglas Gilbert 4607f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4608f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4609f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4610f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4611f0d1cf93SDouglas Gilbert res = check_condition_result; 4612f0d1cf93SDouglas Gilbert goto fini; 4613f0d1cf93SDouglas Gilbert } 4614f0d1cf93SDouglas Gilbert 4615f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4616f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4617f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4618f0d1cf93SDouglas Gilbert res = check_condition_result; 4619f0d1cf93SDouglas Gilbert goto fini; 4620f0d1cf93SDouglas Gilbert } 4621f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4622f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4623f0d1cf93SDouglas Gilbert res = check_condition_result; 4624f0d1cf93SDouglas Gilbert goto fini; 4625f0d1cf93SDouglas Gilbert } 4626f0d1cf93SDouglas Gilbert 4627f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4628f0d1cf93SDouglas Gilbert fini: 4629f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4630f0d1cf93SDouglas Gilbert return res; 4631f0d1cf93SDouglas Gilbert } 4632f0d1cf93SDouglas Gilbert 4633f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4634f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4635f0d1cf93SDouglas Gilbert { 4636f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4637f0d1cf93SDouglas Gilbert 4638f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4639f0d1cf93SDouglas Gilbert return; 4640f0d1cf93SDouglas Gilbert 4641f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4642f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4643f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4644f0d1cf93SDouglas Gilbert 4645f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4646f0d1cf93SDouglas Gilbert devip->nr_closed--; 4647f0d1cf93SDouglas Gilbert 464864e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4649f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4650f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4651f0d1cf93SDouglas Gilbert } 4652f0d1cf93SDouglas Gilbert 4653f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4654f0d1cf93SDouglas Gilbert { 4655f0d1cf93SDouglas Gilbert unsigned int i; 4656f0d1cf93SDouglas Gilbert 4657f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4658f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4659f0d1cf93SDouglas Gilbert } 4660f0d1cf93SDouglas Gilbert 4661f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4662f0d1cf93SDouglas Gilbert { 4663f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4664f0d1cf93SDouglas Gilbert int res = 0; 4665f0d1cf93SDouglas Gilbert u64 z_id; 4666f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4667f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4668b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4669f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4670f0d1cf93SDouglas Gilbert 4671f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4672f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4673f0d1cf93SDouglas Gilbert return check_condition_result; 4674f0d1cf93SDouglas Gilbert } 4675f0d1cf93SDouglas Gilbert 4676f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4677f0d1cf93SDouglas Gilbert 4678f0d1cf93SDouglas Gilbert if (all) { 4679f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4680f0d1cf93SDouglas Gilbert goto fini; 4681f0d1cf93SDouglas Gilbert } 4682f0d1cf93SDouglas Gilbert 4683f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4684f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4685f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4686f0d1cf93SDouglas Gilbert res = check_condition_result; 4687f0d1cf93SDouglas Gilbert goto fini; 4688f0d1cf93SDouglas Gilbert } 4689f0d1cf93SDouglas Gilbert 4690f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4691f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4692f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4693f0d1cf93SDouglas Gilbert res = check_condition_result; 4694f0d1cf93SDouglas Gilbert goto fini; 4695f0d1cf93SDouglas Gilbert } 4696f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4697f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4698f0d1cf93SDouglas Gilbert res = check_condition_result; 4699f0d1cf93SDouglas Gilbert goto fini; 4700f0d1cf93SDouglas Gilbert } 4701f0d1cf93SDouglas Gilbert 4702f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4703f0d1cf93SDouglas Gilbert fini: 4704f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4705f0d1cf93SDouglas Gilbert return res; 4706f0d1cf93SDouglas Gilbert } 4707f0d1cf93SDouglas Gilbert 4708c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4709c4837394SDouglas Gilbert { 4710c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 4711c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 4712c4837394SDouglas Gilbert 4713458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4714458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4715458df78bSBart Van Assche hwq = 0; 4716458df78bSBart Van Assche return sdebug_q_arr + hwq; 4717c4837394SDouglas Gilbert } 4718c4837394SDouglas Gilbert 4719c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4720fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 47211da177e4SLinus Torvalds { 47227382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4723c4837394SDouglas Gilbert int qc_idx; 4724cbf67842SDouglas Gilbert int retiring = 0; 47251da177e4SLinus Torvalds unsigned long iflags; 4726c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4727cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4728cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4729cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 47301da177e4SLinus Torvalds 473110bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 47327382f9d8SDouglas Gilbert if (unlikely(aborted)) 47337382f9d8SDouglas Gilbert sd_dp->aborted = false; 4734c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4735c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4736c4837394SDouglas Gilbert if (sdebug_statistics) { 4737cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4738c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4739c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4740c4837394SDouglas Gilbert } 4741c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4742c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 47431da177e4SLinus Torvalds return; 47441da177e4SLinus Torvalds } 4745c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4746c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4747cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4748b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4749c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4750c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 4751c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 47521da177e4SLinus Torvalds return; 47531da177e4SLinus Torvalds } 4754cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4755f46eb0e9SDouglas Gilbert if (likely(devip)) 4756cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4757cbf67842SDouglas Gilbert else 4758c1287970STomas Winkler pr_err("devip=NULL\n"); 4759f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4760cbf67842SDouglas Gilbert retiring = 1; 4761cbf67842SDouglas Gilbert 4762cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4763c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4764c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4765c1287970STomas Winkler pr_err("Unexpected completion\n"); 4766cbf67842SDouglas Gilbert return; 47671da177e4SLinus Torvalds } 47681da177e4SLinus Torvalds 4769cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4770cbf67842SDouglas Gilbert int k, retval; 4771cbf67842SDouglas Gilbert 4772cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4773c4837394SDouglas Gilbert if (qc_idx >= retval) { 4774c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4775c1287970STomas Winkler pr_err("index %d too large\n", retval); 4776cbf67842SDouglas Gilbert return; 4777cbf67842SDouglas Gilbert } 4778c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4779773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4780cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4781cbf67842SDouglas Gilbert else 4782cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4783cbf67842SDouglas Gilbert } 4784c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 47857382f9d8SDouglas Gilbert if (unlikely(aborted)) { 47867382f9d8SDouglas Gilbert if (sdebug_verbose) 47877382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 47887382f9d8SDouglas Gilbert return; 47897382f9d8SDouglas Gilbert } 4790cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 4791cbf67842SDouglas Gilbert } 4792cbf67842SDouglas Gilbert 4793cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4794fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4795cbf67842SDouglas Gilbert { 4796a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4797a10bc12aSDouglas Gilbert hrt); 4798a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4799cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4800cbf67842SDouglas Gilbert } 48011da177e4SLinus Torvalds 4802a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4803fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4804a10bc12aSDouglas Gilbert { 4805a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4806a10bc12aSDouglas Gilbert ew.work); 4807a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4808a10bc12aSDouglas Gilbert } 4809a10bc12aSDouglas Gilbert 481009ba24c1SDouglas Gilbert static bool got_shared_uuid; 4811bf476433SChristoph Hellwig static uuid_t shared_uuid; 481209ba24c1SDouglas Gilbert 4813f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 4814f0d1cf93SDouglas Gilbert { 4815f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4816f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 4817f0d1cf93SDouglas Gilbert sector_t zstart = 0; 4818f0d1cf93SDouglas Gilbert unsigned int i; 4819f0d1cf93SDouglas Gilbert 4820f0d1cf93SDouglas Gilbert /* 482198e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 482298e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 4823f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 4824f0d1cf93SDouglas Gilbert * created for the device. 4825f0d1cf93SDouglas Gilbert */ 482698e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 4827f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 4828f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4829f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 4830f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 4831f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 4832f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 4833f0d1cf93SDouglas Gilbert return -EINVAL; 4834f0d1cf93SDouglas Gilbert } 4835f0d1cf93SDouglas Gilbert } else { 4836108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 4837108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 4838108e36f0SDamien Le Moal return -EINVAL; 4839108e36f0SDamien Le Moal } 484098e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 4841f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4842f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 4843f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 4844f0d1cf93SDouglas Gilbert return -EINVAL; 4845f0d1cf93SDouglas Gilbert } 4846f0d1cf93SDouglas Gilbert } 4847f0d1cf93SDouglas Gilbert 4848f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 4849f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 4850f0d1cf93SDouglas Gilbert 4851aa8fecf9SDamien Le Moal if (sdeb_zbc_nr_conv >= devip->nr_zones) { 4852aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 4853aa8fecf9SDamien Le Moal return -EINVAL; 4854aa8fecf9SDamien Le Moal } 4855aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 4856aa8fecf9SDamien Le Moal 485764e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 485864e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 4859380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 4860f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 4861f0d1cf93SDouglas Gilbert else 4862380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 486364e14eceSDamien Le Moal } 4864f0d1cf93SDouglas Gilbert 4865f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 4866f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 4867f0d1cf93SDouglas Gilbert if (!devip->zstate) 4868f0d1cf93SDouglas Gilbert return -ENOMEM; 4869f0d1cf93SDouglas Gilbert 4870f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 4871f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 4872f0d1cf93SDouglas Gilbert 4873f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 4874f0d1cf93SDouglas Gilbert 4875aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 487664e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_CNV; 4877f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 4878f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 4879f0d1cf93SDouglas Gilbert } else { 488064e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 488164e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWR; 488264e14eceSDamien Le Moal else 488364e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWP; 4884f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4885f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4886f0d1cf93SDouglas Gilbert } 4887f0d1cf93SDouglas Gilbert 4888f0d1cf93SDouglas Gilbert if (zsp->z_start + devip->zsize < capacity) 4889f0d1cf93SDouglas Gilbert zsp->z_size = devip->zsize; 4890f0d1cf93SDouglas Gilbert else 4891f0d1cf93SDouglas Gilbert zsp->z_size = capacity - zsp->z_start; 4892f0d1cf93SDouglas Gilbert 4893f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 4894f0d1cf93SDouglas Gilbert } 4895f0d1cf93SDouglas Gilbert 4896f0d1cf93SDouglas Gilbert return 0; 4897f0d1cf93SDouglas Gilbert } 4898f0d1cf93SDouglas Gilbert 4899fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 4900fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 49015cb2fc06SFUJITA Tomonori { 49025cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 49035cb2fc06SFUJITA Tomonori 49045cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 49055cb2fc06SFUJITA Tomonori if (devip) { 490609ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 4907bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 490809ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 490909ba24c1SDouglas Gilbert if (got_shared_uuid) 491009ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 491109ba24c1SDouglas Gilbert else { 4912bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 491309ba24c1SDouglas Gilbert got_shared_uuid = true; 491409ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 491509ba24c1SDouglas Gilbert } 491609ba24c1SDouglas Gilbert } 49175cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 4918f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 491964e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 4920f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 4921f0d1cf93SDouglas Gilbert kfree(devip); 4922f0d1cf93SDouglas Gilbert return NULL; 4923f0d1cf93SDouglas Gilbert } 492464e14eceSDamien Le Moal } else { 492564e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 4926f0d1cf93SDouglas Gilbert } 4927f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 49285cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 49295cb2fc06SFUJITA Tomonori } 49305cb2fc06SFUJITA Tomonori return devip; 49315cb2fc06SFUJITA Tomonori } 49325cb2fc06SFUJITA Tomonori 4933f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 49341da177e4SLinus Torvalds { 49351da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 49361da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 4937f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 49381da177e4SLinus Torvalds 4939d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 49401da177e4SLinus Torvalds if (!sdbg_host) { 4941c1287970STomas Winkler pr_err("Host info NULL\n"); 49421da177e4SLinus Torvalds return NULL; 49431da177e4SLinus Torvalds } 49441da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 49451da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 49461da177e4SLinus Torvalds (devip->target == sdev->id) && 49471da177e4SLinus Torvalds (devip->lun == sdev->lun)) 49481da177e4SLinus Torvalds return devip; 49491da177e4SLinus Torvalds else { 49501da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 49511da177e4SLinus Torvalds open_devip = devip; 49521da177e4SLinus Torvalds } 49531da177e4SLinus Torvalds } 49545cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 49555cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 49565cb2fc06SFUJITA Tomonori if (!open_devip) { 4957c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 49581da177e4SLinus Torvalds return NULL; 49591da177e4SLinus Torvalds } 49601da177e4SLinus Torvalds } 4961a75869d1SFUJITA Tomonori 49621da177e4SLinus Torvalds open_devip->channel = sdev->channel; 49631da177e4SLinus Torvalds open_devip->target = sdev->id; 49641da177e4SLinus Torvalds open_devip->lun = sdev->lun; 49651da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 4966cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 4967cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 4968c2248fc9SDouglas Gilbert open_devip->used = true; 49691da177e4SLinus Torvalds return open_devip; 49701da177e4SLinus Torvalds } 49711da177e4SLinus Torvalds 49728dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 49731da177e4SLinus Torvalds { 4974773642d9SDouglas Gilbert if (sdebug_verbose) 4975c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 49768dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 49778dea0d02SFUJITA Tomonori return 0; 49788dea0d02SFUJITA Tomonori } 49791da177e4SLinus Torvalds 49808dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 49818dea0d02SFUJITA Tomonori { 4982f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 4983f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 4984a34c4e98SFUJITA Tomonori 4985773642d9SDouglas Gilbert if (sdebug_verbose) 4986c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 49878dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 4988b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 4989b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 4990b01f6f83SDouglas Gilbert if (devip == NULL) { 4991f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 4992b01f6f83SDouglas Gilbert if (devip == NULL) 49938dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 4994f46eb0e9SDouglas Gilbert } 4995c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 4996773642d9SDouglas Gilbert if (sdebug_no_uld) 499778d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 49989b760fd8SDouglas Gilbert config_cdb_len(sdp); 49998dea0d02SFUJITA Tomonori return 0; 50008dea0d02SFUJITA Tomonori } 50018dea0d02SFUJITA Tomonori 50028dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 50038dea0d02SFUJITA Tomonori { 50048dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 50058dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 50068dea0d02SFUJITA Tomonori 5007773642d9SDouglas Gilbert if (sdebug_verbose) 5008c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 50098dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 50108dea0d02SFUJITA Tomonori if (devip) { 501125985edcSLucas De Marchi /* make this slot available for re-use */ 5012c2248fc9SDouglas Gilbert devip->used = false; 50138dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 50148dea0d02SFUJITA Tomonori } 50158dea0d02SFUJITA Tomonori } 50168dea0d02SFUJITA Tomonori 501710bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 501810bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5019c4837394SDouglas Gilbert { 5020c4837394SDouglas Gilbert if (!sd_dp) 5021c4837394SDouglas Gilbert return; 502210bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5023c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 502410bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5025c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5026c4837394SDouglas Gilbert } 5027c4837394SDouglas Gilbert 5028a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5029a10bc12aSDouglas Gilbert returns false */ 5030a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 50318dea0d02SFUJITA Tomonori { 50328dea0d02SFUJITA Tomonori unsigned long iflags; 5033c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 503410bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5035c4837394SDouglas Gilbert struct sdebug_queue *sqp; 50368dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5037cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5038a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 50398dea0d02SFUJITA Tomonori 5040c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5041c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5042773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5043cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5044cbf67842SDouglas Gilbert if (r_qmax > qmax) 5045cbf67842SDouglas Gilbert qmax = r_qmax; 5046cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5047c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5048c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5049a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5050a10bc12aSDouglas Gilbert continue; 5051c4837394SDouglas Gilbert /* found */ 5052db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5053db525fceSDouglas Gilbert cmnd->device->hostdata; 5054db525fceSDouglas Gilbert if (devip) 5055db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5056db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5057a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 505810bde980SDouglas Gilbert if (sd_dp) { 505910bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 506010bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 506110bde980SDouglas Gilbert } else 506210bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5063c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 506410bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5065c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5066a10bc12aSDouglas Gilbert return true; 50678dea0d02SFUJITA Tomonori } 5068cbf67842SDouglas Gilbert } 5069c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5070c4837394SDouglas Gilbert } 5071a10bc12aSDouglas Gilbert return false; 50728dea0d02SFUJITA Tomonori } 50738dea0d02SFUJITA Tomonori 5074a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 50758dea0d02SFUJITA Tomonori static void stop_all_queued(void) 50768dea0d02SFUJITA Tomonori { 50778dea0d02SFUJITA Tomonori unsigned long iflags; 5078c4837394SDouglas Gilbert int j, k; 507910bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5080c4837394SDouglas Gilbert struct sdebug_queue *sqp; 50818dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5082cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5083a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 50848dea0d02SFUJITA Tomonori 5085c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5086c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5087c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5088c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5089c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5090c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 5091a10bc12aSDouglas Gilbert continue; 5092db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5093db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5094db525fceSDouglas Gilbert if (devip) 5095db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5096db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5097a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 509810bde980SDouglas Gilbert if (sd_dp) { 509910bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 510010bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 510110bde980SDouglas Gilbert } else 510210bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5103c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 510410bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5105c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5106c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 51078dea0d02SFUJITA Tomonori } 51088dea0d02SFUJITA Tomonori } 5109c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5110c4837394SDouglas Gilbert } 5111cbf67842SDouglas Gilbert } 5112cbf67842SDouglas Gilbert 5113cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5114cbf67842SDouglas Gilbert static void free_all_queued(void) 5115cbf67842SDouglas Gilbert { 5116c4837394SDouglas Gilbert int j, k; 5117c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5118cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5119cbf67842SDouglas Gilbert 5120c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5121c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5122c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5123a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5124a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5125cbf67842SDouglas Gilbert } 51261da177e4SLinus Torvalds } 5127c4837394SDouglas Gilbert } 51281da177e4SLinus Torvalds 51291da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 51301da177e4SLinus Torvalds { 5131a10bc12aSDouglas Gilbert bool ok; 5132a10bc12aSDouglas Gilbert 51331da177e4SLinus Torvalds ++num_aborts; 5134cbf67842SDouglas Gilbert if (SCpnt) { 5135a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5136a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5137a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5138a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5139a10bc12aSDouglas Gilbert ok ? "" : " not"); 5140cbf67842SDouglas Gilbert } 51411da177e4SLinus Torvalds return SUCCESS; 51421da177e4SLinus Torvalds } 51431da177e4SLinus Torvalds 51441da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 51451da177e4SLinus Torvalds { 51461da177e4SLinus Torvalds ++num_dev_resets; 5147cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5148cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5149f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5150f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5151cbf67842SDouglas Gilbert 5152773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5153cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 51541da177e4SLinus Torvalds if (devip) 5155cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 51561da177e4SLinus Torvalds } 51571da177e4SLinus Torvalds return SUCCESS; 51581da177e4SLinus Torvalds } 51591da177e4SLinus Torvalds 5160cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5161cbf67842SDouglas Gilbert { 5162cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5163cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5164cbf67842SDouglas Gilbert struct scsi_device *sdp; 5165cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5166cbf67842SDouglas Gilbert int k = 0; 5167cbf67842SDouglas Gilbert 5168cbf67842SDouglas Gilbert ++num_target_resets; 5169cbf67842SDouglas Gilbert if (!SCpnt) 5170cbf67842SDouglas Gilbert goto lie; 5171cbf67842SDouglas Gilbert sdp = SCpnt->device; 5172cbf67842SDouglas Gilbert if (!sdp) 5173cbf67842SDouglas Gilbert goto lie; 5174773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5175cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5176cbf67842SDouglas Gilbert hp = sdp->host; 5177cbf67842SDouglas Gilbert if (!hp) 5178cbf67842SDouglas Gilbert goto lie; 5179cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5180cbf67842SDouglas Gilbert if (sdbg_host) { 5181cbf67842SDouglas Gilbert list_for_each_entry(devip, 5182cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5183cbf67842SDouglas Gilbert dev_list) 5184cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5185cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5186cbf67842SDouglas Gilbert ++k; 5187cbf67842SDouglas Gilbert } 5188cbf67842SDouglas Gilbert } 5189773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5190cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5191cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5192cbf67842SDouglas Gilbert lie: 5193cbf67842SDouglas Gilbert return SUCCESS; 5194cbf67842SDouglas Gilbert } 5195cbf67842SDouglas Gilbert 51961da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 51971da177e4SLinus Torvalds { 51981da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5199cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 52001da177e4SLinus Torvalds struct scsi_device *sdp; 52011da177e4SLinus Torvalds struct Scsi_Host *hp; 5202cbf67842SDouglas Gilbert int k = 0; 52031da177e4SLinus Torvalds 52041da177e4SLinus Torvalds ++num_bus_resets; 5205cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5206cbf67842SDouglas Gilbert goto lie; 5207cbf67842SDouglas Gilbert sdp = SCpnt->device; 5208773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5209cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5210cbf67842SDouglas Gilbert hp = sdp->host; 5211cbf67842SDouglas Gilbert if (hp) { 5212d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 52131da177e4SLinus Torvalds if (sdbg_host) { 5214cbf67842SDouglas Gilbert list_for_each_entry(devip, 52151da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5216cbf67842SDouglas Gilbert dev_list) { 5217cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5218cbf67842SDouglas Gilbert ++k; 52191da177e4SLinus Torvalds } 52201da177e4SLinus Torvalds } 5221cbf67842SDouglas Gilbert } 5222773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5223cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5224cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5225cbf67842SDouglas Gilbert lie: 52261da177e4SLinus Torvalds return SUCCESS; 52271da177e4SLinus Torvalds } 52281da177e4SLinus Torvalds 52291da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 52301da177e4SLinus Torvalds { 52311da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5232cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5233cbf67842SDouglas Gilbert int k = 0; 52341da177e4SLinus Torvalds 52351da177e4SLinus Torvalds ++num_host_resets; 5236773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5237cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 52381da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 52391da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5240cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5241cbf67842SDouglas Gilbert dev_list) { 5242cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5243cbf67842SDouglas Gilbert ++k; 5244cbf67842SDouglas Gilbert } 52451da177e4SLinus Torvalds } 52461da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 52471da177e4SLinus Torvalds stop_all_queued(); 5248773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5249cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5250cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 52511da177e4SLinus Torvalds return SUCCESS; 52521da177e4SLinus Torvalds } 52531da177e4SLinus Torvalds 525487c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 52551da177e4SLinus Torvalds { 52561442f76dSChristoph Hellwig struct msdos_partition *pp; 52571da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 52581da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 52591da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 52601da177e4SLinus Torvalds 52611da177e4SLinus Torvalds /* assume partition table already zeroed */ 5262773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 52631da177e4SLinus Torvalds return; 5264773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5265773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5266c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 52671da177e4SLinus Torvalds } 5268c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 52691da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5270773642d9SDouglas Gilbert / sdebug_num_parts; 52711da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 52721da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5273773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 52741da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 52751da177e4SLinus Torvalds * heads_by_sects; 5276773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5277773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 52781da177e4SLinus Torvalds 52791da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 52801da177e4SLinus Torvalds ramp[511] = 0xAA; 52811442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 52821da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 52831da177e4SLinus Torvalds start_sec = starts[k]; 52841da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 52851da177e4SLinus Torvalds pp->boot_ind = 0; 52861da177e4SLinus Torvalds 52871da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 52881da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 52891da177e4SLinus Torvalds / sdebug_sectors_per; 52901da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 52911da177e4SLinus Torvalds 52921da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 52931da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 52941da177e4SLinus Torvalds / sdebug_sectors_per; 52951da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 52961da177e4SLinus Torvalds 5297150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5298150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 52991da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 53001da177e4SLinus Torvalds } 53011da177e4SLinus Torvalds } 53021da177e4SLinus Torvalds 5303c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 5304c4837394SDouglas Gilbert { 5305c4837394SDouglas Gilbert int j; 5306c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5307c4837394SDouglas Gilbert 5308c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 5309c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 5310c4837394SDouglas Gilbert } 5311c4837394SDouglas Gilbert 5312c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5313c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5314c4837394SDouglas Gilbert */ 5315c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5316c4837394SDouglas Gilbert { 5317c4837394SDouglas Gilbert int count, modulo; 5318c4837394SDouglas Gilbert 5319c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5320c4837394SDouglas Gilbert if (modulo < 2) 5321c4837394SDouglas Gilbert return; 5322c4837394SDouglas Gilbert block_unblock_all_queues(true); 5323c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5324c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5325c4837394SDouglas Gilbert block_unblock_all_queues(false); 5326c4837394SDouglas Gilbert } 5327c4837394SDouglas Gilbert 5328c4837394SDouglas Gilbert static void clear_queue_stats(void) 5329c4837394SDouglas Gilbert { 5330c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5331c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5332c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5333c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5334c4837394SDouglas Gilbert } 5335c4837394SDouglas Gilbert 5336c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 5337c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 5338c4837394SDouglas Gilbert { 5339f9ba7af8SMartin Wilck if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) { 5340f9ba7af8SMartin Wilck if (sdebug_every_nth > 0) 5341f9ba7af8SMartin Wilck sqcp->inj_recovered = sqcp->inj_transport 5342f9ba7af8SMartin Wilck = sqcp->inj_dif 53437382f9d8SDouglas Gilbert = sqcp->inj_dix = sqcp->inj_short 53447382f9d8SDouglas Gilbert = sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0; 5345c4837394SDouglas Gilbert return; 5346f9ba7af8SMartin Wilck } 5347c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 5348c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 5349c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 5350c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 5351c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 53527ee6d1b4SBart Van Assche sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts); 53537382f9d8SDouglas Gilbert sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts); 5354c4837394SDouglas Gilbert } 5355c4837394SDouglas Gilbert 5356a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5357a2aede97SDouglas Gilbert 5358c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5359c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5360c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5361c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5362c4837394SDouglas Gilbert */ 5363fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5364f66b8517SMartin Wilck int scsi_result, 5365f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, 5366f66b8517SMartin Wilck struct sdebug_dev_info *), 5367f66b8517SMartin Wilck int delta_jiff, int ndelay) 53681da177e4SLinus Torvalds { 5369a2aede97SDouglas Gilbert bool new_sd_dp; 5370cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 5371a2aede97SDouglas Gilbert unsigned long iflags; 5372a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5373c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5374c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5375299b6c07STomas Winkler struct scsi_device *sdp; 5376a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 53771da177e4SLinus Torvalds 5378b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5379b01f6f83SDouglas Gilbert if (scsi_result == 0) 5380f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5381f46eb0e9SDouglas Gilbert goto respond_in_thread; 53821da177e4SLinus Torvalds } 5383299b6c07STomas Winkler sdp = cmnd->device; 5384299b6c07STomas Winkler 5385cd62b7daSDouglas Gilbert if (delta_jiff == 0) 5386cd62b7daSDouglas Gilbert goto respond_in_thread; 53871da177e4SLinus Torvalds 5388c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5389c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5390c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5391c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5392c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5393c4837394SDouglas Gilbert } 5394cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5395cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5396cbf67842SDouglas Gilbert inject = 0; 5397f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5398cd62b7daSDouglas Gilbert if (scsi_result) { 5399c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5400cd62b7daSDouglas Gilbert goto respond_in_thread; 5401cd62b7daSDouglas Gilbert } else 5402cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5403c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5404773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5405f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5406cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5407cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5408773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5409cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5410cbf67842SDouglas Gilbert inject = 1; 5411cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 54121da177e4SLinus Torvalds } 5413cbf67842SDouglas Gilbert } 5414cbf67842SDouglas Gilbert 5415c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5416f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5417c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5418cd62b7daSDouglas Gilbert if (scsi_result) 5419cd62b7daSDouglas Gilbert goto respond_in_thread; 5420773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 5421cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5422773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 5423cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5424cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 5425773642d9SDouglas Gilbert __func__, sdebug_max_queue, 5426cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 5427cbf67842SDouglas Gilbert "report: host busy")); 5428cd62b7daSDouglas Gilbert if (scsi_result) 5429cd62b7daSDouglas Gilbert goto respond_in_thread; 5430cd62b7daSDouglas Gilbert else 5431cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 54321da177e4SLinus Torvalds } 543374595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5434cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5435c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 54361da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5437c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5438a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5439c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5440c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 5441c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 544274595c04SDouglas Gilbert if (!sd_dp) { 544310bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 544474595c04SDouglas Gilbert if (!sd_dp) { 544574595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 544674595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 544710bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 544874595c04SDouglas Gilbert } 5449a2aede97SDouglas Gilbert new_sd_dp = true; 5450a2aede97SDouglas Gilbert } else { 5451a2aede97SDouglas Gilbert new_sd_dp = false; 545210bde980SDouglas Gilbert } 5453f66b8517SMartin Wilck 5454a2aede97SDouglas Gilbert if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS) 5455a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5456a2aede97SDouglas Gilbert 5457a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 5458f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5459f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5460f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5461f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5462f66b8517SMartin Wilck } 5463f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5464f66b8517SMartin Wilck cmnd->result = scsi_result; 5465f66b8517SMartin Wilck 5466f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5467f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5468f66b8517SMartin Wilck __func__, cmnd->result); 5469f66b8517SMartin Wilck 547010bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5471b333a819SDouglas Gilbert ktime_t kt; 5472cbf67842SDouglas Gilbert 5473b333a819SDouglas Gilbert if (delta_jiff > 0) { 54740c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 54750c4bc91dSDouglas Gilbert 54760c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 54770c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 54780c4bc91dSDouglas Gilbert } else if (sdebug_random) { 54790c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 54800c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 54810c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 54820c4bc91dSDouglas Gilbert ns <<= 12; 54830c4bc91dSDouglas Gilbert } 54840c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 54850c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 54860c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 54870c4bc91dSDouglas Gilbert (u32)ndelay; 5488a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5489a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5490a2aede97SDouglas Gilbert 5491a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5492a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5493a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5494a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5495a2aede97SDouglas Gilbert if (new_sd_dp) 5496a2aede97SDouglas Gilbert kfree(sd_dp); 5497a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 5498a2aede97SDouglas Gilbert cmnd->scsi_done(cmnd); 5499a2aede97SDouglas Gilbert return 0; 5500a2aede97SDouglas Gilbert } 5501a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5502a2aede97SDouglas Gilbert kt -= d; 5503a2aede97SDouglas Gilbert } 55040c4bc91dSDouglas Gilbert } 550510bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 550610bde980SDouglas Gilbert sd_dp->init_hrt = true; 5507a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5508a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5509c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5510a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5511c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5512c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5513cbf67842SDouglas Gilbert } 5514c4837394SDouglas Gilbert if (sdebug_statistics) 5515c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 551610bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_HRT; 5517a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5518c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 5519c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 552010bde980SDouglas Gilbert if (!sd_dp->init_wq) { 552110bde980SDouglas Gilbert sd_dp->init_wq = true; 5522a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5523c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5524c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5525a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5526cbf67842SDouglas Gilbert } 5527c4837394SDouglas Gilbert if (sdebug_statistics) 5528c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 552910bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_WQ; 55307382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) 55317382f9d8SDouglas Gilbert sd_dp->aborted = true; 5532a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 55337382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) { 55347382f9d8SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 55357382f9d8SDouglas Gilbert cmnd->request->tag); 55367382f9d8SDouglas Gilbert blk_abort_request(cmnd->request); 55377382f9d8SDouglas Gilbert } 5538cbf67842SDouglas Gilbert } 5539f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 5540f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 5541cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5542cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 5543cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 5544cbf67842SDouglas Gilbert "status: TASK SET FULL"); 55451da177e4SLinus Torvalds return 0; 5546cd62b7daSDouglas Gilbert 5547cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5548f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5549f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5550f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5551cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 5552cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 5553cd62b7daSDouglas Gilbert return 0; 55541da177e4SLinus Torvalds } 5555cbf67842SDouglas Gilbert 555623183910SDouglas Gilbert /* Note: The following macros create attribute files in the 555723183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 555823183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 555923183910SDouglas Gilbert as it can when the corresponding attribute in the 556023183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 556123183910SDouglas Gilbert */ 5562773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5563773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 55649b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5565773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5566c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5567773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5568773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5569773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5570773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5571773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5572773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5573773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5574773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5575e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5576e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5577e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5578e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 55795d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 55805d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 55815d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5582773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5583773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5584773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5585773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5586773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5587773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 55885d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 55895d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 55905d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 55915d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5592773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5593773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 5594773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5595773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5596773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5597773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 55985d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5599773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 560087c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 560187c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5602773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5603773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 56040c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5605773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5606773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5607773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5608c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5609773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5610c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5611773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5612773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5613773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5614773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 561509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 56165d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5617773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 561823183910SDouglas Gilbert S_IRUGO | S_IWUSR); 56199447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5620773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 56215b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 56229267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 5623380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5624aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 562598e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 56261da177e4SLinus Torvalds 56271da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 56281da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 56291da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5630b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 56311da177e4SLinus Torvalds 56325d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 56335b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 56349b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 56350759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5636cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5637c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 56385b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 56395b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5640c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5641beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 564223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 56435b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5644185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5645e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 56469b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 56479b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 56485d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 56495d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 56505d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 56515b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 56525b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 56535b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 56545b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5655c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5656cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5657d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 56585d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5659cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5660c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 566178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 56621da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5663c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 566432c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 566586e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 56665d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 56675d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 56685d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 56691da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 56700c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5671d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5672760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5673ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5674c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5675c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5676c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 56775b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 56785b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 56796014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 56806014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 568109ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 568209ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5683c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 56845b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 56859447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 56865b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 56879267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 5688380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5689aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 569098e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 56911da177e4SLinus Torvalds 5692760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5693760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 56941da177e4SLinus Torvalds 56951da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 56961da177e4SLinus Torvalds { 5697c4837394SDouglas Gilbert int k; 5698c4837394SDouglas Gilbert 5699760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5700760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5701760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5702c4837394SDouglas Gilbert return sdebug_info; 5703760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5704760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5705760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5706760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 57071da177e4SLinus Torvalds return sdebug_info; 57081da177e4SLinus Torvalds } 57091da177e4SLinus Torvalds 5710cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5711fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5712fd32119bSDouglas Gilbert int length) 57131da177e4SLinus Torvalds { 57141da177e4SLinus Torvalds char arr[16]; 5715c8ed555aSAl Viro int opts; 57161da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 57171da177e4SLinus Torvalds 57181da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 57191da177e4SLinus Torvalds return -EACCES; 57201da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 57211da177e4SLinus Torvalds arr[minLen] = '\0'; 5722c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 57231da177e4SLinus Torvalds return -EINVAL; 5724773642d9SDouglas Gilbert sdebug_opts = opts; 5725773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5726773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5727773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5728c4837394SDouglas Gilbert tweak_cmnd_count(); 57291da177e4SLinus Torvalds return length; 57301da177e4SLinus Torvalds } 5731c8ed555aSAl Viro 5732cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5733cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5734cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5735c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5736c8ed555aSAl Viro { 5737c4837394SDouglas Gilbert int f, j, l; 5738c4837394SDouglas Gilbert struct sdebug_queue *sqp; 573987c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5740cbf67842SDouglas Gilbert 5741c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5742c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5743c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5744c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5745c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 5746c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 5747c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 5748c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 5749c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 5750c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 5751c4837394SDouglas Gilbert num_aborts); 5752c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 5753c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 5754c4837394SDouglas Gilbert num_host_resets); 5755c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 5756c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 5757458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 5758458df78bSBart Van Assche sdebug_statistics); 5759c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 5760c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 5761c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 5762c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 5763c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 5764cbf67842SDouglas Gilbert 5765c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 5766c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5767c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 5768c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 5769773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 5770c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 5771c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 5772c4837394SDouglas Gilbert "first,last bits", f, l); 5773c4837394SDouglas Gilbert } 5774cbf67842SDouglas Gilbert } 577587c715dcSDouglas Gilbert 577687c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 577787c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 577887c715dcSDouglas Gilbert bool niu; 577987c715dcSDouglas Gilbert int idx; 578087c715dcSDouglas Gilbert unsigned long l_idx; 578187c715dcSDouglas Gilbert struct sdeb_store_info *sip; 578287c715dcSDouglas Gilbert 578387c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 578487c715dcSDouglas Gilbert j = 0; 578587c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 578687c715dcSDouglas Gilbert idx = sdhp->si_idx; 578787c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 578887c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 578987c715dcSDouglas Gilbert ++j; 579087c715dcSDouglas Gilbert } 579187c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 579287c715dcSDouglas Gilbert sdeb_most_recent_idx); 579387c715dcSDouglas Gilbert j = 0; 579487c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 579587c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 579687c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 579787c715dcSDouglas Gilbert idx = (int)l_idx; 579887c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 579987c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 580087c715dcSDouglas Gilbert ++j; 580187c715dcSDouglas Gilbert } 580287c715dcSDouglas Gilbert } 5803c8ed555aSAl Viro return 0; 58041da177e4SLinus Torvalds } 58051da177e4SLinus Torvalds 580682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 58071da177e4SLinus Torvalds { 5808c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 58091da177e4SLinus Torvalds } 5810c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 5811c4837394SDouglas Gilbert * of delay is jiffies. 5812c4837394SDouglas Gilbert */ 581382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 581482069379SAkinobu Mita size_t count) 58151da177e4SLinus Torvalds { 5816c2206098SDouglas Gilbert int jdelay, res; 58171da177e4SLinus Torvalds 5818b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 5819cbf67842SDouglas Gilbert res = count; 5820c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 5821c4837394SDouglas Gilbert int j, k; 5822c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5823cbf67842SDouglas Gilbert 5824c4837394SDouglas Gilbert block_unblock_all_queues(true); 5825c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5826c4837394SDouglas Gilbert ++j, ++sqp) { 5827c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5828c4837394SDouglas Gilbert sdebug_max_queue); 5829c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5830c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5831c4837394SDouglas Gilbert break; 5832c4837394SDouglas Gilbert } 5833c4837394SDouglas Gilbert } 5834c4837394SDouglas Gilbert if (res > 0) { 5835c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 5836773642d9SDouglas Gilbert sdebug_ndelay = 0; 58371da177e4SLinus Torvalds } 5838c4837394SDouglas Gilbert block_unblock_all_queues(false); 5839cbf67842SDouglas Gilbert } 5840cbf67842SDouglas Gilbert return res; 58411da177e4SLinus Torvalds } 58421da177e4SLinus Torvalds return -EINVAL; 58431da177e4SLinus Torvalds } 584482069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 58451da177e4SLinus Torvalds 5846cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 5847cbf67842SDouglas Gilbert { 5848773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 5849cbf67842SDouglas Gilbert } 5850cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 5851c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 5852cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 5853cbf67842SDouglas Gilbert size_t count) 5854cbf67842SDouglas Gilbert { 5855c4837394SDouglas Gilbert int ndelay, res; 5856cbf67842SDouglas Gilbert 5857cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 5858c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 5859cbf67842SDouglas Gilbert res = count; 5860773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 5861c4837394SDouglas Gilbert int j, k; 5862c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5863c4837394SDouglas Gilbert 5864c4837394SDouglas Gilbert block_unblock_all_queues(true); 5865c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5866c4837394SDouglas Gilbert ++j, ++sqp) { 5867c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5868c4837394SDouglas Gilbert sdebug_max_queue); 5869c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5870c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5871c4837394SDouglas Gilbert break; 5872c4837394SDouglas Gilbert } 5873c4837394SDouglas Gilbert } 5874c4837394SDouglas Gilbert if (res > 0) { 5875773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 5876c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 5877c2206098SDouglas Gilbert : DEF_JDELAY; 5878cbf67842SDouglas Gilbert } 5879c4837394SDouglas Gilbert block_unblock_all_queues(false); 5880cbf67842SDouglas Gilbert } 5881cbf67842SDouglas Gilbert return res; 5882cbf67842SDouglas Gilbert } 5883cbf67842SDouglas Gilbert return -EINVAL; 5884cbf67842SDouglas Gilbert } 5885cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 5886cbf67842SDouglas Gilbert 588782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 58881da177e4SLinus Torvalds { 5889773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 58901da177e4SLinus Torvalds } 58911da177e4SLinus Torvalds 589282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 589382069379SAkinobu Mita size_t count) 58941da177e4SLinus Torvalds { 58951da177e4SLinus Torvalds int opts; 58961da177e4SLinus Torvalds char work[20]; 58971da177e4SLinus Torvalds 58989a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 58999a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 59009a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 59011da177e4SLinus Torvalds goto opts_done; 59021da177e4SLinus Torvalds } else { 59039a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 59041da177e4SLinus Torvalds goto opts_done; 59051da177e4SLinus Torvalds } 59061da177e4SLinus Torvalds } 59071da177e4SLinus Torvalds return -EINVAL; 59081da177e4SLinus Torvalds opts_done: 5909773642d9SDouglas Gilbert sdebug_opts = opts; 5910773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5911773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5912c4837394SDouglas Gilbert tweak_cmnd_count(); 59131da177e4SLinus Torvalds return count; 59141da177e4SLinus Torvalds } 591582069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 59161da177e4SLinus Torvalds 591782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 59181da177e4SLinus Torvalds { 5919773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 59201da177e4SLinus Torvalds } 592182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 592282069379SAkinobu Mita size_t count) 59231da177e4SLinus Torvalds { 59241da177e4SLinus Torvalds int n; 59251da177e4SLinus Torvalds 5926f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 5927f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 5928f0d1cf93SDouglas Gilbert return -EINVAL; 5929f0d1cf93SDouglas Gilbert 59301da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5931f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 5932f0d1cf93SDouglas Gilbert return -EINVAL; 5933773642d9SDouglas Gilbert sdebug_ptype = n; 59341da177e4SLinus Torvalds return count; 59351da177e4SLinus Torvalds } 59361da177e4SLinus Torvalds return -EINVAL; 59371da177e4SLinus Torvalds } 593882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 59391da177e4SLinus Torvalds 594082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 59411da177e4SLinus Torvalds { 5942773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 59431da177e4SLinus Torvalds } 594482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 594582069379SAkinobu Mita size_t count) 59461da177e4SLinus Torvalds { 59471da177e4SLinus Torvalds int n; 59481da177e4SLinus Torvalds 59491da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5950773642d9SDouglas Gilbert sdebug_dsense = n; 59511da177e4SLinus Torvalds return count; 59521da177e4SLinus Torvalds } 59531da177e4SLinus Torvalds return -EINVAL; 59541da177e4SLinus Torvalds } 595582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 59561da177e4SLinus Torvalds 595782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 595823183910SDouglas Gilbert { 5959773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 596023183910SDouglas Gilbert } 596182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 596282069379SAkinobu Mita size_t count) 596323183910SDouglas Gilbert { 596487c715dcSDouglas Gilbert int n, idx; 596523183910SDouglas Gilbert 596623183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 596787c715dcSDouglas Gilbert bool want_store = (n == 0); 596887c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 596987c715dcSDouglas Gilbert 5970cbf67842SDouglas Gilbert n = (n > 0); 5971773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 597287c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 597387c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 5974cbf67842SDouglas Gilbert 597587c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 597687c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 597787c715dcSDouglas Gilbert idx = sdebug_add_store(); 597887c715dcSDouglas Gilbert if (idx < 0) 597987c715dcSDouglas Gilbert return idx; 598087c715dcSDouglas Gilbert } else { 598187c715dcSDouglas Gilbert idx = sdeb_first_idx; 598287c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 598387c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 5984cbf67842SDouglas Gilbert } 598587c715dcSDouglas Gilbert /* make all hosts use same store */ 598687c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 598787c715dcSDouglas Gilbert host_list) { 598887c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 598987c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 599087c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 599187c715dcSDouglas Gilbert sdhp->si_idx = idx; 599287c715dcSDouglas Gilbert } 599387c715dcSDouglas Gilbert } 599487c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 599587c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 599687c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 5997cbf67842SDouglas Gilbert } 5998773642d9SDouglas Gilbert sdebug_fake_rw = n; 599923183910SDouglas Gilbert return count; 600023183910SDouglas Gilbert } 600123183910SDouglas Gilbert return -EINVAL; 600223183910SDouglas Gilbert } 600382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 600423183910SDouglas Gilbert 600582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6006c65b1445SDouglas Gilbert { 6007773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6008c65b1445SDouglas Gilbert } 600982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 601082069379SAkinobu Mita size_t count) 6011c65b1445SDouglas Gilbert { 6012c65b1445SDouglas Gilbert int n; 6013c65b1445SDouglas Gilbert 6014c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6015773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6016c65b1445SDouglas Gilbert return count; 6017c65b1445SDouglas Gilbert } 6018c65b1445SDouglas Gilbert return -EINVAL; 6019c65b1445SDouglas Gilbert } 602082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6021c65b1445SDouglas Gilbert 602282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 60231da177e4SLinus Torvalds { 6024773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 60251da177e4SLinus Torvalds } 602682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 602782069379SAkinobu Mita size_t count) 60281da177e4SLinus Torvalds { 60291da177e4SLinus Torvalds int n; 60301da177e4SLinus Torvalds 60311da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6032773642d9SDouglas Gilbert sdebug_num_tgts = n; 60331da177e4SLinus Torvalds sdebug_max_tgts_luns(); 60341da177e4SLinus Torvalds return count; 60351da177e4SLinus Torvalds } 60361da177e4SLinus Torvalds return -EINVAL; 60371da177e4SLinus Torvalds } 603882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 60391da177e4SLinus Torvalds 604082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 60411da177e4SLinus Torvalds { 6042773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 60431da177e4SLinus Torvalds } 604482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 60451da177e4SLinus Torvalds 604687c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 604787c715dcSDouglas Gilbert { 604887c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 604987c715dcSDouglas Gilbert } 605087c715dcSDouglas Gilbert 605187c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 605287c715dcSDouglas Gilbert size_t count) 605387c715dcSDouglas Gilbert { 605487c715dcSDouglas Gilbert bool v; 605587c715dcSDouglas Gilbert 605687c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 605787c715dcSDouglas Gilbert return -EINVAL; 605887c715dcSDouglas Gilbert 605987c715dcSDouglas Gilbert sdebug_per_host_store = v; 606087c715dcSDouglas Gilbert return count; 606187c715dcSDouglas Gilbert } 606287c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 606387c715dcSDouglas Gilbert 606482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 60651da177e4SLinus Torvalds { 6066773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 60671da177e4SLinus Torvalds } 606882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 60691da177e4SLinus Torvalds 607082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 60711da177e4SLinus Torvalds { 6072773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 60731da177e4SLinus Torvalds } 607482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 607582069379SAkinobu Mita size_t count) 60761da177e4SLinus Torvalds { 60771da177e4SLinus Torvalds int nth; 60781da177e4SLinus Torvalds 60791da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 6080773642d9SDouglas Gilbert sdebug_every_nth = nth; 6081c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6082c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6083c4837394SDouglas Gilbert sdebug_statistics = true; 6084c4837394SDouglas Gilbert } 6085c4837394SDouglas Gilbert tweak_cmnd_count(); 60861da177e4SLinus Torvalds return count; 60871da177e4SLinus Torvalds } 60881da177e4SLinus Torvalds return -EINVAL; 60891da177e4SLinus Torvalds } 609082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 60911da177e4SLinus Torvalds 609282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 60931da177e4SLinus Torvalds { 6094773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 60951da177e4SLinus Torvalds } 609682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 609782069379SAkinobu Mita size_t count) 60981da177e4SLinus Torvalds { 60991da177e4SLinus Torvalds int n; 610019c8ead7SEwan D. Milne bool changed; 61011da177e4SLinus Torvalds 61021da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 61038d039e22SDouglas Gilbert if (n > 256) { 61048d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 61058d039e22SDouglas Gilbert return -EINVAL; 61068d039e22SDouglas Gilbert } 6107773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6108773642d9SDouglas Gilbert sdebug_max_luns = n; 61091da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6110773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 611119c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 611219c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 611319c8ead7SEwan D. Milne 611419c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 611519c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 611619c8ead7SEwan D. Milne host_list) { 611719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 611819c8ead7SEwan D. Milne dev_list) { 611919c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 612019c8ead7SEwan D. Milne dp->uas_bm); 612119c8ead7SEwan D. Milne } 612219c8ead7SEwan D. Milne } 612319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 612419c8ead7SEwan D. Milne } 61251da177e4SLinus Torvalds return count; 61261da177e4SLinus Torvalds } 61271da177e4SLinus Torvalds return -EINVAL; 61281da177e4SLinus Torvalds } 612982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 61301da177e4SLinus Torvalds 613182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 613278d4e5a0SDouglas Gilbert { 6133773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 613478d4e5a0SDouglas Gilbert } 6135cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6136cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 613782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 613882069379SAkinobu Mita size_t count) 613978d4e5a0SDouglas Gilbert { 6140c4837394SDouglas Gilbert int j, n, k, a; 6141c4837394SDouglas Gilbert struct sdebug_queue *sqp; 614278d4e5a0SDouglas Gilbert 614378d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6144c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 6145c4837394SDouglas Gilbert block_unblock_all_queues(true); 6146c4837394SDouglas Gilbert k = 0; 6147c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6148c4837394SDouglas Gilbert ++j, ++sqp) { 6149c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6150c4837394SDouglas Gilbert if (a > k) 6151c4837394SDouglas Gilbert k = a; 6152c4837394SDouglas Gilbert } 6153773642d9SDouglas Gilbert sdebug_max_queue = n; 6154c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6155cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6156cbf67842SDouglas Gilbert else if (k >= n) 6157cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6158cbf67842SDouglas Gilbert else 6159cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6160c4837394SDouglas Gilbert block_unblock_all_queues(false); 616178d4e5a0SDouglas Gilbert return count; 616278d4e5a0SDouglas Gilbert } 616378d4e5a0SDouglas Gilbert return -EINVAL; 616478d4e5a0SDouglas Gilbert } 616582069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 616678d4e5a0SDouglas Gilbert 616782069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 616878d4e5a0SDouglas Gilbert { 6169773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 617078d4e5a0SDouglas Gilbert } 617182069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 617278d4e5a0SDouglas Gilbert 617382069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 61741da177e4SLinus Torvalds { 6175773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 61761da177e4SLinus Torvalds } 617782069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 61781da177e4SLinus Torvalds 617982069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6180c65b1445SDouglas Gilbert { 6181773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6182c65b1445SDouglas Gilbert } 618382069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 618482069379SAkinobu Mita size_t count) 6185c65b1445SDouglas Gilbert { 6186c65b1445SDouglas Gilbert int n; 61870d01c5dfSDouglas Gilbert bool changed; 6188c65b1445SDouglas Gilbert 6189f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6190f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6191f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6192f0d1cf93SDouglas Gilbert 6193c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6194773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6195773642d9SDouglas Gilbert sdebug_virtual_gb = n; 619628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 61970d01c5dfSDouglas Gilbert if (changed) { 61980d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 61990d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 620028898873SFUJITA Tomonori 62014bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 62020d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 62030d01c5dfSDouglas Gilbert host_list) { 62040d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 62050d01c5dfSDouglas Gilbert dev_list) { 62060d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 62070d01c5dfSDouglas Gilbert dp->uas_bm); 62080d01c5dfSDouglas Gilbert } 62090d01c5dfSDouglas Gilbert } 62104bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 62110d01c5dfSDouglas Gilbert } 6212c65b1445SDouglas Gilbert return count; 6213c65b1445SDouglas Gilbert } 6214c65b1445SDouglas Gilbert return -EINVAL; 6215c65b1445SDouglas Gilbert } 621682069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6217c65b1445SDouglas Gilbert 621882069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 62191da177e4SLinus Torvalds { 622087c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 622187c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 62221da177e4SLinus Torvalds } 62231da177e4SLinus Torvalds 622482069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 622582069379SAkinobu Mita size_t count) 62261da177e4SLinus Torvalds { 622787c715dcSDouglas Gilbert bool found; 622887c715dcSDouglas Gilbert unsigned long idx; 622987c715dcSDouglas Gilbert struct sdeb_store_info *sip; 623087c715dcSDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 62311da177e4SLinus Torvalds int delta_hosts; 62321da177e4SLinus Torvalds 6233f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 62341da177e4SLinus Torvalds return -EINVAL; 62351da177e4SLinus Torvalds if (delta_hosts > 0) { 62361da177e4SLinus Torvalds do { 623787c715dcSDouglas Gilbert found = false; 623887c715dcSDouglas Gilbert if (want_phs) { 623987c715dcSDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, 624087c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE) { 624187c715dcSDouglas Gilbert sdeb_most_recent_idx = (int)idx; 624287c715dcSDouglas Gilbert found = true; 624387c715dcSDouglas Gilbert break; 624487c715dcSDouglas Gilbert } 624587c715dcSDouglas Gilbert if (found) /* re-use case */ 624687c715dcSDouglas Gilbert sdebug_add_host_helper((int)idx); 624787c715dcSDouglas Gilbert else 624887c715dcSDouglas Gilbert sdebug_do_add_host(true); 624987c715dcSDouglas Gilbert } else { 625087c715dcSDouglas Gilbert sdebug_do_add_host(false); 625187c715dcSDouglas Gilbert } 62521da177e4SLinus Torvalds } while (--delta_hosts); 62531da177e4SLinus Torvalds } else if (delta_hosts < 0) { 62541da177e4SLinus Torvalds do { 625587c715dcSDouglas Gilbert sdebug_do_remove_host(false); 62561da177e4SLinus Torvalds } while (++delta_hosts); 62571da177e4SLinus Torvalds } 62581da177e4SLinus Torvalds return count; 62591da177e4SLinus Torvalds } 626082069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 62611da177e4SLinus Torvalds 626282069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 626323183910SDouglas Gilbert { 6264773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 626523183910SDouglas Gilbert } 626682069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 626782069379SAkinobu Mita size_t count) 626823183910SDouglas Gilbert { 626923183910SDouglas Gilbert int n; 627023183910SDouglas Gilbert 627123183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6272773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 627323183910SDouglas Gilbert return count; 627423183910SDouglas Gilbert } 627523183910SDouglas Gilbert return -EINVAL; 627623183910SDouglas Gilbert } 627782069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 627823183910SDouglas Gilbert 6279c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6280c4837394SDouglas Gilbert { 6281c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6282c4837394SDouglas Gilbert } 6283c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6284c4837394SDouglas Gilbert size_t count) 6285c4837394SDouglas Gilbert { 6286c4837394SDouglas Gilbert int n; 6287c4837394SDouglas Gilbert 6288c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6289c4837394SDouglas Gilbert if (n > 0) 6290c4837394SDouglas Gilbert sdebug_statistics = true; 6291c4837394SDouglas Gilbert else { 6292c4837394SDouglas Gilbert clear_queue_stats(); 6293c4837394SDouglas Gilbert sdebug_statistics = false; 6294c4837394SDouglas Gilbert } 6295c4837394SDouglas Gilbert return count; 6296c4837394SDouglas Gilbert } 6297c4837394SDouglas Gilbert return -EINVAL; 6298c4837394SDouglas Gilbert } 6299c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6300c4837394SDouglas Gilbert 630182069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6302597136abSMartin K. Petersen { 6303773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6304597136abSMartin K. Petersen } 630582069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6306597136abSMartin K. Petersen 6307c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6308c4837394SDouglas Gilbert { 6309c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6310c4837394SDouglas Gilbert } 6311c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6312c4837394SDouglas Gilbert 631382069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6314c6a44287SMartin K. Petersen { 6315773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6316c6a44287SMartin K. Petersen } 631782069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6318c6a44287SMartin K. Petersen 631982069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6320c6a44287SMartin K. Petersen { 6321773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6322c6a44287SMartin K. Petersen } 632382069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6324c6a44287SMartin K. Petersen 632582069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6326c6a44287SMartin K. Petersen { 6327773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6328c6a44287SMartin K. Petersen } 632982069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6330c6a44287SMartin K. Petersen 633182069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6332c6a44287SMartin K. Petersen { 6333773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6334c6a44287SMartin K. Petersen } 633582069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6336c6a44287SMartin K. Petersen 633782069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 633844d92694SMartin K. Petersen { 633987c715dcSDouglas Gilbert ssize_t count = 0; 634044d92694SMartin K. Petersen 63415b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 634244d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 634344d92694SMartin K. Petersen sdebug_store_sectors); 634444d92694SMartin K. Petersen 634587c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 634687c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 634787c715dcSDouglas Gilbert 634887c715dcSDouglas Gilbert if (sip) 6349c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 635087c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 635187c715dcSDouglas Gilbert } 635244d92694SMartin K. Petersen buf[count++] = '\n'; 6353c7badc90STejun Heo buf[count] = '\0'; 635444d92694SMartin K. Petersen 635544d92694SMartin K. Petersen return count; 635644d92694SMartin K. Petersen } 635782069379SAkinobu Mita static DRIVER_ATTR_RO(map); 635844d92694SMartin K. Petersen 63590c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 63600c4bc91dSDouglas Gilbert { 63610c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 63620c4bc91dSDouglas Gilbert } 63630c4bc91dSDouglas Gilbert 63640c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 63650c4bc91dSDouglas Gilbert size_t count) 63660c4bc91dSDouglas Gilbert { 63670c4bc91dSDouglas Gilbert bool v; 63680c4bc91dSDouglas Gilbert 63690c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 63700c4bc91dSDouglas Gilbert return -EINVAL; 63710c4bc91dSDouglas Gilbert 63720c4bc91dSDouglas Gilbert sdebug_random = v; 63730c4bc91dSDouglas Gilbert return count; 63740c4bc91dSDouglas Gilbert } 63750c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 63760c4bc91dSDouglas Gilbert 637782069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6378d986788bSMartin Pitt { 6379773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6380d986788bSMartin Pitt } 638182069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 638282069379SAkinobu Mita size_t count) 6383d986788bSMartin Pitt { 6384d986788bSMartin Pitt int n; 6385d986788bSMartin Pitt 6386d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6387773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6388d986788bSMartin Pitt return count; 6389d986788bSMartin Pitt } 6390d986788bSMartin Pitt return -EINVAL; 6391d986788bSMartin Pitt } 639282069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6393d986788bSMartin Pitt 6394cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6395cbf67842SDouglas Gilbert { 6396773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6397cbf67842SDouglas Gilbert } 6398185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6399cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6400cbf67842SDouglas Gilbert size_t count) 6401cbf67842SDouglas Gilbert { 6402185dd232SDouglas Gilbert int n; 6403cbf67842SDouglas Gilbert 6404cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6405185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6406185dd232SDouglas Gilbert return count; 6407cbf67842SDouglas Gilbert } 6408cbf67842SDouglas Gilbert return -EINVAL; 6409cbf67842SDouglas Gilbert } 6410cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6411cbf67842SDouglas Gilbert 6412c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6413c2248fc9SDouglas Gilbert { 6414773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6415c2248fc9SDouglas Gilbert } 6416c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6417c2248fc9SDouglas Gilbert size_t count) 6418c2248fc9SDouglas Gilbert { 6419c2248fc9SDouglas Gilbert int n; 6420c2248fc9SDouglas Gilbert 6421c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6422773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6423c2248fc9SDouglas Gilbert return count; 6424c2248fc9SDouglas Gilbert } 6425c2248fc9SDouglas Gilbert return -EINVAL; 6426c2248fc9SDouglas Gilbert } 6427c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6428c2248fc9SDouglas Gilbert 642909ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 643009ba24c1SDouglas Gilbert { 643109ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 643209ba24c1SDouglas Gilbert } 643309ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 643409ba24c1SDouglas Gilbert 64359b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 64369b760fd8SDouglas Gilbert { 64379b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 64389b760fd8SDouglas Gilbert } 64399b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 64409b760fd8SDouglas Gilbert size_t count) 64419b760fd8SDouglas Gilbert { 64429b760fd8SDouglas Gilbert int ret, n; 64439b760fd8SDouglas Gilbert 64449b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 64459b760fd8SDouglas Gilbert if (ret) 64469b760fd8SDouglas Gilbert return ret; 64479b760fd8SDouglas Gilbert sdebug_cdb_len = n; 64489b760fd8SDouglas Gilbert all_config_cdb_len(); 64499b760fd8SDouglas Gilbert return count; 64509b760fd8SDouglas Gilbert } 64519b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 64529b760fd8SDouglas Gilbert 64539267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 64549267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 64559267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 64569267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 64579267e0ebSDouglas Gilbert }; 64589267e0ebSDouglas Gilbert 64599267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 64609267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 64619267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 64629267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 64639267e0ebSDouglas Gilbert }; 64649267e0ebSDouglas Gilbert 64659267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 64669267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 64679267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 64689267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 64699267e0ebSDouglas Gilbert }; 64709267e0ebSDouglas Gilbert 64719267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 64729267e0ebSDouglas Gilbert { 64739267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 64749267e0ebSDouglas Gilbert 64759267e0ebSDouglas Gilbert if (res < 0) { 64769267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 64779267e0ebSDouglas Gilbert if (res < 0) { 64789267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 647947742bdeSDan Carpenter if (res < 0) 64809267e0ebSDouglas Gilbert return -EINVAL; 64819267e0ebSDouglas Gilbert } 64829267e0ebSDouglas Gilbert } 64839267e0ebSDouglas Gilbert return res; 64849267e0ebSDouglas Gilbert } 64859267e0ebSDouglas Gilbert 64869267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 64879267e0ebSDouglas Gilbert { 64889267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 64899267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 64909267e0ebSDouglas Gilbert } 64919267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6492cbf67842SDouglas Gilbert 649382069379SAkinobu Mita /* Note: The following array creates attribute files in the 649423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 649523183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 649623183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 649787c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 649823183910SDouglas Gilbert */ 64996ecaff7fSRandy Dunlap 650082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 650182069379SAkinobu Mita &driver_attr_delay.attr, 650282069379SAkinobu Mita &driver_attr_opts.attr, 650382069379SAkinobu Mita &driver_attr_ptype.attr, 650482069379SAkinobu Mita &driver_attr_dsense.attr, 650582069379SAkinobu Mita &driver_attr_fake_rw.attr, 650682069379SAkinobu Mita &driver_attr_no_lun_0.attr, 650782069379SAkinobu Mita &driver_attr_num_tgts.attr, 650882069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 650982069379SAkinobu Mita &driver_attr_num_parts.attr, 651082069379SAkinobu Mita &driver_attr_every_nth.attr, 651182069379SAkinobu Mita &driver_attr_max_luns.attr, 651282069379SAkinobu Mita &driver_attr_max_queue.attr, 651382069379SAkinobu Mita &driver_attr_no_uld.attr, 651482069379SAkinobu Mita &driver_attr_scsi_level.attr, 651582069379SAkinobu Mita &driver_attr_virtual_gb.attr, 651682069379SAkinobu Mita &driver_attr_add_host.attr, 651787c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 651882069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 651982069379SAkinobu Mita &driver_attr_sector_size.attr, 6520c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6521c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 652282069379SAkinobu Mita &driver_attr_dix.attr, 652382069379SAkinobu Mita &driver_attr_dif.attr, 652482069379SAkinobu Mita &driver_attr_guard.attr, 652582069379SAkinobu Mita &driver_attr_ato.attr, 652682069379SAkinobu Mita &driver_attr_map.attr, 65270c4bc91dSDouglas Gilbert &driver_attr_random.attr, 652882069379SAkinobu Mita &driver_attr_removable.attr, 6529cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6530cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6531c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 653209ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 65339b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 65349267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 653582069379SAkinobu Mita NULL, 653682069379SAkinobu Mita }; 653782069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 65381da177e4SLinus Torvalds 653911ddcecaSAkinobu Mita static struct device *pseudo_primary; 65408dea0d02SFUJITA Tomonori 65411da177e4SLinus Torvalds static int __init scsi_debug_init(void) 65421da177e4SLinus Torvalds { 654387c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 65445f2578e5SFUJITA Tomonori unsigned long sz; 654587c715dcSDouglas Gilbert int k, ret, hosts_to_add; 654687c715dcSDouglas Gilbert int idx = -1; 65471da177e4SLinus Torvalds 654887c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 654987c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6550cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6551cbf67842SDouglas Gilbert 6552773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6553c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6554773642d9SDouglas Gilbert sdebug_ndelay = 0; 6555773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6556c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6557cbf67842SDouglas Gilbert 6558773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6559597136abSMartin K. Petersen case 512: 6560597136abSMartin K. Petersen case 1024: 6561597136abSMartin K. Petersen case 2048: 6562597136abSMartin K. Petersen case 4096: 6563597136abSMartin K. Petersen break; 6564597136abSMartin K. Petersen default: 6565773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6566597136abSMartin K. Petersen return -EINVAL; 6567597136abSMartin K. Petersen } 6568597136abSMartin K. Petersen 6569773642d9SDouglas Gilbert switch (sdebug_dif) { 65708475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6571f46eb0e9SDouglas Gilbert break; 65728475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 65738475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 65748475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6575f46eb0e9SDouglas Gilbert have_dif_prot = true; 6576c6a44287SMartin K. Petersen break; 6577c6a44287SMartin K. Petersen 6578c6a44287SMartin K. Petersen default: 6579c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6580c6a44287SMartin K. Petersen return -EINVAL; 6581c6a44287SMartin K. Petersen } 6582c6a44287SMartin K. Petersen 6583aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6584aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6585aa5334c4SMaurizio Lombardi return -EINVAL; 6586aa5334c4SMaurizio Lombardi } 6587aa5334c4SMaurizio Lombardi 6588773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6589c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6590c6a44287SMartin K. Petersen return -EINVAL; 6591c6a44287SMartin K. Petersen } 6592c6a44287SMartin K. Petersen 6593773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6594c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6595c6a44287SMartin K. Petersen return -EINVAL; 6596c6a44287SMartin K. Petersen } 6597c6a44287SMartin K. Petersen 6598773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6599773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6600ea61fca5SMartin K. Petersen return -EINVAL; 6601ea61fca5SMartin K. Petersen } 66028d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 66038d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 66048d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 66058d039e22SDouglas Gilbert } 6606ea61fca5SMartin K. Petersen 6607773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6608773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6609ea61fca5SMartin K. Petersen return -EINVAL; 6610ea61fca5SMartin K. Petersen } 6611ea61fca5SMartin K. Petersen 6612c4837394SDouglas Gilbert if (submit_queues < 1) { 6613c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6614c4837394SDouglas Gilbert return -EINVAL; 6615c4837394SDouglas Gilbert } 6616c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6617c4837394SDouglas Gilbert GFP_KERNEL); 6618c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6619c4837394SDouglas Gilbert return -ENOMEM; 6620c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6621c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6622c4837394SDouglas Gilbert 6623f0d1cf93SDouglas Gilbert /* 66249267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 66259267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 6626f0d1cf93SDouglas Gilbert */ 66279267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 66289267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 66299267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 66309267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 66319267e0ebSDouglas Gilbert if (k < 0) { 66329267e0ebSDouglas Gilbert ret = k; 66339267e0ebSDouglas Gilbert goto free_vm; 66349267e0ebSDouglas Gilbert } 66359267e0ebSDouglas Gilbert sdeb_zbc_model = k; 66369267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 66379267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 663864e14eceSDamien Le Moal case BLK_ZONED_HA: 66399267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 66409267e0ebSDouglas Gilbert break; 66419267e0ebSDouglas Gilbert case BLK_ZONED_HM: 66429267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 66439267e0ebSDouglas Gilbert break; 66449267e0ebSDouglas Gilbert default: 66459267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 66469267e0ebSDouglas Gilbert return -EINVAL; 66479267e0ebSDouglas Gilbert } 66489267e0ebSDouglas Gilbert } 66499267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 6650f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 66519267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 66529267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 66539267e0ebSDouglas Gilbert } 6654f0d1cf93SDouglas Gilbert 66559267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 66569267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 6657773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 6658773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 6659773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 6660773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 666128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 66621da177e4SLinus Torvalds 66631da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 66641da177e4SLinus Torvalds sdebug_heads = 8; 66651da177e4SLinus Torvalds sdebug_sectors_per = 32; 6666773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 66671da177e4SLinus Torvalds sdebug_heads = 64; 6668773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 6669fa785f0aSAndy Shevchenko sdebug_heads = 32; 66701da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 66711da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 66721da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 66731da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 66741da177e4SLinus Torvalds sdebug_heads = 255; 66751da177e4SLinus Torvalds sdebug_sectors_per = 63; 66761da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 66771da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 66781da177e4SLinus Torvalds } 66795b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 6680773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 6681773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 66826014759cSMartin K. Petersen 6683773642d9SDouglas Gilbert sdebug_unmap_max_desc = 6684773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 66856014759cSMartin K. Petersen 6686773642d9SDouglas Gilbert sdebug_unmap_granularity = 6687773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 66886014759cSMartin K. Petersen 6689773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 6690773642d9SDouglas Gilbert sdebug_unmap_granularity <= 6691773642d9SDouglas Gilbert sdebug_unmap_alignment) { 6692c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 6693c4837394SDouglas Gilbert ret = -EINVAL; 669487c715dcSDouglas Gilbert goto free_q_arr; 669544d92694SMartin K. Petersen } 669644d92694SMartin K. Petersen } 669787c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 669887c715dcSDouglas Gilbert if (want_store) { 669987c715dcSDouglas Gilbert idx = sdebug_add_store(); 670087c715dcSDouglas Gilbert if (idx < 0) { 670187c715dcSDouglas Gilbert ret = idx; 670287c715dcSDouglas Gilbert goto free_q_arr; 670387c715dcSDouglas Gilbert } 670444d92694SMartin K. Petersen } 670544d92694SMartin K. Petersen 67069b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 67079b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 6708c1287970STomas Winkler pr_warn("root_device_register() error\n"); 67099b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 67106ecaff7fSRandy Dunlap goto free_vm; 67116ecaff7fSRandy Dunlap } 67126ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 67136ecaff7fSRandy Dunlap if (ret < 0) { 6714c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 67156ecaff7fSRandy Dunlap goto dev_unreg; 67166ecaff7fSRandy Dunlap } 67176ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 67186ecaff7fSRandy Dunlap if (ret < 0) { 6719c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 67206ecaff7fSRandy Dunlap goto bus_unreg; 67216ecaff7fSRandy Dunlap } 67221da177e4SLinus Torvalds 672387c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 6724773642d9SDouglas Gilbert sdebug_add_host = 0; 67251da177e4SLinus Torvalds 672687c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 672787c715dcSDouglas Gilbert if (want_store && k == 0) { 672887c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 672987c715dcSDouglas Gilbert if (ret < 0) { 673087c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 673187c715dcSDouglas Gilbert k, -ret); 673287c715dcSDouglas Gilbert break; 673387c715dcSDouglas Gilbert } 673487c715dcSDouglas Gilbert } else { 673587c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 673687c715dcSDouglas Gilbert sdebug_per_host_store); 673787c715dcSDouglas Gilbert if (ret < 0) { 673887c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 67391da177e4SLinus Torvalds break; 67401da177e4SLinus Torvalds } 67411da177e4SLinus Torvalds } 674287c715dcSDouglas Gilbert } 6743773642d9SDouglas Gilbert if (sdebug_verbose) 674487c715dcSDouglas Gilbert pr_info("built %d host(s)\n", sdebug_num_hosts); 6745c1287970STomas Winkler 67461da177e4SLinus Torvalds return 0; 67476ecaff7fSRandy Dunlap 67486ecaff7fSRandy Dunlap bus_unreg: 67496ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 67506ecaff7fSRandy Dunlap dev_unreg: 67519b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 67526ecaff7fSRandy Dunlap free_vm: 675387c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 6754c4837394SDouglas Gilbert free_q_arr: 6755c4837394SDouglas Gilbert kfree(sdebug_q_arr); 67566ecaff7fSRandy Dunlap return ret; 67571da177e4SLinus Torvalds } 67581da177e4SLinus Torvalds 67591da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 67601da177e4SLinus Torvalds { 676187c715dcSDouglas Gilbert int k = sdebug_num_hosts; 67621da177e4SLinus Torvalds 67631da177e4SLinus Torvalds stop_all_queued(); 67641da177e4SLinus Torvalds for (; k; k--) 676587c715dcSDouglas Gilbert sdebug_do_remove_host(true); 676652ab9768SLuis Henriques free_all_queued(); 67671da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 67681da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 67699b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 67701da177e4SLinus Torvalds 677187c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 677287c715dcSDouglas Gilbert xa_destroy(per_store_ap); 67731da177e4SLinus Torvalds } 67741da177e4SLinus Torvalds 67751da177e4SLinus Torvalds device_initcall(scsi_debug_init); 67761da177e4SLinus Torvalds module_exit(scsi_debug_exit); 67771da177e4SLinus Torvalds 67781da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 67791da177e4SLinus Torvalds { 67801da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 67811da177e4SLinus Torvalds 67821da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 67831da177e4SLinus Torvalds kfree(sdbg_host); 67841da177e4SLinus Torvalds } 67851da177e4SLinus Torvalds 678687c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 678787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 67881da177e4SLinus Torvalds { 678987c715dcSDouglas Gilbert if (idx < 0) 679087c715dcSDouglas Gilbert return; 679187c715dcSDouglas Gilbert if (!sip) { 679287c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 679387c715dcSDouglas Gilbert return; 679487c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 679587c715dcSDouglas Gilbert if (!sip) 679687c715dcSDouglas Gilbert return; 679787c715dcSDouglas Gilbert } 679887c715dcSDouglas Gilbert vfree(sip->map_storep); 679987c715dcSDouglas Gilbert vfree(sip->dif_storep); 680087c715dcSDouglas Gilbert vfree(sip->storep); 680187c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 680287c715dcSDouglas Gilbert kfree(sip); 680387c715dcSDouglas Gilbert } 680487c715dcSDouglas Gilbert 680587c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 680687c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 680787c715dcSDouglas Gilbert { 680887c715dcSDouglas Gilbert unsigned long idx; 680987c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 681087c715dcSDouglas Gilbert 681187c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 681287c715dcSDouglas Gilbert if (apart_from_first) 681387c715dcSDouglas Gilbert apart_from_first = false; 681487c715dcSDouglas Gilbert else 681587c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 681687c715dcSDouglas Gilbert } 681787c715dcSDouglas Gilbert if (apart_from_first) 681887c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 681987c715dcSDouglas Gilbert } 682087c715dcSDouglas Gilbert 682187c715dcSDouglas Gilbert /* 682287c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 682387c715dcSDouglas Gilbert * Limit the number of stores to 65536. 682487c715dcSDouglas Gilbert */ 682587c715dcSDouglas Gilbert static int sdebug_add_store(void) 682687c715dcSDouglas Gilbert { 682787c715dcSDouglas Gilbert int res; 682887c715dcSDouglas Gilbert u32 n_idx; 682987c715dcSDouglas Gilbert unsigned long iflags; 683087c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 683187c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 683287c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 683387c715dcSDouglas Gilbert 683487c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 683587c715dcSDouglas Gilbert if (!sip) 683687c715dcSDouglas Gilbert return -ENOMEM; 683787c715dcSDouglas Gilbert 683887c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 683987c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 684087c715dcSDouglas Gilbert if (unlikely(res < 0)) { 684187c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 684287c715dcSDouglas Gilbert kfree(sip); 684387c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 684487c715dcSDouglas Gilbert return res; 684587c715dcSDouglas Gilbert } 684687c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 684787c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 684887c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 684987c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 685087c715dcSDouglas Gilbert 685187c715dcSDouglas Gilbert res = -ENOMEM; 685287c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 685387c715dcSDouglas Gilbert if (!sip->storep) { 685487c715dcSDouglas Gilbert pr_err("user data oom\n"); 685587c715dcSDouglas Gilbert goto err; 685687c715dcSDouglas Gilbert } 685787c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 685887c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 685987c715dcSDouglas Gilbert 686087c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 686187c715dcSDouglas Gilbert if (sdebug_dix) { 686287c715dcSDouglas Gilbert int dif_size; 686387c715dcSDouglas Gilbert 686487c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 686587c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 686687c715dcSDouglas Gilbert 686787c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 686887c715dcSDouglas Gilbert sip->dif_storep); 686987c715dcSDouglas Gilbert 687087c715dcSDouglas Gilbert if (!sip->dif_storep) { 687187c715dcSDouglas Gilbert pr_err("DIX oom\n"); 687287c715dcSDouglas Gilbert goto err; 687387c715dcSDouglas Gilbert } 687487c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 687587c715dcSDouglas Gilbert } 687687c715dcSDouglas Gilbert /* Logical Block Provisioning */ 687787c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 687887c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 687987c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 688087c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 688187c715dcSDouglas Gilbert 688287c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 688387c715dcSDouglas Gilbert 688487c715dcSDouglas Gilbert if (!sip->map_storep) { 688587c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 688687c715dcSDouglas Gilbert goto err; 688787c715dcSDouglas Gilbert } 688887c715dcSDouglas Gilbert 688987c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 689087c715dcSDouglas Gilbert 689187c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 689287c715dcSDouglas Gilbert if (sdebug_num_parts) 689387c715dcSDouglas Gilbert map_region(sip, 0, 2); 689487c715dcSDouglas Gilbert } 689587c715dcSDouglas Gilbert 689687c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 689787c715dcSDouglas Gilbert return (int)n_idx; 689887c715dcSDouglas Gilbert err: 689987c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 690087c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 690187c715dcSDouglas Gilbert return res; 690287c715dcSDouglas Gilbert } 690387c715dcSDouglas Gilbert 690487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 690587c715dcSDouglas Gilbert { 690687c715dcSDouglas Gilbert int k, devs_per_host, idx; 690787c715dcSDouglas Gilbert int error = -ENOMEM; 69081da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 69098b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 69101da177e4SLinus Torvalds 691124669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 691287c715dcSDouglas Gilbert if (!sdbg_host) 69131da177e4SLinus Torvalds return -ENOMEM; 691487c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 691587c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 691687c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 691787c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 69181da177e4SLinus Torvalds 69191da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 69201da177e4SLinus Torvalds 6921773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 69221da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 69235cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 692487c715dcSDouglas Gilbert if (!sdbg_devinfo) 69251da177e4SLinus Torvalds goto clean; 69261da177e4SLinus Torvalds } 69271da177e4SLinus Torvalds 69281da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 69291da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 69301da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 69311da177e4SLinus Torvalds 69321da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 69339b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 69341da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 693587c715dcSDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 69361da177e4SLinus Torvalds 69371da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 69381da177e4SLinus Torvalds if (error) 69391da177e4SLinus Torvalds goto clean; 69401da177e4SLinus Torvalds 694187c715dcSDouglas Gilbert ++sdebug_num_hosts; 694287c715dcSDouglas Gilbert return 0; 69431da177e4SLinus Torvalds 69441da177e4SLinus Torvalds clean: 69458b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 69468b40228fSFUJITA Tomonori dev_list) { 69471da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 6948f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 69491da177e4SLinus Torvalds kfree(sdbg_devinfo); 69501da177e4SLinus Torvalds } 69511da177e4SLinus Torvalds kfree(sdbg_host); 695287c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 69531da177e4SLinus Torvalds return error; 69541da177e4SLinus Torvalds } 69551da177e4SLinus Torvalds 695687c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 69571da177e4SLinus Torvalds { 695887c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 695987c715dcSDouglas Gilbert 696087c715dcSDouglas Gilbert if (mk_new_store) { 696187c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 696287c715dcSDouglas Gilbert if (ph_idx < 0) 696387c715dcSDouglas Gilbert return ph_idx; 696487c715dcSDouglas Gilbert } 696587c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 696687c715dcSDouglas Gilbert } 696787c715dcSDouglas Gilbert 696887c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 696987c715dcSDouglas Gilbert { 697087c715dcSDouglas Gilbert int idx = -1; 69711da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 697287c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 69731da177e4SLinus Torvalds 69741da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 69751da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 69761da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 69771da177e4SLinus Torvalds struct sdebug_host_info, host_list); 697887c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 69791da177e4SLinus Torvalds } 698087c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 698187c715dcSDouglas Gilbert bool unique = true; 698287c715dcSDouglas Gilbert 698387c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 698487c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 698587c715dcSDouglas Gilbert continue; 698687c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 698787c715dcSDouglas Gilbert unique = false; 698887c715dcSDouglas Gilbert break; 698987c715dcSDouglas Gilbert } 699087c715dcSDouglas Gilbert } 699187c715dcSDouglas Gilbert if (unique) { 699287c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 699387c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 699487c715dcSDouglas Gilbert --sdeb_most_recent_idx; 699587c715dcSDouglas Gilbert } 699687c715dcSDouglas Gilbert } 699787c715dcSDouglas Gilbert if (sdbg_host) 699887c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 69991da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 70001da177e4SLinus Torvalds 70011da177e4SLinus Torvalds if (!sdbg_host) 70021da177e4SLinus Torvalds return; 70031da177e4SLinus Torvalds 70041da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 700587c715dcSDouglas Gilbert --sdebug_num_hosts; 70061da177e4SLinus Torvalds } 70071da177e4SLinus Torvalds 7008fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7009cbf67842SDouglas Gilbert { 7010cbf67842SDouglas Gilbert int num_in_q = 0; 7011cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7012cbf67842SDouglas Gilbert 7013c4837394SDouglas Gilbert block_unblock_all_queues(true); 7014cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7015cbf67842SDouglas Gilbert if (NULL == devip) { 7016c4837394SDouglas Gilbert block_unblock_all_queues(false); 7017cbf67842SDouglas Gilbert return -ENODEV; 7018cbf67842SDouglas Gilbert } 7019cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7020c40ecc12SChristoph Hellwig 7021cbf67842SDouglas Gilbert if (qdepth < 1) 7022cbf67842SDouglas Gilbert qdepth = 1; 7023c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 7024c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 7025c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 7026db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7027cbf67842SDouglas Gilbert 7028773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7029c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7030c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7031cbf67842SDouglas Gilbert } 7032c4837394SDouglas Gilbert block_unblock_all_queues(false); 7033cbf67842SDouglas Gilbert return sdev->queue_depth; 7034cbf67842SDouglas Gilbert } 7035cbf67842SDouglas Gilbert 7036c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7037817fd66bSDouglas Gilbert { 7038c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7039773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7040773642d9SDouglas Gilbert sdebug_every_nth = -1; 7041773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7042c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7043773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7044817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7045c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7046817fd66bSDouglas Gilbert } 7047c4837394SDouglas Gilbert return false; 7048817fd66bSDouglas Gilbert } 7049817fd66bSDouglas Gilbert 70507ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp) 70517ee6d1b4SBart Van Assche { 70527ee6d1b4SBart Van Assche return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) && 70537ee6d1b4SBart Van Assche (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 70547ee6d1b4SBart Van Assche } 70557ee6d1b4SBart Van Assche 7056fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7057fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7058c2248fc9SDouglas Gilbert { 7059c2248fc9SDouglas Gilbert u8 sdeb_i; 7060c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7061c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7062c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7063c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 706487c715dcSDouglas Gilbert 7065c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7066c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7067f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7068c2248fc9SDouglas Gilbert int k, na; 7069c2248fc9SDouglas Gilbert int errsts = 0; 7070c2248fc9SDouglas Gilbert u32 flags; 7071c2248fc9SDouglas Gilbert u16 sa; 7072c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7073c2248fc9SDouglas Gilbert bool has_wlun_rl; 7074c2248fc9SDouglas Gilbert 7075c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 7076c4837394SDouglas Gilbert if (sdebug_statistics) 7077c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 7078f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7079f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7080c2248fc9SDouglas Gilbert char b[120]; 7081c2248fc9SDouglas Gilbert int n, len, sb; 7082c2248fc9SDouglas Gilbert 7083c2248fc9SDouglas Gilbert len = scp->cmd_len; 7084c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7085c2248fc9SDouglas Gilbert if (len > 32) 7086c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7087c2248fc9SDouglas Gilbert else { 7088c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7089c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7090c2248fc9SDouglas Gilbert (u32)cmd[k]); 7091c2248fc9SDouglas Gilbert } 7092458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7093458df78bSBart Van Assche blk_mq_unique_tag(scp->request), b); 7094c2248fc9SDouglas Gilbert } 70957ee6d1b4SBart Van Assche if (fake_host_busy(scp)) 70967ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 709734d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7098f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 7099f46eb0e9SDouglas Gilbert goto err_out; 7100c2248fc9SDouglas Gilbert 7101c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7102c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7103c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7104f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7105f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7106c2248fc9SDouglas Gilbert if (NULL == devip) 7107f46eb0e9SDouglas Gilbert goto err_out; 7108c2248fc9SDouglas Gilbert } 7109c2248fc9SDouglas Gilbert na = oip->num_attached; 7110c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7111c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7112c2248fc9SDouglas Gilbert r_oip = oip; 7113c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7114c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7115c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7116c2248fc9SDouglas Gilbert else 7117c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7118c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7119c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7120c2248fc9SDouglas Gilbert break; 7121c2248fc9SDouglas Gilbert } 7122c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7123c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7124c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7125c2248fc9SDouglas Gilbert break; 7126c2248fc9SDouglas Gilbert } 7127c2248fc9SDouglas Gilbert } 7128c2248fc9SDouglas Gilbert if (k > na) { 7129c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7130c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7131c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7132c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7133c2248fc9SDouglas Gilbert else 7134c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7135c2248fc9SDouglas Gilbert goto check_cond; 7136c2248fc9SDouglas Gilbert } 7137c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7138c2248fc9SDouglas Gilbert flags = oip->flags; 7139f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7140c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7141c2248fc9SDouglas Gilbert goto check_cond; 7142c2248fc9SDouglas Gilbert } 7143f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7144773642d9SDouglas Gilbert if (sdebug_verbose) 7145773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7146773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7147c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7148c2248fc9SDouglas Gilbert goto check_cond; 7149c2248fc9SDouglas Gilbert } 7150f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7151c2248fc9SDouglas Gilbert u8 rem; 7152c2248fc9SDouglas Gilbert int j; 7153c2248fc9SDouglas Gilbert 7154c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7155c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7156c2248fc9SDouglas Gilbert if (rem) { 7157c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7158c2248fc9SDouglas Gilbert if (0x80 & rem) 7159c2248fc9SDouglas Gilbert break; 7160c2248fc9SDouglas Gilbert } 7161c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7162c2248fc9SDouglas Gilbert goto check_cond; 7163c2248fc9SDouglas Gilbert } 7164c2248fc9SDouglas Gilbert } 7165c2248fc9SDouglas Gilbert } 7166f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7167b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7168b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7169f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7170c2248fc9SDouglas Gilbert if (errsts) 7171c2248fc9SDouglas Gilbert goto check_cond; 7172c2248fc9SDouglas Gilbert } 7173c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 7174c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7175773642d9SDouglas Gilbert if (sdebug_verbose) 7176c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 7177c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 7178c2248fc9SDouglas Gilbert "required"); 7179c2248fc9SDouglas Gilbert errsts = check_condition_result; 7180c2248fc9SDouglas Gilbert goto fini; 7181c2248fc9SDouglas Gilbert } 7182773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7183c2248fc9SDouglas Gilbert goto fini; 7184f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7185c4837394SDouglas Gilbert if (fake_timeout(scp)) 7186c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7187c2248fc9SDouglas Gilbert } 7188f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7189f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7190f66b8517SMartin Wilck else 7191f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7192c2248fc9SDouglas Gilbert 7193c2248fc9SDouglas Gilbert fini: 719467da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7195f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 719675aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 719775aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 719880c49563SDouglas Gilbert /* 719975aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 720075aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 720175aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 720275aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 720380c49563SDouglas Gilbert */ 720480c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 72054f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 720680c49563SDouglas Gilbert 72074f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7208f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 720980c49563SDouglas Gilbert } else 7210f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 721110bde980SDouglas Gilbert sdebug_ndelay); 7212c2248fc9SDouglas Gilbert check_cond: 7213f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7214f46eb0e9SDouglas Gilbert err_out: 7215f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7216c2248fc9SDouglas Gilbert } 7217c2248fc9SDouglas Gilbert 72189e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7219c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7220c8ed555aSAl Viro .write_info = scsi_debug_write_info, 72219e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 72229e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 72239e603ca0SFUJITA Tomonori .info = scsi_debug_info, 72249e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 72259e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 72269e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 72279e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7228185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7229cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 72309e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 72319e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7232cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7233cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 72349e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7235c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 72369e603ca0SFUJITA Tomonori .this_id = 7, 723765e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7238cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 72396bb5e6e7SAkinobu Mita .max_sectors = -1U, 724050c2e910SChristoph Hellwig .max_segment_size = -1U, 72419e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7242c40ecc12SChristoph Hellwig .track_queue_depth = 1, 72439e603ca0SFUJITA Tomonori }; 72449e603ca0SFUJITA Tomonori 72451da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 72461da177e4SLinus Torvalds { 72471da177e4SLinus Torvalds int error = 0; 72481da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72491da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7250f46eb0e9SDouglas Gilbert int hprot; 72511da177e4SLinus Torvalds 72521da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 72531da177e4SLinus Torvalds 7254773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 72552a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 72564af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 72574af14d11SChristoph Hellwig 72581da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 72591da177e4SLinus Torvalds if (NULL == hpnt) { 7260c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 72611da177e4SLinus Torvalds error = -ENODEV; 72621da177e4SLinus Torvalds return error; 72631da177e4SLinus Torvalds } 7264c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 72659b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7266c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7267c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7268c4837394SDouglas Gilbert } 7269c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 7270c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 7271c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 72721da177e4SLinus Torvalds 72731da177e4SLinus Torvalds sdbg_host->shost = hpnt; 72741da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7275773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7276773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 72771da177e4SLinus Torvalds else 7278773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7279773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7280f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 72811da177e4SLinus Torvalds 7282f46eb0e9SDouglas Gilbert hprot = 0; 7283c6a44287SMartin K. Petersen 7284773642d9SDouglas Gilbert switch (sdebug_dif) { 7285c6a44287SMartin K. Petersen 72868475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7287f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7288773642d9SDouglas Gilbert if (sdebug_dix) 7289f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7290c6a44287SMartin K. Petersen break; 7291c6a44287SMartin K. Petersen 72928475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7293f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7294773642d9SDouglas Gilbert if (sdebug_dix) 7295f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7296c6a44287SMartin K. Petersen break; 7297c6a44287SMartin K. Petersen 72988475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7299f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7300773642d9SDouglas Gilbert if (sdebug_dix) 7301f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7302c6a44287SMartin K. Petersen break; 7303c6a44287SMartin K. Petersen 7304c6a44287SMartin K. Petersen default: 7305773642d9SDouglas Gilbert if (sdebug_dix) 7306f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7307c6a44287SMartin K. Petersen break; 7308c6a44287SMartin K. Petersen } 7309c6a44287SMartin K. Petersen 7310f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7311c6a44287SMartin K. Petersen 7312f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7313c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7314f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7315f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7316f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7317f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7318f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7319f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7320f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7321c6a44287SMartin K. Petersen 7322773642d9SDouglas Gilbert if (sdebug_guard == 1) 7323c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7324c6a44287SMartin K. Petersen else 7325c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7326c6a44287SMartin K. Petersen 7327773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7328773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7329c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7330c4837394SDouglas Gilbert sdebug_statistics = true; 73311da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 73321da177e4SLinus Torvalds if (error) { 7333c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 73341da177e4SLinus Torvalds error = -ENODEV; 73351da177e4SLinus Torvalds scsi_host_put(hpnt); 733687c715dcSDouglas Gilbert } else { 73371da177e4SLinus Torvalds scsi_scan_host(hpnt); 733887c715dcSDouglas Gilbert } 73391da177e4SLinus Torvalds 73401da177e4SLinus Torvalds return error; 73411da177e4SLinus Torvalds } 73421da177e4SLinus Torvalds 73431da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev) 73441da177e4SLinus Torvalds { 73451da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 73468b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 73471da177e4SLinus Torvalds 73481da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 73491da177e4SLinus Torvalds 73501da177e4SLinus Torvalds if (!sdbg_host) { 7351c1287970STomas Winkler pr_err("Unable to locate host info\n"); 73521da177e4SLinus Torvalds return -ENODEV; 73531da177e4SLinus Torvalds } 73541da177e4SLinus Torvalds 73551da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 73561da177e4SLinus Torvalds 73578b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 73588b40228fSFUJITA Tomonori dev_list) { 73591da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7360f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 73611da177e4SLinus Torvalds kfree(sdbg_devinfo); 73621da177e4SLinus Torvalds } 73631da177e4SLinus Torvalds 73641da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 73651da177e4SLinus Torvalds return 0; 73661da177e4SLinus Torvalds } 73671da177e4SLinus Torvalds 73688dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 73698dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 73701da177e4SLinus Torvalds { 73718dea0d02SFUJITA Tomonori return 1; 73728dea0d02SFUJITA Tomonori } 73731da177e4SLinus Torvalds 73748dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 73758dea0d02SFUJITA Tomonori .name = "pseudo", 73768dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 73778dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 73788dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 737982069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 73808dea0d02SFUJITA Tomonori }; 7381