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 160f0d1cf93SDouglas Gilbert 161b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 162b01f6f83SDouglas Gilbert 163773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 164773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 165773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 166773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 167773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 168773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 169773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 170773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 171773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 172773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 173773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 174773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 175773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 176773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 177773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 178773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1797ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 1807382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT 0x10000 181773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 182773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 183773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 184773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 185773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1867ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1877382f9d8SDouglas Gilbert SDEBUG_OPT_HOST_BUSY | \ 1887382f9d8SDouglas Gilbert SDEBUG_OPT_CMD_ABORT) 1891da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 190fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1911da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 192773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1936f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 194773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1957382f9d8SDouglas Gilbert * - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and 1967382f9d8SDouglas Gilbert * CMD_ABORT 1971da177e4SLinus Torvalds * 1987382f9d8SDouglas Gilbert * When "every_nth" < 0 then after "- every_nth" commands the selected 1997382f9d8SDouglas Gilbert * error will be injected. The error will be injected on every subsequent 2007382f9d8SDouglas Gilbert * command until some other action occurs; for example, the user writing 2017382f9d8SDouglas Gilbert * a new value (other than -1 or 1) to every_nth: 2027382f9d8SDouglas Gilbert * echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth 2031da177e4SLinus Torvalds */ 2041da177e4SLinus Torvalds 205cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 206cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 207cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 208cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 209cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 210cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 211cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 2120d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 21319c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 214acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 215acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 216acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 217cbf67842SDouglas Gilbert 218773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2191da177e4SLinus Torvalds * sector on read commands: */ 2201da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 22132f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2221da177e4SLinus Torvalds 2231da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2241da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2251da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2261da177e4SLinus Torvalds 227c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 228c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 229c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 230c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 231c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 232c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 233c4837394SDouglas Gilbert */ 234c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 235c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 236cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 237cbf67842SDouglas Gilbert 238fd32119bSDouglas Gilbert #define F_D_IN 1 239fd32119bSDouglas Gilbert #define F_D_OUT 2 240fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 241fd32119bSDouglas Gilbert #define F_D_UNKN 8 242fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 243fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 244fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 245fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 246fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 247fd32119bSDouglas Gilbert #define F_INV_OP 0x200 248fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 249fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 2504f2c8bf6SDouglas Gilbert #define F_SSU_DELAY 0x1000 2514f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY 0x2000 252fd32119bSDouglas Gilbert 253fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 25446f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 255fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2564f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 257fd32119bSDouglas Gilbert 258fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 259fd32119bSDouglas Gilbert 260b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 261fd32119bSDouglas Gilbert 26287c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 26387c715dcSDouglas Gilbert 264f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 265f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 266f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 267f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 268f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 269f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 270f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 271f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 272f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 273f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 274f0d1cf93SDouglas Gilbert }; 275f0d1cf93SDouglas Gilbert 276f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 277f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 278f0d1cf93SDouglas Gilbert unsigned int z_size; 279f0d1cf93SDouglas Gilbert sector_t z_start; 280f0d1cf93SDouglas Gilbert sector_t z_wp; 281f0d1cf93SDouglas Gilbert }; 282fd32119bSDouglas Gilbert 283fd32119bSDouglas Gilbert struct sdebug_dev_info { 284fd32119bSDouglas Gilbert struct list_head dev_list; 285fd32119bSDouglas Gilbert unsigned int channel; 286fd32119bSDouglas Gilbert unsigned int target; 287fd32119bSDouglas Gilbert u64 lun; 288bf476433SChristoph Hellwig uuid_t lu_name; 289fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 290fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 291fd32119bSDouglas Gilbert atomic_t num_in_q; 292c4837394SDouglas Gilbert atomic_t stopped; 293fd32119bSDouglas Gilbert bool used; 294f0d1cf93SDouglas Gilbert 295f0d1cf93SDouglas Gilbert /* For ZBC devices */ 296f0d1cf93SDouglas Gilbert unsigned int zsize; 297f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 298f0d1cf93SDouglas Gilbert unsigned int nr_zones; 299f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 300f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 301f0d1cf93SDouglas Gilbert unsigned int nr_closed; 302f0d1cf93SDouglas Gilbert unsigned int max_open; 303f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 304fd32119bSDouglas Gilbert }; 305fd32119bSDouglas Gilbert 306fd32119bSDouglas Gilbert struct sdebug_host_info { 307fd32119bSDouglas Gilbert struct list_head host_list; 30887c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 309fd32119bSDouglas Gilbert struct Scsi_Host *shost; 310fd32119bSDouglas Gilbert struct device dev; 311fd32119bSDouglas Gilbert struct list_head dev_info_list; 312fd32119bSDouglas Gilbert }; 313fd32119bSDouglas Gilbert 31487c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 31587c715dcSDouglas Gilbert struct sdeb_store_info { 31687c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 31787c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 31887c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 31987c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 32087c715dcSDouglas Gilbert }; 32187c715dcSDouglas Gilbert 322fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 323fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 324fd32119bSDouglas Gilbert 32510bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 32610bde980SDouglas Gilbert SDEB_DEFER_WQ = 2}; 32710bde980SDouglas Gilbert 328fd32119bSDouglas Gilbert struct sdebug_defer { 329fd32119bSDouglas Gilbert struct hrtimer hrt; 330fd32119bSDouglas Gilbert struct execute_work ew; 331c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 332c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 333c4837394SDouglas Gilbert int issuing_cpu; 33410bde980SDouglas Gilbert bool init_hrt; 33510bde980SDouglas Gilbert bool init_wq; 3367382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 33710bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 338fd32119bSDouglas Gilbert }; 339fd32119bSDouglas Gilbert 340fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 341c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 342c4837394SDouglas Gilbert * instance indicates this slot is in use. 343c4837394SDouglas Gilbert */ 344fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 345fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 346c4837394SDouglas Gilbert unsigned int inj_recovered:1; 347c4837394SDouglas Gilbert unsigned int inj_transport:1; 348c4837394SDouglas Gilbert unsigned int inj_dif:1; 349c4837394SDouglas Gilbert unsigned int inj_dix:1; 350c4837394SDouglas Gilbert unsigned int inj_short:1; 3517ee6d1b4SBart Van Assche unsigned int inj_host_busy:1; 3527382f9d8SDouglas Gilbert unsigned int inj_cmd_abort:1; 353fd32119bSDouglas Gilbert }; 354fd32119bSDouglas Gilbert 355c4837394SDouglas Gilbert struct sdebug_queue { 356c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 357c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 358c4837394SDouglas Gilbert spinlock_t qc_lock; 359c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 360fd32119bSDouglas Gilbert }; 361fd32119bSDouglas Gilbert 362c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 363c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 364c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 365c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 366c4837394SDouglas Gilbert 367fd32119bSDouglas Gilbert struct opcode_info_t { 368b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 369b01f6f83SDouglas Gilbert /* for terminating element */ 370fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 371fd32119bSDouglas Gilbert u16 sa; /* service action */ 372fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 373fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 374fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3759a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3769a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 377fd32119bSDouglas Gilbert }; 378fd32119bSDouglas Gilbert 379fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 380c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 381c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 382c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 383c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 384c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 385c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 386c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 387c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 388c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 389c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 390c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 391c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 392c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 39346f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 39446f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 395c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 396c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 397c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 398481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 399c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 400c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 401c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 402c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 403c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 404c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 405c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 406c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 407c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 408c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 409c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 410ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 411f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 412f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 413f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 414c2248fc9SDouglas Gilbert }; 415c2248fc9SDouglas Gilbert 416c4837394SDouglas Gilbert 417c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 418c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 419c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 420c2248fc9SDouglas Gilbert 0, 0, 0, 0, 421c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 422c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 423c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 424c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 425c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 426c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 427c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 428c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 429ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 430c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 431c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 432c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 433c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 434c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 435c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 436c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 437fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 438c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 439c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 440c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 441c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 442c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 443c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 444c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 445f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 446f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 44746f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 448c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 449c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 450c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 45146f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 45246f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 453c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 454c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 455c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 456c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 457c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 458c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 460c2248fc9SDouglas Gilbert }; 461c2248fc9SDouglas Gilbert 46280c49563SDouglas Gilbert /* 46380c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 46480c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 46580c49563SDouglas Gilbert * command completion, they can mask their return value with 46680c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 46780c49563SDouglas Gilbert */ 46880c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 46980c49563SDouglas Gilbert 470c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 471c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 472c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 473c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 474c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 475c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 476c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 477c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 478c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 479481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 482c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 483c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 484c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 48538d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 48638d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 487c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 488c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 489c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 49038d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 491acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 49280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 493ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 494f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 495f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 496f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 497f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 498f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 499c2248fc9SDouglas Gilbert 50087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 50187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 50287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 50387c715dcSDouglas Gilbert static int sdebug_add_store(void); 50487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 50587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 50687c715dcSDouglas Gilbert 50746f64e70SDouglas Gilbert /* 50846f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 50946f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 51046f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 51146f64e70SDouglas Gilbert */ 51246f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 513c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 514c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 515c2248fc9SDouglas Gilbert }; 516c2248fc9SDouglas Gilbert 51746f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 518c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 519c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 520c2248fc9SDouglas Gilbert }; 521c2248fc9SDouglas Gilbert 52246f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 52346f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 524b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 525c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 52646f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 527c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 52846f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 529b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 530c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 531c2248fc9SDouglas Gilbert }; 532c2248fc9SDouglas Gilbert 53346f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 53446f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 53546f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 53646f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 53746f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 53846f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 53946f64e70SDouglas Gilbert 0, 0, 0} }, 54046f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 54146f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54246f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 543c2248fc9SDouglas Gilbert }; 544c2248fc9SDouglas Gilbert 545c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 546c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 547c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 548c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 549c3e2fe92SDouglas Gilbert }; 550c3e2fe92SDouglas Gilbert 55146f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 552c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 553c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55446f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 555c2248fc9SDouglas Gilbert }; 556c2248fc9SDouglas Gilbert 55746f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 55846f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 559b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 560c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 561481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 562481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 563481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 564c2248fc9SDouglas Gilbert }; 565c2248fc9SDouglas Gilbert 56646f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 56738d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 568c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 56946f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 57038d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 571c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 57246f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 573c2248fc9SDouglas Gilbert }; 574c2248fc9SDouglas Gilbert 57546f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 57646f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 577c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57846f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 579c2248fc9SDouglas Gilbert }; 580c2248fc9SDouglas Gilbert 58146f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 582c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 583c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 584c2248fc9SDouglas Gilbert }; 585c2248fc9SDouglas Gilbert 58646f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 587c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 588c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 589c2248fc9SDouglas Gilbert }; 590c2248fc9SDouglas Gilbert 59180c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5924f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 59380c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59480c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 59580c49563SDouglas Gilbert }; 59680c49563SDouglas Gilbert 597ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 598ed9f3e25SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | F_M_ACCESS, resp_pre_fetch, NULL, 599ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 600ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 601ed9f3e25SDouglas Gilbert }; 602ed9f3e25SDouglas Gilbert 603f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 604f0d1cf93SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW, resp_close_zone, NULL, 605f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 606f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 607f0d1cf93SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW, resp_finish_zone, NULL, 608f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 609f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 610f0d1cf93SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW, resp_rwp_zone, NULL, 611f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 612f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 613f0d1cf93SDouglas Gilbert }; 614f0d1cf93SDouglas Gilbert 615f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 616f0d1cf93SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN, NULL, NULL, 617f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 618f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 619f0d1cf93SDouglas Gilbert }; 620f0d1cf93SDouglas Gilbert 621c2248fc9SDouglas Gilbert 622c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 623c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 624c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 625ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 626c2248fc9SDouglas Gilbert /* 0 */ 62746f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 628c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 62946f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 630c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 631c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 632c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 63346f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 634c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 635c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 636c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 637c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63846f64e70SDouglas Gilbert /* 5 */ 63946f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 64046f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 64146f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64246f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 64346f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 64446f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64546f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 646c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 647c2248fc9SDouglas Gilbert 0, 0, 0} }, 64846f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 649c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 650c2248fc9SDouglas Gilbert 0, 0} }, 65146f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 65246f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 65346f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 654c2248fc9SDouglas Gilbert /* 10 */ 65546f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 65646f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 65746f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65880c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6594f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 660c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 66146f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 66246f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 66346f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66446f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 665481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 666481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 667481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 66846f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 66946f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 67046f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 67146f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 67246f64e70SDouglas Gilbert /* 15 */ 673c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 674c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 675c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 676c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 677c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 678c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 67946f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 68046f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 68146f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 68246f64e70SDouglas Gilbert 0xff, 0xff} }, 68346f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 68446f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 685c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 686c2248fc9SDouglas Gilbert 0} }, 68746f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 68846f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 689c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 690c2248fc9SDouglas Gilbert 0} }, 691c2248fc9SDouglas Gilbert /* 20 */ 692f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 693f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 694c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 695c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 696c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 697c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 698c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 699c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 70046f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 701b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 70246f64e70SDouglas Gilbert /* 25 */ 703acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 704acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 705acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 70646f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 70746f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 70846f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 70946f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7104f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 71180c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 712b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 71380c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 71446f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 715c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 716b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 717ed9f3e25SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | F_M_ACCESS, 718ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 719ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 720ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 721c2248fc9SDouglas Gilbert 722ed9f3e25SDouglas Gilbert /* 30 */ 723f0d1cf93SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW, 724f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 725f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 726f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 727f0d1cf93SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_D_IN, 728f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 729f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 730f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 731f0d1cf93SDouglas Gilbert /* sentinel */ 732c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 733c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 734c2248fc9SDouglas Gilbert }; 735c2248fc9SDouglas Gilbert 73687c715dcSDouglas Gilbert static int sdebug_num_hosts; 73787c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 738773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7399b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 740c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7419267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 742773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 743773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 744773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 745773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 746773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 747773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 748773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 749773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 750c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 751d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 752d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 753cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 754c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 755773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 756773642d9SDouglas Gilbert static int sdebug_no_uld; 757773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 758773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 759773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 760773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 761773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 76286e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 763b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 764773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 765773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 766773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 767773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 768773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 769773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 770773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 771773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 773773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 776773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 77709ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7780c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 77987c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 780773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 781773642d9SDouglas Gilbert static bool sdebug_clustering; 782773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 783773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 784817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 785773642d9SDouglas Gilbert static bool sdebug_verbose; 786f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7874f2c8bf6SDouglas Gilbert static bool write_since_sync; 788c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7899447b6ceSMartin K. Petersen static bool sdebug_wp; 7909267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 7919267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 7929267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 7931da177e4SLinus Torvalds 794c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 7951da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 7981da177e4SLinus Torvalds may still need them */ 7991da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8001da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8011da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8041da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8051da177e4SLinus Torvalds 80687c715dcSDouglas Gilbert static struct xarray per_store_arr; 80787c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 80887c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 80987c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 81087c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8111da177e4SLinus Torvalds 81244d92694SMartin K. Petersen static unsigned long map_size; 813cbf67842SDouglas Gilbert static int num_aborts; 814cbf67842SDouglas Gilbert static int num_dev_resets; 815cbf67842SDouglas Gilbert static int num_target_resets; 816cbf67842SDouglas Gilbert static int num_bus_resets; 817cbf67842SDouglas Gilbert static int num_host_resets; 818c6a44287SMartin K. Petersen static int dix_writes; 819c6a44287SMartin K. Petersen static int dix_reads; 820c6a44287SMartin K. Petersen static int dif_errors; 8211da177e4SLinus Torvalds 822f0d1cf93SDouglas Gilbert /* ZBC global data */ 823f0d1cf93SDouglas Gilbert static bool sdeb_zbc_in_use; /* true when ptype=TYPE_ZBC [0x14] */ 824f0d1cf93SDouglas Gilbert static const int zbc_zone_size_mb; 825f0d1cf93SDouglas Gilbert static const int zbc_max_open_zones = DEF_ZBC_MAX_OPEN_ZONES; 826f0d1cf93SDouglas Gilbert 827c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 828c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 829fd32119bSDouglas Gilbert 8301da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 83187c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 83287c715dcSDouglas Gilbert 83387c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8341da177e4SLinus Torvalds 835cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 836cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8391da177e4SLinus Torvalds 8401da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8411da177e4SLinus Torvalds .name = sdebug_proc_name, 8421da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8431da177e4SLinus Torvalds }; 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds static const int check_condition_result = 8461da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 8471da177e4SLinus Torvalds 848c6a44287SMartin K. Petersen static const int illegal_condition_result = 849c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 850c6a44287SMartin K. Petersen 851cbf67842SDouglas Gilbert static const int device_qfull_result = 852cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 853cbf67842SDouglas Gilbert 854ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 855ed9f3e25SDouglas Gilbert 856fd32119bSDouglas Gilbert 857760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 858760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 859760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 860760f3b03SDouglas Gilbert */ 861760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 862fd32119bSDouglas Gilbert { 863fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 864fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 865fd32119bSDouglas Gilbert } 866c65b1445SDouglas Gilbert 86787c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 86887c715dcSDouglas Gilbert unsigned long long lba) 86914faa944SAkinobu Mita { 87087c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 87114faa944SAkinobu Mita 87287c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 87387c715dcSDouglas Gilbert if (!sip || !sip->storep) { 87487c715dcSDouglas Gilbert WARN_ON_ONCE(true); 87587c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 87687c715dcSDouglas Gilbert } 87787c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 87814faa944SAkinobu Mita } 87914faa944SAkinobu Mita 88087c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 88187c715dcSDouglas Gilbert sector_t sector) 88214faa944SAkinobu Mita { 88349413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 88414faa944SAkinobu Mita 88587c715dcSDouglas Gilbert return sip->dif_storep + sector; 88614faa944SAkinobu Mita } 88714faa944SAkinobu Mita 8888dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 8898dea0d02SFUJITA Tomonori { 8908dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 8918dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 8928dea0d02SFUJITA Tomonori 8938dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 8948dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 8958dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 8968dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 897773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 898773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 8998dea0d02SFUJITA Tomonori else 900773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 901773642d9SDouglas Gilbert /* sdebug_max_luns; */ 902f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9038dea0d02SFUJITA Tomonori } 9048dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9058dea0d02SFUJITA Tomonori } 9068dea0d02SFUJITA Tomonori 90722017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 90822017ed2SDouglas Gilbert 90922017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 910fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 911fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 91222017ed2SDouglas Gilbert int in_byte, int in_bit) 91322017ed2SDouglas Gilbert { 91422017ed2SDouglas Gilbert unsigned char *sbuff; 91522017ed2SDouglas Gilbert u8 sks[4]; 91622017ed2SDouglas Gilbert int sl, asc; 91722017ed2SDouglas Gilbert 91822017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 91922017ed2SDouglas Gilbert if (!sbuff) { 92022017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 92122017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 92222017ed2SDouglas Gilbert return; 92322017ed2SDouglas Gilbert } 92422017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 92522017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 926773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 92722017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 92822017ed2SDouglas Gilbert sks[0] = 0x80; 92922017ed2SDouglas Gilbert if (c_d) 93022017ed2SDouglas Gilbert sks[0] |= 0x40; 93122017ed2SDouglas Gilbert if (in_bit >= 0) { 93222017ed2SDouglas Gilbert sks[0] |= 0x8; 93322017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 93422017ed2SDouglas Gilbert } 93522017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 936773642d9SDouglas Gilbert if (sdebug_dsense) { 93722017ed2SDouglas Gilbert sl = sbuff[7] + 8; 93822017ed2SDouglas Gilbert sbuff[7] = sl; 93922017ed2SDouglas Gilbert sbuff[sl] = 0x2; 94022017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 94122017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 94222017ed2SDouglas Gilbert } else 94322017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 944773642d9SDouglas Gilbert if (sdebug_verbose) 94522017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 94622017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 94722017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 94822017ed2SDouglas Gilbert } 94922017ed2SDouglas Gilbert 950cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9518dea0d02SFUJITA Tomonori { 9528dea0d02SFUJITA Tomonori unsigned char *sbuff; 9538dea0d02SFUJITA Tomonori 954cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 955cbf67842SDouglas Gilbert if (!sbuff) { 956cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 957cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 958cbf67842SDouglas Gilbert return; 959cbf67842SDouglas Gilbert } 960cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 9618dea0d02SFUJITA Tomonori 962773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 9638dea0d02SFUJITA Tomonori 964773642d9SDouglas Gilbert if (sdebug_verbose) 965cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 966cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 967cbf67842SDouglas Gilbert my_name, key, asc, asq); 9688dea0d02SFUJITA Tomonori } 9691da177e4SLinus Torvalds 970fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 97122017ed2SDouglas Gilbert { 97222017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 97322017ed2SDouglas Gilbert } 97422017ed2SDouglas Gilbert 9756f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9766f4e626fSNathan Chancellor void __user *arg) 9771da177e4SLinus Torvalds { 978773642d9SDouglas Gilbert if (sdebug_verbose) { 979cbf67842SDouglas Gilbert if (0x1261 == cmd) 980cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 981cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 982cbf67842SDouglas Gilbert else if (0x5331 == cmd) 983cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 984cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 985cbf67842SDouglas Gilbert __func__); 986cbf67842SDouglas Gilbert else 987cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 988cbf67842SDouglas Gilbert __func__, cmd); 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds return -EINVAL; 9911da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 9921da177e4SLinus Torvalds } 9931da177e4SLinus Torvalds 9949b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 9959b760fd8SDouglas Gilbert { 9969b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 9979b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 9989b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 9999b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10009b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10019b760fd8SDouglas Gilbert break; 10029b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10039b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10049b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10059b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10069b760fd8SDouglas Gilbert break; 10079b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10089b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10099b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10109b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10119b760fd8SDouglas Gilbert break; 10129b760fd8SDouglas Gilbert case 16: 10139b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10149b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10159b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10169b760fd8SDouglas Gilbert break; 10179b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10189b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10199b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10209b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10219b760fd8SDouglas Gilbert break; 10229b760fd8SDouglas Gilbert default: 10239b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10249b760fd8SDouglas Gilbert sdebug_cdb_len); 10259b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10269b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10279b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10289b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10299b760fd8SDouglas Gilbert break; 10309b760fd8SDouglas Gilbert } 10319b760fd8SDouglas Gilbert } 10329b760fd8SDouglas Gilbert 10339b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10349b760fd8SDouglas Gilbert { 10359b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10369b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10379b760fd8SDouglas Gilbert struct scsi_device *sdev; 10389b760fd8SDouglas Gilbert 10399b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10409b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10419b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10429b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10439b760fd8SDouglas Gilbert config_cdb_len(sdev); 10449b760fd8SDouglas Gilbert } 10459b760fd8SDouglas Gilbert } 10469b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10479b760fd8SDouglas Gilbert } 10489b760fd8SDouglas Gilbert 104919c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 105019c8ead7SEwan D. Milne { 105119c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 105219c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 105319c8ead7SEwan D. Milne 105419c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 105519c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 105619c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 105719c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 105819c8ead7SEwan D. Milne (devip->target == dp->target)) 105919c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 106019c8ead7SEwan D. Milne } 106119c8ead7SEwan D. Milne } 106219c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 106319c8ead7SEwan D. Milne } 106419c8ead7SEwan D. Milne 1065f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10661da177e4SLinus Torvalds { 1067cbf67842SDouglas Gilbert int k; 1068cbf67842SDouglas Gilbert 1069cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1070cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1071cbf67842SDouglas Gilbert const char *cp = NULL; 1072cbf67842SDouglas Gilbert 1073cbf67842SDouglas Gilbert switch (k) { 1074cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1075f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1076f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1077773642d9SDouglas Gilbert if (sdebug_verbose) 1078cbf67842SDouglas Gilbert cp = "power on reset"; 1079cbf67842SDouglas Gilbert break; 1080cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1081f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1082f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1083773642d9SDouglas Gilbert if (sdebug_verbose) 1084cbf67842SDouglas Gilbert cp = "bus reset"; 1085cbf67842SDouglas Gilbert break; 1086cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1087f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1088f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1089773642d9SDouglas Gilbert if (sdebug_verbose) 1090cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1091cbf67842SDouglas Gilbert break; 10920d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1093f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1094f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1095773642d9SDouglas Gilbert if (sdebug_verbose) 10960d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1097f49accf1SEwan D. Milne break; 1098acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1099f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1100b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1101b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1102773642d9SDouglas Gilbert if (sdebug_verbose) 1103acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1104acafd0b9SEwan D. Milne break; 1105acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1106f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1107acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1108acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1109773642d9SDouglas Gilbert if (sdebug_verbose) 1110acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1111acafd0b9SEwan D. Milne break; 111219c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 111319c8ead7SEwan D. Milne /* 111419c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 111519c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 111619c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 111719c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1118773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 111919c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 112019c8ead7SEwan D. Milne */ 1121773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 112219c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1123f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 112419c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 112519c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1126773642d9SDouglas Gilbert if (sdebug_verbose) 112719c8ead7SEwan D. Milne cp = "reported luns data has changed"; 112819c8ead7SEwan D. Milne break; 1129cbf67842SDouglas Gilbert default: 1130773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1131773642d9SDouglas Gilbert if (sdebug_verbose) 1132cbf67842SDouglas Gilbert cp = "unknown"; 1133cbf67842SDouglas Gilbert break; 1134cbf67842SDouglas Gilbert } 1135cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1136773642d9SDouglas Gilbert if (sdebug_verbose) 1137f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1138cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1139cbf67842SDouglas Gilbert my_name, cp); 11401da177e4SLinus Torvalds return check_condition_result; 11411da177e4SLinus Torvalds } 11421da177e4SLinus Torvalds return 0; 11431da177e4SLinus Torvalds } 11441da177e4SLinus Torvalds 1145fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11461da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11471da177e4SLinus Torvalds int arr_len) 11481da177e4SLinus Torvalds { 114921a61829SFUJITA Tomonori int act_len; 1150ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11511da177e4SLinus Torvalds 1152072d0bb3SFUJITA Tomonori if (!sdb->length) 11531da177e4SLinus Torvalds return 0; 1154ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1155773642d9SDouglas Gilbert return DID_ERROR << 16; 115621a61829SFUJITA Tomonori 115721a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 115821a61829SFUJITA Tomonori arr, arr_len); 115942d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 116021a61829SFUJITA Tomonori 11611da177e4SLinus Torvalds return 0; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 1164fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1165fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1166fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1167fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1168fb0cc8d1SDouglas Gilbert */ 1169fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1170fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1171fb0cc8d1SDouglas Gilbert { 11729237f04eSDamien Le Moal unsigned int act_len, n; 1173ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1174fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1175fb0cc8d1SDouglas Gilbert 1176fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1177fb0cc8d1SDouglas Gilbert return 0; 1178ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1179fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1180fb0cc8d1SDouglas Gilbert 1181fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1182fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1183fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 118442d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 118542d387beSBart Van Assche scsi_get_resid(scp)); 11869237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 118787c715dcSDouglas Gilbert scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n)); 1188fb0cc8d1SDouglas Gilbert return 0; 1189fb0cc8d1SDouglas Gilbert } 1190fb0cc8d1SDouglas Gilbert 1191fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1192fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1193fb0cc8d1SDouglas Gilbert */ 11941da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 119521a61829SFUJITA Tomonori int arr_len) 11961da177e4SLinus Torvalds { 119721a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 11981da177e4SLinus Torvalds return 0; 1199ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12001da177e4SLinus Torvalds return -1; 120121a61829SFUJITA Tomonori 120221a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12031da177e4SLinus Torvalds } 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds 1206e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1207e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12089b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12091b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12101b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12111b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12121b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12131da177e4SLinus Torvalds 1214cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1215760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12165a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 121709ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1218bf476433SChristoph Hellwig const uuid_t *lu_name) 12191da177e4SLinus Torvalds { 1220c65b1445SDouglas Gilbert int num, port_a; 1221c65b1445SDouglas Gilbert char b[32]; 12221da177e4SLinus Torvalds 1223c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12241da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12251da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12261da177e4SLinus Torvalds arr[1] = 0x1; 12271da177e4SLinus Torvalds arr[2] = 0x0; 1228e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1229e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12301da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12311da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12321da177e4SLinus Torvalds arr[3] = num; 12331da177e4SLinus Torvalds num += 4; 1234c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 123509ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 123609ba24c1SDouglas Gilbert /* Locally assigned UUID */ 123709ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 123809ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 123909ba24c1SDouglas Gilbert arr[num++] = 0x0; 124009ba24c1SDouglas Gilbert arr[num++] = 0x12; 124109ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 124209ba24c1SDouglas Gilbert arr[num++] = 0x0; 124309ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 124409ba24c1SDouglas Gilbert num += 16; 124509ba24c1SDouglas Gilbert } else { 12461b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1247c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1248c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1249c65b1445SDouglas Gilbert arr[num++] = 0x0; 1250c65b1445SDouglas Gilbert arr[num++] = 0x8; 12511b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1252773642d9SDouglas Gilbert num += 8; 125309ba24c1SDouglas Gilbert } 1254c65b1445SDouglas Gilbert /* Target relative port number */ 1255c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1256c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1257c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1258c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1259c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1260c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1261c65b1445SDouglas Gilbert arr[num++] = 0x0; 1262c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1263c65b1445SDouglas Gilbert } 12641b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1265c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1266c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1267c65b1445SDouglas Gilbert arr[num++] = 0x0; 1268c65b1445SDouglas Gilbert arr[num++] = 0x8; 12691b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1270773642d9SDouglas Gilbert num += 8; 12711b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12725a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12735a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12745a09e398SHannes Reinecke arr[num++] = 0x0; 12755a09e398SHannes Reinecke arr[num++] = 0x4; 12765a09e398SHannes Reinecke arr[num++] = 0; 12775a09e398SHannes Reinecke arr[num++] = 0; 1278773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1279773642d9SDouglas Gilbert num += 2; 12801b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1281c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1282c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1283c65b1445SDouglas Gilbert arr[num++] = 0x0; 1284c65b1445SDouglas Gilbert arr[num++] = 0x8; 12851b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1286773642d9SDouglas Gilbert num += 8; 1287c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1288c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1289c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1290c65b1445SDouglas Gilbert arr[num++] = 0x0; 1291c65b1445SDouglas Gilbert arr[num++] = 24; 12921b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1293c65b1445SDouglas Gilbert num += 12; 1294c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1295c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1296c65b1445SDouglas Gilbert num += 8; 1297c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1298c65b1445SDouglas Gilbert num += 4; 1299c65b1445SDouglas Gilbert return num; 1300c65b1445SDouglas Gilbert } 1301c65b1445SDouglas Gilbert 1302c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1303c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1304c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1305c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1306c65b1445SDouglas Gilbert }; 1307c65b1445SDouglas Gilbert 1308cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1309760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1310c65b1445SDouglas Gilbert { 1311c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1312c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1313c65b1445SDouglas Gilbert } 1314c65b1445SDouglas Gilbert 1315cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1316760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1317c65b1445SDouglas Gilbert { 1318c65b1445SDouglas Gilbert int num = 0; 1319c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1320c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1321c65b1445SDouglas Gilbert int plen, olen; 1322c65b1445SDouglas Gilbert 1323c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1324c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1325c65b1445SDouglas Gilbert arr[num++] = 0x0; 1326c65b1445SDouglas Gilbert olen = strlen(na1); 1327c65b1445SDouglas Gilbert plen = olen + 1; 1328c65b1445SDouglas Gilbert if (plen % 4) 1329c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1330c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1331c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1332c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1333c65b1445SDouglas Gilbert num += plen; 1334c65b1445SDouglas Gilbert 1335c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1336c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1337c65b1445SDouglas Gilbert arr[num++] = 0x0; 1338c65b1445SDouglas Gilbert olen = strlen(na2); 1339c65b1445SDouglas Gilbert plen = olen + 1; 1340c65b1445SDouglas Gilbert if (plen % 4) 1341c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1342c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1343c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1344c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1345c65b1445SDouglas Gilbert num += plen; 1346c65b1445SDouglas Gilbert 1347c65b1445SDouglas Gilbert return num; 1348c65b1445SDouglas Gilbert } 1349c65b1445SDouglas Gilbert 1350c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1351760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1352c65b1445SDouglas Gilbert { 1353c65b1445SDouglas Gilbert int num = 0; 1354c65b1445SDouglas Gilbert int port_a, port_b; 1355c65b1445SDouglas Gilbert 1356c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1357c65b1445SDouglas Gilbert port_b = port_a + 1; 1358c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1359c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1360c65b1445SDouglas Gilbert arr[num++] = 0x0; 1361c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1362c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1363c65b1445SDouglas Gilbert num += 6; 1364c65b1445SDouglas Gilbert arr[num++] = 0x0; 1365c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1366c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1367c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1368c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1369c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1370c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13711b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1372773642d9SDouglas Gilbert num += 8; 1373c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1374c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1375c65b1445SDouglas Gilbert arr[num++] = 0x0; 1376c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 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 (B) */ 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_b, arr + num); 1387773642d9SDouglas Gilbert num += 8; 1388c65b1445SDouglas Gilbert 1389c65b1445SDouglas Gilbert return num; 1390c65b1445SDouglas Gilbert } 1391c65b1445SDouglas Gilbert 1392c65b1445SDouglas Gilbert 1393c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1394c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1395c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1396c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1397c65b1445SDouglas Gilbert '1','2','3','4', 1398c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1399c65b1445SDouglas Gilbert 0xec,0,0,0, 1400c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1401c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1402c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1403c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1404c65b1445SDouglas Gilbert 0x53,0x41, 1405c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1406c65b1445SDouglas Gilbert 0x20,0x20, 1407c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1408c65b1445SDouglas Gilbert 0x10,0x80, 1409c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1410c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1411c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1412c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1413c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1414c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1415c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1416c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1417c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1418c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1419c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1420c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1421c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1422c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1423c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1426c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1428c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1430c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1435c65b1445SDouglas Gilbert }; 1436c65b1445SDouglas Gilbert 1437cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1438760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1439c65b1445SDouglas Gilbert { 1440c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1441c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1442c65b1445SDouglas Gilbert } 1443c65b1445SDouglas Gilbert 1444c65b1445SDouglas Gilbert 1445c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14461e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14471e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14481e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14491e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1450c65b1445SDouglas Gilbert }; 1451c65b1445SDouglas Gilbert 1452cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1453760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1454c65b1445SDouglas Gilbert { 1455ea61fca5SMartin K. Petersen unsigned int gran; 1456ea61fca5SMartin K. Petersen 1457c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1458e308b3d1SMartin K. Petersen 1459e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 146086e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 146186e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 146286e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 146386e6828aSLukas Herbolt else 1464773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1465773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1466e308b3d1SMartin K. Petersen 1467e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1468773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1469773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 147044d92694SMartin K. Petersen 1471e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1472773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1473e308b3d1SMartin K. Petersen 1474773642d9SDouglas Gilbert if (sdebug_lbpu) { 1475e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1476773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1477e308b3d1SMartin K. Petersen 1478e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1479773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 148044d92694SMartin K. Petersen } 148144d92694SMartin K. Petersen 1482e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1483773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1484773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 148544d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 148644d92694SMartin K. Petersen } 148744d92694SMartin K. Petersen 1488e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1489773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 14906014759cSMartin K. Petersen 14915b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1492773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 14935b94e232SMartin K. Petersen 14945b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 149544d92694SMartin K. Petersen 1496c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 14971da177e4SLinus Torvalds } 14981da177e4SLinus Torvalds 14991e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1500760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1501eac6e8e4SMatthew Wilcox { 1502eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1503eac6e8e4SMatthew Wilcox arr[0] = 0; 15041e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15051e49f785SDouglas Gilbert arr[2] = 0; 15061e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1507eac6e8e4SMatthew Wilcox 1508eac6e8e4SMatthew Wilcox return 0x3c; 1509eac6e8e4SMatthew Wilcox } 15101da177e4SLinus Torvalds 1511760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1512760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15136014759cSMartin K. Petersen { 15143f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15156014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1516773642d9SDouglas Gilbert if (sdebug_lbpu) 15176014759cSMartin K. Petersen arr[1] = 1 << 7; 1518773642d9SDouglas Gilbert if (sdebug_lbpws) 15196014759cSMartin K. Petersen arr[1] |= 1 << 6; 1520773642d9SDouglas Gilbert if (sdebug_lbpws10) 15215b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1522760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1523760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1524760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1525760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1526760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15273f0bc3b3SMartin K. Petersen return 0x4; 15286014759cSMartin K. Petersen } 15296014759cSMartin K. Petersen 1530d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1531f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1532d36da305SDouglas Gilbert { 1533d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1534d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1535d36da305SDouglas Gilbert /* 1536d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1537d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1538f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1539f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1540d36da305SDouglas Gilbert */ 1541d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1542d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 1543f0d1cf93SDouglas Gilbert if (devip->max_open) 1544f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1545f0d1cf93SDouglas Gilbert else 1546d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 1547d36da305SDouglas Gilbert return 0x3c; 1548d36da305SDouglas Gilbert } 1549d36da305SDouglas Gilbert 15501da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1551c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15521da177e4SLinus Torvalds 1553c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15541da177e4SLinus Torvalds { 15551da177e4SLinus Torvalds unsigned char pq_pdt; 15565a09e398SHannes Reinecke unsigned char *arr; 155701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15585a09e398SHannes Reinecke int alloc_len, n, ret; 1559d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15601da177e4SLinus Torvalds 1561773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15626f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15636f3cbf55SDouglas Gilbert if (! arr) 15646f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1565760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1566d36da305SDouglas Gilbert is_zbc = (sdebug_ptype == TYPE_ZBC); 1567d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1568b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1569c2248fc9SDouglas Gilbert if (have_wlun) 1570b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1571b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1572b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1573c65b1445SDouglas Gilbert else 1574773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 15751da177e4SLinus Torvalds arr[0] = pq_pdt; 15761da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 157722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 15785a09e398SHannes Reinecke kfree(arr); 15791da177e4SLinus Torvalds return check_condition_result; 15801da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 15815a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1582c65b1445SDouglas Gilbert char lu_id_str[6]; 1583c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 15841da177e4SLinus Torvalds 15855a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 15865a09e398SHannes Reinecke (devip->channel & 0x7f); 1587b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 158823183910SDouglas Gilbert host_no = 0; 1589c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1590c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1591c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1592c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1593c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 15941da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1595c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1596c65b1445SDouglas Gilbert n = 4; 1597c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1598c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1599c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1600c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1601c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1602c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1603c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1604c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1605d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1606c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1607760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1608760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1609d36da305SDouglas Gilbert if (is_disk) 1610d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 1611d36da305SDouglas Gilbert else if (is_zbc) 1612d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1613760f3b03SDouglas Gilbert } 1614c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16151da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1616c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16171da177e4SLinus Torvalds arr[3] = len; 1618c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16191da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1620c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1621760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16225a09e398SHannes Reinecke target_dev_id, lu_id_num, 162309ba24c1SDouglas Gilbert lu_id_str, len, 162409ba24c1SDouglas Gilbert &devip->lu_name); 1625c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1626c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1627760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1628c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1629c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1630760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1631c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1632c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1633c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16348475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1635c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1636760f3b03SDouglas Gilbert else if (have_dif_prot) 1637c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1638c6a44287SMartin K. Petersen else 1639c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1640c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1641c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1642c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1643c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1644c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1645c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1646c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1647c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1648c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1649c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1650760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1651d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1652c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1653760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1654773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1655d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1656c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1657760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1658d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1659eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1660760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1661760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16626014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1663760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1664d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1665d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1666f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16671da177e4SLinus Torvalds } else { 166822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16695a09e398SHannes Reinecke kfree(arr); 16701da177e4SLinus Torvalds return check_condition_result; 16711da177e4SLinus Torvalds } 1672773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 16735a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1674c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 16755a09e398SHannes Reinecke kfree(arr); 16765a09e398SHannes Reinecke return ret; 16771da177e4SLinus Torvalds } 16781da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1679773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1680773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 16811da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 16821da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1683f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1684b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 168570bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1686c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 16871da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1688c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1689e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1690e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1691e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 16929b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 16939b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 16941da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1695760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1696760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1697c65b1445SDouglas Gilbert n = 62; 1698760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1699760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1700760f3b03SDouglas Gilbert n += 2; 1701760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1702760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1703760f3b03SDouglas Gilbert n += 2; 1704d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1705d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1706d36da305SDouglas Gilbert n += 2; 17071da177e4SLinus Torvalds } 1708760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17095a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 171087c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ)); 17115a09e398SHannes Reinecke kfree(arr); 17125a09e398SHannes Reinecke return ret; 17131da177e4SLinus Torvalds } 17141da177e4SLinus Torvalds 1715fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1716fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1717fd32119bSDouglas Gilbert 17181da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17191da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17201da177e4SLinus Torvalds { 17211da177e4SLinus Torvalds unsigned char *sbuff; 172201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1723cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 17242492fc09STomas Winkler bool dsense; 17251da177e4SLinus Torvalds int len = 18; 17261da177e4SLinus Torvalds 1727c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1728c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1729cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1730c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1731c2248fc9SDouglas Gilbert if (dsense) { 1732c65b1445SDouglas Gilbert arr[0] = 0x72; 1733c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1734c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1735c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1736c2248fc9SDouglas Gilbert len = 8; 1737c65b1445SDouglas Gilbert } else { 1738c65b1445SDouglas Gilbert arr[0] = 0x70; 1739c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1740c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1741c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1742c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1743c65b1445SDouglas Gilbert } 1744c65b1445SDouglas Gilbert } else { 1745cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1746773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1747c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1748c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1749c2248fc9SDouglas Gilbert if (dsense) { 1750c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1751c2248fc9SDouglas Gilbert arr[0] = 0x72; 1752c2248fc9SDouglas Gilbert len = 8; 1753c2248fc9SDouglas Gilbert } else { 1754c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1755c2248fc9SDouglas Gilbert arr[0] = 0x70; 1756c2248fc9SDouglas Gilbert arr[7] = 0xa; 1757c2248fc9SDouglas Gilbert } 1758c2248fc9SDouglas Gilbert } else if (dsense) { 1759c2248fc9SDouglas Gilbert memset(arr, 0, 8); 17601da177e4SLinus Torvalds arr[0] = 0x72; 17611da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 17621da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 17631da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 17641da177e4SLinus Torvalds len = 8; 1765c2248fc9SDouglas Gilbert } else { 1766c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1767c2248fc9SDouglas Gilbert arr[0] = 0x70; 1768c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1769c2248fc9SDouglas Gilbert arr[7] = 0xa; 1770c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1771c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1772c65b1445SDouglas Gilbert } 1773c2248fc9SDouglas Gilbert 1774c65b1445SDouglas Gilbert } 1775cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 17761da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 17771da177e4SLinus Torvalds } 17781da177e4SLinus Torvalds 1779c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, 1780c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1781c65b1445SDouglas Gilbert { 178201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1783c4837394SDouglas Gilbert int power_cond, stop; 17844f2c8bf6SDouglas Gilbert bool changing; 1785c65b1445SDouglas Gilbert 1786c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1787c65b1445SDouglas Gilbert if (power_cond) { 178822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1789c65b1445SDouglas Gilbert return check_condition_result; 1790c65b1445SDouglas Gilbert } 1791c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 17924f2c8bf6SDouglas Gilbert changing = atomic_read(&devip->stopped) == !stop; 1793c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 17944f2c8bf6SDouglas Gilbert if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */ 17954f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 17964f2c8bf6SDouglas Gilbert else 17974f2c8bf6SDouglas Gilbert return 0; 1798c65b1445SDouglas Gilbert } 1799c65b1445SDouglas Gilbert 180028898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 180128898873SFUJITA Tomonori { 1802773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1803773642d9SDouglas Gilbert 1804773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1805773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1806773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 180728898873SFUJITA Tomonori else 180828898873SFUJITA Tomonori return sdebug_store_sectors; 180928898873SFUJITA Tomonori } 181028898873SFUJITA Tomonori 18111da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18121da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18131da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18141da177e4SLinus Torvalds { 18151da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1816c65b1445SDouglas Gilbert unsigned int capac; 18171da177e4SLinus Torvalds 1818c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 181928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18201da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1821c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1822c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1823773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1824773642d9SDouglas Gilbert } else 1825773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1826773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18271da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18281da177e4SLinus Torvalds } 18291da177e4SLinus Torvalds 1830c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1831c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1832c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1833c65b1445SDouglas Gilbert { 183401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1835c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1836773642d9SDouglas Gilbert int alloc_len; 1837c65b1445SDouglas Gilbert 1838773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1839c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 184028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1841c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1842773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1843773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1844773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1845773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 184644d92694SMartin K. Petersen 1847be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18485b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1849760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1850760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1851760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1852760f3b03SDouglas Gilbert */ 1853760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1854760f3b03SDouglas Gilbert arr[14] |= 0x40; 1855be1dd78dSEric Sandeen } 185644d92694SMartin K. Petersen 1857773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1858c6a44287SMartin K. Petersen 1859760f3b03SDouglas Gilbert if (have_dif_prot) { 1860773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1861c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1862c6a44287SMartin K. Petersen } 1863c6a44287SMartin K. Petersen 1864c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 186587c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1866c65b1445SDouglas Gilbert } 1867c65b1445SDouglas Gilbert 18685a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 18695a09e398SHannes Reinecke 18705a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 18715a09e398SHannes Reinecke struct sdebug_dev_info *devip) 18725a09e398SHannes Reinecke { 187301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 18745a09e398SHannes Reinecke unsigned char *arr; 18755a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 18765a09e398SHannes Reinecke int n, ret, alen, rlen; 18775a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 18785a09e398SHannes Reinecke 1879773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 18806f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 18816f3cbf55SDouglas Gilbert if (! arr) 18826f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 18835a09e398SHannes Reinecke /* 18845a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 18855a09e398SHannes Reinecke * real and a fake port with no device connected. 18865a09e398SHannes Reinecke * So we create two port groups with one port each 18875a09e398SHannes Reinecke * and set the group with port B to unavailable. 18885a09e398SHannes Reinecke */ 18895a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 18905a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 18915a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 18925a09e398SHannes Reinecke (devip->channel & 0x7f); 18935a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 18945a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 18955a09e398SHannes Reinecke 18965a09e398SHannes Reinecke /* 18975a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 18985a09e398SHannes Reinecke */ 18995a09e398SHannes Reinecke n = 4; 1900b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19015a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19025a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19035a09e398SHannes Reinecke } else { 19045a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1905773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19065a09e398SHannes Reinecke } 1907773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1908773642d9SDouglas Gilbert n += 2; 19095a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19105a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19115a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19125a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19135a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19145a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1915773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1916773642d9SDouglas Gilbert n += 2; 19175a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19185a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1919773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1920773642d9SDouglas Gilbert n += 2; 19215a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19225a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19235a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19245a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19255a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19265a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1927773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1928773642d9SDouglas Gilbert n += 2; 19295a09e398SHannes Reinecke 19305a09e398SHannes Reinecke rlen = n - 4; 1931773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19325a09e398SHannes Reinecke 19335a09e398SHannes Reinecke /* 19345a09e398SHannes Reinecke * Return the smallest value of either 19355a09e398SHannes Reinecke * - The allocated length 19365a09e398SHannes Reinecke * - The constructed command length 19375a09e398SHannes Reinecke * - The maximum array size 19385a09e398SHannes Reinecke */ 193987c715dcSDouglas Gilbert rlen = min_t(int, alen, n); 19405a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 194187c715dcSDouglas Gilbert min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19425a09e398SHannes Reinecke kfree(arr); 19435a09e398SHannes Reinecke return ret; 19445a09e398SHannes Reinecke } 19455a09e398SHannes Reinecke 1946fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1947fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 194838d5c833SDouglas Gilbert { 194938d5c833SDouglas Gilbert bool rctd; 195038d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 195138d5c833SDouglas Gilbert u16 req_sa, u; 195238d5c833SDouglas Gilbert u32 alloc_len, a_len; 195338d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 195438d5c833SDouglas Gilbert const struct opcode_info_t *oip; 195538d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 195638d5c833SDouglas Gilbert u8 *arr; 195738d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 195838d5c833SDouglas Gilbert 195938d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 196038d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 196138d5c833SDouglas Gilbert req_opcode = cmd[3]; 196238d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 196338d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 19646d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 196538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 196638d5c833SDouglas Gilbert return check_condition_result; 196738d5c833SDouglas Gilbert } 196838d5c833SDouglas Gilbert if (alloc_len > 8192) 196938d5c833SDouglas Gilbert a_len = 8192; 197038d5c833SDouglas Gilbert else 197138d5c833SDouglas Gilbert a_len = alloc_len; 197299531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 197338d5c833SDouglas Gilbert if (NULL == arr) { 197438d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 197538d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 197638d5c833SDouglas Gilbert return check_condition_result; 197738d5c833SDouglas Gilbert } 197838d5c833SDouglas Gilbert switch (reporting_opts) { 197938d5c833SDouglas Gilbert case 0: /* all commands */ 198038d5c833SDouglas Gilbert /* count number of commands */ 198138d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 198238d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 198338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 198438d5c833SDouglas Gilbert continue; 198538d5c833SDouglas Gilbert count += (oip->num_attached + 1); 198638d5c833SDouglas Gilbert } 198738d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 198838d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 198938d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 199038d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 199138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 199238d5c833SDouglas Gilbert continue; 199338d5c833SDouglas Gilbert na = oip->num_attached; 199438d5c833SDouglas Gilbert arr[offset] = oip->opcode; 199538d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 199638d5c833SDouglas Gilbert if (rctd) 199738d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 199838d5c833SDouglas Gilbert if (FF_SA & oip->flags) 199938d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 200038d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 200138d5c833SDouglas Gilbert if (rctd) 200238d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 200338d5c833SDouglas Gilbert r_oip = oip; 200438d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 200538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 200638d5c833SDouglas Gilbert continue; 200738d5c833SDouglas Gilbert offset += bump; 200838d5c833SDouglas Gilbert arr[offset] = oip->opcode; 200938d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 201038d5c833SDouglas Gilbert if (rctd) 201138d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 201238d5c833SDouglas Gilbert if (FF_SA & oip->flags) 201338d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 201438d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 201538d5c833SDouglas Gilbert arr + offset + 6); 201638d5c833SDouglas Gilbert if (rctd) 201738d5c833SDouglas Gilbert put_unaligned_be16(0xa, 201838d5c833SDouglas Gilbert arr + offset + 8); 201938d5c833SDouglas Gilbert } 202038d5c833SDouglas Gilbert oip = r_oip; 202138d5c833SDouglas Gilbert offset += bump; 202238d5c833SDouglas Gilbert } 202338d5c833SDouglas Gilbert break; 202438d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 202538d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 202638d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 202738d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 202838d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 202938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 203038d5c833SDouglas Gilbert supp = 1; 203138d5c833SDouglas Gilbert offset = 4; 203238d5c833SDouglas Gilbert } else { 203338d5c833SDouglas Gilbert if (1 == reporting_opts) { 203438d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 203538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 203638d5c833SDouglas Gilbert 2, 2); 203738d5c833SDouglas Gilbert kfree(arr); 203838d5c833SDouglas Gilbert return check_condition_result; 203938d5c833SDouglas Gilbert } 204038d5c833SDouglas Gilbert req_sa = 0; 204138d5c833SDouglas Gilbert } else if (2 == reporting_opts && 204238d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 204338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 204438d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 204538d5c833SDouglas Gilbert return check_condition_result; 204638d5c833SDouglas Gilbert } 204738d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 204838d5c833SDouglas Gilbert req_opcode == oip->opcode) 204938d5c833SDouglas Gilbert supp = 3; 205038d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 205138d5c833SDouglas Gilbert na = oip->num_attached; 205238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 205338d5c833SDouglas Gilbert ++k, ++oip) { 205438d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 205538d5c833SDouglas Gilbert break; 205638d5c833SDouglas Gilbert } 205738d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 205838d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 205938d5c833SDouglas Gilbert na = oip->num_attached; 206038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 206138d5c833SDouglas Gilbert ++k, ++oip) { 206238d5c833SDouglas Gilbert if (req_sa == oip->sa) 206338d5c833SDouglas Gilbert break; 206438d5c833SDouglas Gilbert } 206538d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 206638d5c833SDouglas Gilbert } else 206738d5c833SDouglas Gilbert supp = 3; 206838d5c833SDouglas Gilbert if (3 == supp) { 206938d5c833SDouglas Gilbert u = oip->len_mask[0]; 207038d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 207138d5c833SDouglas Gilbert arr[4] = oip->opcode; 207238d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 207338d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 207438d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 207538d5c833SDouglas Gilbert offset = 4 + u; 207638d5c833SDouglas Gilbert } else 207738d5c833SDouglas Gilbert offset = 4; 207838d5c833SDouglas Gilbert } 207938d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 208038d5c833SDouglas Gilbert if (rctd) { 208138d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 208238d5c833SDouglas Gilbert offset += 12; 208338d5c833SDouglas Gilbert } 208438d5c833SDouglas Gilbert break; 208538d5c833SDouglas Gilbert default: 208638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 208738d5c833SDouglas Gilbert kfree(arr); 208838d5c833SDouglas Gilbert return check_condition_result; 208938d5c833SDouglas Gilbert } 209038d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 209138d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 209238d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 209338d5c833SDouglas Gilbert kfree(arr); 209438d5c833SDouglas Gilbert return errsts; 209538d5c833SDouglas Gilbert } 209638d5c833SDouglas Gilbert 2097fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2098fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 209938d5c833SDouglas Gilbert { 210038d5c833SDouglas Gilbert bool repd; 210138d5c833SDouglas Gilbert u32 alloc_len, len; 210238d5c833SDouglas Gilbert u8 arr[16]; 210338d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 210438d5c833SDouglas Gilbert 210538d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 210638d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 210738d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 210838d5c833SDouglas Gilbert if (alloc_len < 4) { 210938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 211038d5c833SDouglas Gilbert return check_condition_result; 211138d5c833SDouglas Gilbert } 211238d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 211338d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 211438d5c833SDouglas Gilbert if (repd) { 211538d5c833SDouglas Gilbert arr[3] = 0xc; 211638d5c833SDouglas Gilbert len = 16; 211738d5c833SDouglas Gilbert } else 211838d5c833SDouglas Gilbert len = 4; 211938d5c833SDouglas Gilbert 212038d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 212138d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 212238d5c833SDouglas Gilbert } 212338d5c833SDouglas Gilbert 21241da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21251da177e4SLinus Torvalds 21261da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21271da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21281da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21291da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21301da177e4SLinus Torvalds 21311da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21321da177e4SLinus Torvalds if (1 == pcontrol) 21331da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21341da177e4SLinus Torvalds return sizeof(err_recov_pg); 21351da177e4SLinus Torvalds } 21361da177e4SLinus Torvalds 21371da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21381da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21391da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21401da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21411da177e4SLinus Torvalds 21421da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21431da177e4SLinus Torvalds if (1 == pcontrol) 21441da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21451da177e4SLinus Torvalds return sizeof(disconnect_pg); 21461da177e4SLinus Torvalds } 21471da177e4SLinus Torvalds 21481da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21491da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21501da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21511da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21521da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21531da177e4SLinus Torvalds 21541da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2155773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2156773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2157773642d9SDouglas Gilbert if (sdebug_removable) 21581da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 21591da177e4SLinus Torvalds if (1 == pcontrol) 21601da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 21611da177e4SLinus Torvalds return sizeof(format_pg); 21621da177e4SLinus Torvalds } 21631da177e4SLinus Torvalds 2164fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2165fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2166fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2167fd32119bSDouglas Gilbert 21681da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 21691da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2170cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2171cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2172cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 21731da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 21741da177e4SLinus Torvalds 2175773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2176cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 21771da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 21781da177e4SLinus Torvalds if (1 == pcontrol) 2179cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2180cbf67842SDouglas Gilbert else if (2 == pcontrol) 2181cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 21821da177e4SLinus Torvalds return sizeof(caching_pg); 21831da177e4SLinus Torvalds } 21841da177e4SLinus Torvalds 2185fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2186fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2187fd32119bSDouglas Gilbert 21881da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 21891da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2190c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2191c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2192c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 21931da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 21941da177e4SLinus Torvalds 2195773642d9SDouglas Gilbert if (sdebug_dsense) 21961da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2197c65b1445SDouglas Gilbert else 2198c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2199c6a44287SMartin K. Petersen 2200773642d9SDouglas Gilbert if (sdebug_ato) 2201c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2202c6a44287SMartin K. Petersen 22031da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22041da177e4SLinus Torvalds if (1 == pcontrol) 2205c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2206c65b1445SDouglas Gilbert else if (2 == pcontrol) 2207c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22081da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22091da177e4SLinus Torvalds } 22101da177e4SLinus Torvalds 2211c65b1445SDouglas Gilbert 22121da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22131da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2214c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22151da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2216c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2217c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2218c65b1445SDouglas Gilbert 22191da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22201da177e4SLinus Torvalds if (1 == pcontrol) 2221c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2222c65b1445SDouglas Gilbert else if (2 == pcontrol) 2223c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22241da177e4SLinus Torvalds return sizeof(iec_m_pg); 22251da177e4SLinus Torvalds } 22261da177e4SLinus Torvalds 2227c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2228c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2229c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2230c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2231c65b1445SDouglas Gilbert 2232c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2233c65b1445SDouglas Gilbert if (1 == pcontrol) 2234c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2235c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2236c65b1445SDouglas Gilbert } 2237c65b1445SDouglas Gilbert 2238c65b1445SDouglas Gilbert 2239c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2240c65b1445SDouglas Gilbert int target_dev_id) 2241c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2242c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2243c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2244773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2245773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2246c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2247c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2248c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2249c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2250773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2251773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2252c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2253c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2254c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2255c65b1445SDouglas Gilbert }; 2256c65b1445SDouglas Gilbert int port_a, port_b; 2257c65b1445SDouglas Gilbert 22581b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 22591b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 22601b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 22611b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2262c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2263c65b1445SDouglas Gilbert port_b = port_a + 1; 2264c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2265773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2266773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2267c65b1445SDouglas Gilbert if (1 == pcontrol) 2268c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2269c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2270c65b1445SDouglas Gilbert } 2271c65b1445SDouglas Gilbert 2272c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2273c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2274c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2275c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2276c65b1445SDouglas Gilbert }; 2277c65b1445SDouglas Gilbert 2278c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2279c65b1445SDouglas Gilbert if (1 == pcontrol) 2280c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2281c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2282c65b1445SDouglas Gilbert } 2283c65b1445SDouglas Gilbert 22841da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 22851da177e4SLinus Torvalds 2286fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2287fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 22881da177e4SLinus Torvalds { 228923183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 22901da177e4SLinus Torvalds unsigned char dev_spec; 2291760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2292c2248fc9SDouglas Gilbert int target = scp->device->id; 22931da177e4SLinus Torvalds unsigned char *ap; 22941da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 229501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2296d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 22971da177e4SLinus Torvalds 2298760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 22991da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23001da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23011da177e4SLinus Torvalds subpcode = cmd[3]; 23021da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2303760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2304760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 2305d36da305SDouglas Gilbert is_zbc = (sdebug_ptype == TYPE_ZBC); 2306d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 230723183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 230823183910SDouglas Gilbert else 230923183910SDouglas Gilbert bd_len = 0; 2310773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23111da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23121da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2313cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23141da177e4SLinus Torvalds return check_condition_result; 23151da177e4SLinus Torvalds } 2316c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2317c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2318d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2319d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2320b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23219447b6ceSMartin K. Petersen if (sdebug_wp) 23229447b6ceSMartin K. Petersen dev_spec |= 0x80; 23239447b6ceSMartin K. Petersen } else 232423183910SDouglas Gilbert dev_spec = 0x0; 23251da177e4SLinus Torvalds if (msense_6) { 23261da177e4SLinus Torvalds arr[2] = dev_spec; 232723183910SDouglas Gilbert arr[3] = bd_len; 23281da177e4SLinus Torvalds offset = 4; 23291da177e4SLinus Torvalds } else { 23301da177e4SLinus Torvalds arr[3] = dev_spec; 233123183910SDouglas Gilbert if (16 == bd_len) 233223183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 233323183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23341da177e4SLinus Torvalds offset = 8; 23351da177e4SLinus Torvalds } 23361da177e4SLinus Torvalds ap = arr + offset; 233728898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 233828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 233928898873SFUJITA Tomonori 234023183910SDouglas Gilbert if (8 == bd_len) { 2341773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2342773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2343773642d9SDouglas Gilbert else 2344773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2345773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 234623183910SDouglas Gilbert offset += bd_len; 234723183910SDouglas Gilbert ap = arr + offset; 234823183910SDouglas Gilbert } else if (16 == bd_len) { 2349773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2350773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 235123183910SDouglas Gilbert offset += bd_len; 235223183910SDouglas Gilbert ap = arr + offset; 235323183910SDouglas Gilbert } 23541da177e4SLinus Torvalds 2355c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2356c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 235722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 23581da177e4SLinus Torvalds return check_condition_result; 23591da177e4SLinus Torvalds } 2360760f3b03SDouglas Gilbert bad_pcode = false; 2361760f3b03SDouglas Gilbert 23621da177e4SLinus Torvalds switch (pcode) { 23631da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 23641da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 23651da177e4SLinus Torvalds offset += len; 23661da177e4SLinus Torvalds break; 23671da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 23681da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 23691da177e4SLinus Torvalds offset += len; 23701da177e4SLinus Torvalds break; 23711da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2372760f3b03SDouglas Gilbert if (is_disk) { 23731da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 23741da177e4SLinus Torvalds offset += len; 2375760f3b03SDouglas Gilbert } else 2376760f3b03SDouglas Gilbert bad_pcode = true; 23771da177e4SLinus Torvalds break; 23781da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2379d36da305SDouglas Gilbert if (is_disk || is_zbc) { 23801da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 23811da177e4SLinus Torvalds offset += len; 2382760f3b03SDouglas Gilbert } else 2383760f3b03SDouglas Gilbert bad_pcode = true; 23841da177e4SLinus Torvalds break; 23851da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 23861da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 23871da177e4SLinus Torvalds offset += len; 23881da177e4SLinus Torvalds break; 2389c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2390c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 239122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2392c65b1445SDouglas Gilbert return check_condition_result; 2393c65b1445SDouglas Gilbert } 2394c65b1445SDouglas Gilbert len = 0; 2395c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2396c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2397c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2398c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2399c65b1445SDouglas Gilbert target_dev_id); 2400c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2401c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2402c65b1445SDouglas Gilbert offset += len; 2403c65b1445SDouglas Gilbert break; 24041da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24051da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24061da177e4SLinus Torvalds offset += len; 24071da177e4SLinus Torvalds break; 24081da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2409c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24101da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24111da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2412760f3b03SDouglas Gilbert if (is_disk) { 2413760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2414760f3b03SDouglas Gilbert target); 2415760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2416760f3b03SDouglas Gilbert target); 2417d36da305SDouglas Gilbert } else if (is_zbc) { 2418d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2419d36da305SDouglas Gilbert target); 2420760f3b03SDouglas Gilbert } 24211da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2422c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2423c65b1445SDouglas Gilbert if (0xff == subpcode) { 2424c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2425c65b1445SDouglas Gilbert target, target_dev_id); 2426c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2427c65b1445SDouglas Gilbert } 24281da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2429760f3b03SDouglas Gilbert offset += len; 2430c65b1445SDouglas Gilbert } else { 243122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2432c65b1445SDouglas Gilbert return check_condition_result; 2433c65b1445SDouglas Gilbert } 24341da177e4SLinus Torvalds break; 24351da177e4SLinus Torvalds default: 2436760f3b03SDouglas Gilbert bad_pcode = true; 2437760f3b03SDouglas Gilbert break; 2438760f3b03SDouglas Gilbert } 2439760f3b03SDouglas Gilbert if (bad_pcode) { 244022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24411da177e4SLinus Torvalds return check_condition_result; 24421da177e4SLinus Torvalds } 24431da177e4SLinus Torvalds if (msense_6) 24441da177e4SLinus Torvalds arr[0] = offset - 1; 2445773642d9SDouglas Gilbert else 2446773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 244787c715dcSDouglas Gilbert return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset)); 24481da177e4SLinus Torvalds } 24491da177e4SLinus Torvalds 2450c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2451c65b1445SDouglas Gilbert 2452fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2453fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2454c65b1445SDouglas Gilbert { 2455c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2456c2248fc9SDouglas Gilbert int param_len, res, mpage; 2457c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 245801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2459c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2460c65b1445SDouglas Gilbert 2461c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2462c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2463c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2464773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2465c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 246622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2467c65b1445SDouglas Gilbert return check_condition_result; 2468c65b1445SDouglas Gilbert } 2469c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2470c65b1445SDouglas Gilbert if (-1 == res) 2471773642d9SDouglas Gilbert return DID_ERROR << 16; 2472773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2473cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2474cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2475cbf67842SDouglas Gilbert __func__, param_len, res); 2476773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2477773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 247823183910SDouglas Gilbert if (md_len > 2) { 247922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2480c65b1445SDouglas Gilbert return check_condition_result; 2481c65b1445SDouglas Gilbert } 2482c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2483c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2484c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2485c65b1445SDouglas Gilbert if (ps) { 248622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2487c65b1445SDouglas Gilbert return check_condition_result; 2488c65b1445SDouglas Gilbert } 2489c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2490773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2491c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2492c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2493cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2494c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2495c65b1445SDouglas Gilbert return check_condition_result; 2496c65b1445SDouglas Gilbert } 2497c65b1445SDouglas Gilbert switch (mpage) { 2498cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2499cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2500cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2501cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2502cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2503cbf67842SDouglas Gilbert } 2504cbf67842SDouglas Gilbert break; 2505c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2506c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2507c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2508c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25099447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25109447b6ceSMartin K. Petersen sdebug_wp = true; 25119447b6ceSMartin K. Petersen else 25129447b6ceSMartin K. Petersen sdebug_wp = false; 2513773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2514cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2515c65b1445SDouglas Gilbert } 2516c65b1445SDouglas Gilbert break; 2517c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2518c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2519c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2520c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2521cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2522c65b1445SDouglas Gilbert } 2523c65b1445SDouglas Gilbert break; 2524c65b1445SDouglas Gilbert default: 2525c65b1445SDouglas Gilbert break; 2526c65b1445SDouglas Gilbert } 252722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2528c65b1445SDouglas Gilbert return check_condition_result; 2529cbf67842SDouglas Gilbert set_mode_changed_ua: 2530cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2531cbf67842SDouglas Gilbert return 0; 2532c65b1445SDouglas Gilbert } 2533c65b1445SDouglas Gilbert 2534c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2535c65b1445SDouglas Gilbert { 2536c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2537c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2538c65b1445SDouglas Gilbert }; 2539c65b1445SDouglas Gilbert 2540c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2541c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2542c65b1445SDouglas Gilbert } 2543c65b1445SDouglas Gilbert 2544c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2545c65b1445SDouglas Gilbert { 2546c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2547c65b1445SDouglas Gilbert }; 2548c65b1445SDouglas Gilbert 2549c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2550c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2551c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2552c65b1445SDouglas Gilbert arr[5] = 0xff; 2553c65b1445SDouglas Gilbert } 2554c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2555c65b1445SDouglas Gilbert } 2556c65b1445SDouglas Gilbert 2557c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2558c65b1445SDouglas Gilbert 2559c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2560c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2561c65b1445SDouglas Gilbert { 2562ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2563c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 256401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2565c65b1445SDouglas Gilbert 2566c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2567c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2568c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2569c65b1445SDouglas Gilbert if (ppc || sp) { 257022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2571c65b1445SDouglas Gilbert return check_condition_result; 2572c65b1445SDouglas Gilbert } 2573c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 257423183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2575773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2576c65b1445SDouglas Gilbert arr[0] = pcode; 257723183910SDouglas Gilbert if (0 == subpcode) { 2578c65b1445SDouglas Gilbert switch (pcode) { 2579c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2580c65b1445SDouglas Gilbert n = 4; 2581c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2582c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2583c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2584c65b1445SDouglas Gilbert arr[3] = n - 4; 2585c65b1445SDouglas Gilbert break; 2586c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2587c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2588c65b1445SDouglas Gilbert break; 2589c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2590c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2591c65b1445SDouglas Gilbert break; 2592c65b1445SDouglas Gilbert default: 259322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2594c65b1445SDouglas Gilbert return check_condition_result; 2595c65b1445SDouglas Gilbert } 259623183910SDouglas Gilbert } else if (0xff == subpcode) { 259723183910SDouglas Gilbert arr[0] |= 0x40; 259823183910SDouglas Gilbert arr[1] = subpcode; 259923183910SDouglas Gilbert switch (pcode) { 260023183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 260123183910SDouglas Gilbert n = 4; 260223183910SDouglas Gilbert arr[n++] = 0x0; 260323183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 260423183910SDouglas Gilbert arr[n++] = 0x0; 260523183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 260623183910SDouglas Gilbert arr[n++] = 0xd; 260723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 260823183910SDouglas Gilbert arr[n++] = 0x2f; 260923183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 261023183910SDouglas Gilbert arr[3] = n - 4; 261123183910SDouglas Gilbert break; 261223183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 261323183910SDouglas Gilbert n = 4; 261423183910SDouglas Gilbert arr[n++] = 0xd; 261523183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 261623183910SDouglas Gilbert arr[3] = n - 4; 261723183910SDouglas Gilbert break; 261823183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 261923183910SDouglas Gilbert n = 4; 262023183910SDouglas Gilbert arr[n++] = 0x2f; 262123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 262223183910SDouglas Gilbert arr[3] = n - 4; 262323183910SDouglas Gilbert break; 262423183910SDouglas Gilbert default: 262522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 262623183910SDouglas Gilbert return check_condition_result; 262723183910SDouglas Gilbert } 262823183910SDouglas Gilbert } else { 262922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 263023183910SDouglas Gilbert return check_condition_result; 263123183910SDouglas Gilbert } 263287c715dcSDouglas Gilbert len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len); 2633c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 263487c715dcSDouglas Gilbert min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ)); 2635c65b1445SDouglas Gilbert } 2636c65b1445SDouglas Gilbert 2637f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2638f0d1cf93SDouglas Gilbert { 2639f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2640f0d1cf93SDouglas Gilbert } 2641f0d1cf93SDouglas Gilbert 2642f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2643f0d1cf93SDouglas Gilbert unsigned long long lba) 2644f0d1cf93SDouglas Gilbert { 2645f0d1cf93SDouglas Gilbert unsigned int zno; 2646f0d1cf93SDouglas Gilbert 2647f0d1cf93SDouglas Gilbert if (devip->zsize_shift) 2648f0d1cf93SDouglas Gilbert zno = lba >> devip->zsize_shift; 2649f0d1cf93SDouglas Gilbert else 2650f0d1cf93SDouglas Gilbert zno = lba / devip->zsize; 2651f0d1cf93SDouglas Gilbert return &devip->zstate[zno]; 2652f0d1cf93SDouglas Gilbert } 2653f0d1cf93SDouglas Gilbert 2654f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2655f0d1cf93SDouglas Gilbert { 2656f0d1cf93SDouglas Gilbert return zsp->z_cond == ZBC_NOT_WRITE_POINTER; 2657f0d1cf93SDouglas Gilbert } 2658f0d1cf93SDouglas Gilbert 2659f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2660f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2661f0d1cf93SDouglas Gilbert { 2662f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2663f0d1cf93SDouglas Gilbert 2664f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2665f0d1cf93SDouglas Gilbert return; 2666f0d1cf93SDouglas Gilbert 2667f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2668f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2669f0d1cf93SDouglas Gilbert return; 2670f0d1cf93SDouglas Gilbert 2671f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2672f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2673f0d1cf93SDouglas Gilbert else 2674f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2675f0d1cf93SDouglas Gilbert 2676f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2677f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2678f0d1cf93SDouglas Gilbert } else { 2679f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2680f0d1cf93SDouglas Gilbert devip->nr_closed++; 2681f0d1cf93SDouglas Gilbert } 2682f0d1cf93SDouglas Gilbert } 2683f0d1cf93SDouglas Gilbert 2684f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2685f0d1cf93SDouglas Gilbert { 2686f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2687f0d1cf93SDouglas Gilbert unsigned int i; 2688f0d1cf93SDouglas Gilbert 2689f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2690f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2691f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2692f0d1cf93SDouglas Gilbert return; 2693f0d1cf93SDouglas Gilbert } 2694f0d1cf93SDouglas Gilbert } 2695f0d1cf93SDouglas Gilbert } 2696f0d1cf93SDouglas Gilbert 2697f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2698f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2699f0d1cf93SDouglas Gilbert { 2700f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2701f0d1cf93SDouglas Gilbert 2702f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2703f0d1cf93SDouglas Gilbert return; 2704f0d1cf93SDouglas Gilbert 2705f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2706f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2707f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2708f0d1cf93SDouglas Gilbert return; 2709f0d1cf93SDouglas Gilbert 2710f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2711f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2712f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2713f0d1cf93SDouglas Gilbert else if (devip->max_open && 2714f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2715f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2716f0d1cf93SDouglas Gilbert 2717f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2718f0d1cf93SDouglas Gilbert devip->nr_closed--; 2719f0d1cf93SDouglas Gilbert if (explicit) { 2720f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2721f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2722f0d1cf93SDouglas Gilbert } else { 2723f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2724f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2725f0d1cf93SDouglas Gilbert } 2726f0d1cf93SDouglas Gilbert } 2727f0d1cf93SDouglas Gilbert 2728f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2729f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2730f0d1cf93SDouglas Gilbert { 2731f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2732f0d1cf93SDouglas Gilbert 2733f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2734f0d1cf93SDouglas Gilbert return; 2735f0d1cf93SDouglas Gilbert 2736f0d1cf93SDouglas Gilbert zsp->z_wp += num; 2737f0d1cf93SDouglas Gilbert if (zsp->z_wp >= zsp->z_start + zsp->z_size) 2738f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 2739f0d1cf93SDouglas Gilbert } 2740f0d1cf93SDouglas Gilbert 2741f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 27429447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 27431da177e4SLinus Torvalds { 2744f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2745f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2746f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2747f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2748f0d1cf93SDouglas Gilbert 2749f0d1cf93SDouglas Gilbert if (!write) { 2750f0d1cf93SDouglas Gilbert /* Reads cannot cross zone types boundaries */ 2751f0d1cf93SDouglas Gilbert if (zsp_end != zsp && 2752f0d1cf93SDouglas Gilbert zbc_zone_is_conv(zsp) && 2753f0d1cf93SDouglas Gilbert !zbc_zone_is_conv(zsp_end)) { 2754f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2755f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2756f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2757f0d1cf93SDouglas Gilbert return check_condition_result; 2758f0d1cf93SDouglas Gilbert } 2759f0d1cf93SDouglas Gilbert return 0; 2760f0d1cf93SDouglas Gilbert } 2761f0d1cf93SDouglas Gilbert 2762f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2763f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2764f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2765f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2766f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2767f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2768f0d1cf93SDouglas Gilbert return check_condition_result; 2769f0d1cf93SDouglas Gilbert } 2770f0d1cf93SDouglas Gilbert return 0; 2771f0d1cf93SDouglas Gilbert } 2772f0d1cf93SDouglas Gilbert 2773f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2774f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2775f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2776f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2777f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2778f0d1cf93SDouglas Gilbert return check_condition_result; 2779f0d1cf93SDouglas Gilbert } 2780f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2781f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2782f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2783f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2784f0d1cf93SDouglas Gilbert return check_condition_result; 2785f0d1cf93SDouglas Gilbert } 2786f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2787f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2788f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2789f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2790f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2791f0d1cf93SDouglas Gilbert return check_condition_result; 2792f0d1cf93SDouglas Gilbert } 2793f0d1cf93SDouglas Gilbert 2794f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2795f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2796f0d1cf93SDouglas Gilbert if (devip->max_open && 2797f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2798f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2799f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2800f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2801f0d1cf93SDouglas Gilbert return check_condition_result; 2802f0d1cf93SDouglas Gilbert } 2803f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2804f0d1cf93SDouglas Gilbert } 2805f0d1cf93SDouglas Gilbert 2806f0d1cf93SDouglas Gilbert return 0; 2807f0d1cf93SDouglas Gilbert } 2808f0d1cf93SDouglas Gilbert 2809f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2810f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2811f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2812f0d1cf93SDouglas Gilbert { 2813f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2814f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2815f0d1cf93SDouglas Gilbert 2816c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 281722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 28181da177e4SLinus Torvalds return check_condition_result; 28191da177e4SLinus Torvalds } 2820c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2821c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 282222017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2823cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2824c65b1445SDouglas Gilbert return check_condition_result; 2825c65b1445SDouglas Gilbert } 28269447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 28279447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 28289447b6ceSMartin K. Petersen return check_condition_result; 28299447b6ceSMartin K. Petersen } 2830f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2831f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2832f0d1cf93SDouglas Gilbert 283319789100SFUJITA Tomonori return 0; 283419789100SFUJITA Tomonori } 283519789100SFUJITA Tomonori 283687c715dcSDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip) 283787c715dcSDouglas Gilbert { 283887c715dcSDouglas Gilbert return sdebug_fake_rw ? 283987c715dcSDouglas Gilbert NULL : xa_load(per_store_ap, devip->sdbg_host->si_idx); 284087c715dcSDouglas Gilbert } 284187c715dcSDouglas Gilbert 2842a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 284387c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 284487c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 284519789100SFUJITA Tomonori { 284619789100SFUJITA Tomonori int ret; 2847c2248fc9SDouglas Gilbert u64 block, rest = 0; 2848a4517511SAkinobu Mita enum dma_data_direction dir; 284987c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 285087c715dcSDouglas Gilbert u8 *fsp; 285119789100SFUJITA Tomonori 2852c2248fc9SDouglas Gilbert if (do_write) { 2853a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 28544f2c8bf6SDouglas Gilbert write_since_sync = true; 2855a4517511SAkinobu Mita } else { 2856a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2857a4517511SAkinobu Mita } 2858a4517511SAkinobu Mita 285987c715dcSDouglas Gilbert if (!sdb->length || !sip) 2860a4517511SAkinobu Mita return 0; 286187c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2862a4517511SAkinobu Mita return -1; 286387c715dcSDouglas Gilbert fsp = sip->storep; 286419789100SFUJITA Tomonori 286519789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 286619789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 286719789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 286819789100SFUJITA Tomonori 2869386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 287087c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 28710a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2872773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2873a4517511SAkinobu Mita return ret; 2874a4517511SAkinobu Mita 2875a4517511SAkinobu Mita if (rest) { 2876386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 287787c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 28780a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 28790a7e69c7SDouglas Gilbert do_write); 2880a4517511SAkinobu Mita } 288119789100SFUJITA Tomonori 288219789100SFUJITA Tomonori return ret; 288319789100SFUJITA Tomonori } 288419789100SFUJITA Tomonori 288587c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 288687c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 288787c715dcSDouglas Gilbert { 288887c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 288987c715dcSDouglas Gilbert 289087c715dcSDouglas Gilbert if (!sdb->length) 289187c715dcSDouglas Gilbert return 0; 289287c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 289387c715dcSDouglas Gilbert return -1; 289487c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 289587c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 289687c715dcSDouglas Gilbert } 289787c715dcSDouglas Gilbert 289887c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 289987c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 290038d5c833SDouglas Gilbert * return false. */ 290187c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 2902c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 290338d5c833SDouglas Gilbert { 290438d5c833SDouglas Gilbert bool res; 290538d5c833SDouglas Gilbert u64 block, rest = 0; 290638d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2907773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 290887c715dcSDouglas Gilbert u8 *fsp = sip->storep; 290938d5c833SDouglas Gilbert 291038d5c833SDouglas Gilbert block = do_div(lba, store_blks); 291138d5c833SDouglas Gilbert if (block + num > store_blks) 291238d5c833SDouglas Gilbert rest = block + num - store_blks; 291338d5c833SDouglas Gilbert 291487c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 291538d5c833SDouglas Gilbert if (!res) 291638d5c833SDouglas Gilbert return res; 291738d5c833SDouglas Gilbert if (rest) 291887c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 291938d5c833SDouglas Gilbert rest * lb_size); 292038d5c833SDouglas Gilbert if (!res) 292138d5c833SDouglas Gilbert return res; 2922c3e2fe92SDouglas Gilbert if (compare_only) 2923c3e2fe92SDouglas Gilbert return true; 292438d5c833SDouglas Gilbert arr += num * lb_size; 292587c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 292638d5c833SDouglas Gilbert if (rest) 292787c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 292838d5c833SDouglas Gilbert return res; 292938d5c833SDouglas Gilbert } 293038d5c833SDouglas Gilbert 293151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2932beb40ea4SAkinobu Mita { 293351d648afSAkinobu Mita __be16 csum; 2934beb40ea4SAkinobu Mita 2935773642d9SDouglas Gilbert if (sdebug_guard) 293651d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 293751d648afSAkinobu Mita else 2938beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 293951d648afSAkinobu Mita 2940beb40ea4SAkinobu Mita return csum; 2941beb40ea4SAkinobu Mita } 2942beb40ea4SAkinobu Mita 29436ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 2944beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2945beb40ea4SAkinobu Mita { 2946773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2947beb40ea4SAkinobu Mita 2948beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2949c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2950beb40ea4SAkinobu Mita (unsigned long)sector, 2951beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2952beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2953beb40ea4SAkinobu Mita return 0x01; 2954beb40ea4SAkinobu Mita } 29558475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 2956beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2957c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2958c1287970STomas Winkler (unsigned long)sector); 2959beb40ea4SAkinobu Mita return 0x03; 2960beb40ea4SAkinobu Mita } 29618475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2962beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2963c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2964c1287970STomas Winkler (unsigned long)sector); 2965beb40ea4SAkinobu Mita return 0x03; 2966beb40ea4SAkinobu Mita } 2967beb40ea4SAkinobu Mita return 0; 2968beb40ea4SAkinobu Mita } 2969beb40ea4SAkinobu Mita 297087c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 297165f72f2aSAkinobu Mita unsigned int sectors, bool read) 2972c6a44287SMartin K. Petersen { 2973be4e11beSAkinobu Mita size_t resid; 2974c6a44287SMartin K. Petersen void *paddr; 297587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 297687c715dcSDouglas Gilbert scp->device->hostdata); 297787c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 297814faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2979be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2980c6a44287SMartin K. Petersen 2981e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2982e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2983c6a44287SMartin K. Petersen 298487c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 298587c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 2986be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2987be4e11beSAkinobu Mita 2988be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 298987c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 299087c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 2991be4e11beSAkinobu Mita size_t rest = 0; 299214faa944SAkinobu Mita 299314faa944SAkinobu Mita if (dif_store_end < start + len) 299414faa944SAkinobu Mita rest = start + len - dif_store_end; 2995c6a44287SMartin K. Petersen 2996be4e11beSAkinobu Mita paddr = miter.addr; 299714faa944SAkinobu Mita 299865f72f2aSAkinobu Mita if (read) 299965f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 300065f72f2aSAkinobu Mita else 300165f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 300265f72f2aSAkinobu Mita 300365f72f2aSAkinobu Mita if (rest) { 300465f72f2aSAkinobu Mita if (read) 300514faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 300665f72f2aSAkinobu Mita else 300765f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 300865f72f2aSAkinobu Mita } 3009c6a44287SMartin K. Petersen 3010e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3011c6a44287SMartin K. Petersen resid -= len; 3012c6a44287SMartin K. Petersen } 3013be4e11beSAkinobu Mita sg_miter_stop(&miter); 3014bb8c063cSAkinobu Mita } 3015c6a44287SMartin K. Petersen 301687c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3017bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3018bb8c063cSAkinobu Mita { 3019bb8c063cSAkinobu Mita unsigned int i; 3020bb8c063cSAkinobu Mita sector_t sector; 302187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 302287c715dcSDouglas Gilbert scp->device->hostdata); 302387c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3024bb8c063cSAkinobu Mita 3025c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3026bb8c063cSAkinobu Mita int ret; 3027bb8c063cSAkinobu Mita 3028bb8c063cSAkinobu Mita sector = start_sec + i; 302987c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3030bb8c063cSAkinobu Mita 303151d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3032bb8c063cSAkinobu Mita continue; 3033bb8c063cSAkinobu Mita 303487c715dcSDouglas Gilbert ret = dif_verify(sdt, lba2fake_store(sip, sector), sector, 303587c715dcSDouglas Gilbert ei_lba); 3036bb8c063cSAkinobu Mita if (ret) { 3037bb8c063cSAkinobu Mita dif_errors++; 3038bb8c063cSAkinobu Mita return ret; 3039bb8c063cSAkinobu Mita } 3040bb8c063cSAkinobu Mita } 3041bb8c063cSAkinobu Mita 304287c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3043c6a44287SMartin K. Petersen dix_reads++; 3044c6a44287SMartin K. Petersen 3045c6a44287SMartin K. Petersen return 0; 3046c6a44287SMartin K. Petersen } 3047c6a44287SMartin K. Petersen 3048fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 304919789100SFUJITA Tomonori { 305087c715dcSDouglas Gilbert bool check_prot; 3051c2248fc9SDouglas Gilbert u32 num; 3052c2248fc9SDouglas Gilbert u32 ei_lba; 305319789100SFUJITA Tomonori int ret; 305487c715dcSDouglas Gilbert u64 lba; 305587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 305687c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 305787c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 305887c715dcSDouglas Gilbert struct sdebug_queued_cmd *sqcp; 305919789100SFUJITA Tomonori 3060c2248fc9SDouglas Gilbert switch (cmd[0]) { 3061c2248fc9SDouglas Gilbert case READ_16: 3062c2248fc9SDouglas Gilbert ei_lba = 0; 3063c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3064c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3065c2248fc9SDouglas Gilbert check_prot = true; 3066c2248fc9SDouglas Gilbert break; 3067c2248fc9SDouglas Gilbert case READ_10: 3068c2248fc9SDouglas Gilbert ei_lba = 0; 3069c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3070c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3071c2248fc9SDouglas Gilbert check_prot = true; 3072c2248fc9SDouglas Gilbert break; 3073c2248fc9SDouglas Gilbert case READ_6: 3074c2248fc9SDouglas Gilbert ei_lba = 0; 3075c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3076c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3077c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3078c2248fc9SDouglas Gilbert check_prot = true; 3079c2248fc9SDouglas Gilbert break; 3080c2248fc9SDouglas Gilbert case READ_12: 3081c2248fc9SDouglas Gilbert ei_lba = 0; 3082c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3083c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3084c2248fc9SDouglas Gilbert check_prot = true; 3085c2248fc9SDouglas Gilbert break; 3086c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3087c2248fc9SDouglas Gilbert ei_lba = 0; 3088c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3089c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3090c2248fc9SDouglas Gilbert check_prot = false; 3091c2248fc9SDouglas Gilbert break; 3092c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3093c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3094c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3095c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3096c2248fc9SDouglas Gilbert check_prot = false; 3097c2248fc9SDouglas Gilbert break; 3098c2248fc9SDouglas Gilbert } 3099f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 31008475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3101c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3102c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3103c2248fc9SDouglas Gilbert return check_condition_result; 3104c2248fc9SDouglas Gilbert } 31058475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31068475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3107c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3108c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3109c2248fc9SDouglas Gilbert "to DIF device\n"); 3110c2248fc9SDouglas Gilbert } 3111f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3112c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 3113c2248fc9SDouglas Gilbert 3114c4837394SDouglas Gilbert if (sqcp) { 3115c4837394SDouglas Gilbert if (sqcp->inj_short) 3116c2248fc9SDouglas Gilbert num /= 2; 3117c2248fc9SDouglas Gilbert } 3118c4837394SDouglas Gilbert } else 3119c4837394SDouglas Gilbert sqcp = NULL; 3120c2248fc9SDouglas Gilbert 31219447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 31229447b6ceSMartin K. Petersen if (ret) 31239447b6ceSMartin K. Petersen return ret; 3124f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3125d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3126d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3127c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3128c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3129c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3130c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3131c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 313232f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 313332f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3134c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3135c65b1445SDouglas Gilbert } 3136c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 31371da177e4SLinus Torvalds return check_condition_result; 31381da177e4SLinus Torvalds } 3139c6a44287SMartin K. Petersen 314067da413fSDouglas Gilbert read_lock(macc_lckp); 31416c78cc06SAkinobu Mita 3142c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3143f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3144c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 3145c6a44287SMartin K. Petersen 3146c6a44287SMartin K. Petersen if (prot_ret) { 314767da413fSDouglas Gilbert read_unlock(macc_lckp); 3148c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 3149c6a44287SMartin K. Petersen return illegal_condition_result; 3150c6a44287SMartin K. Petersen } 3151c6a44287SMartin K. Petersen } 3152c6a44287SMartin K. Petersen 315387c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 315467da413fSDouglas Gilbert read_unlock(macc_lckp); 3155f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3156a4517511SAkinobu Mita return DID_ERROR << 16; 3157a4517511SAkinobu Mita 315842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3159a4517511SAkinobu Mita 3160c4837394SDouglas Gilbert if (unlikely(sqcp)) { 3161c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3162c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3163c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3164c2248fc9SDouglas Gilbert return check_condition_result; 3165c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 3166c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 3167c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 3168c2248fc9SDouglas Gilbert return check_condition_result; 3169c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3170c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3171c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3172c2248fc9SDouglas Gilbert return illegal_condition_result; 3173c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3174c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3175c2248fc9SDouglas Gilbert return illegal_condition_result; 3176c2248fc9SDouglas Gilbert } 3177c2248fc9SDouglas Gilbert } 3178a4517511SAkinobu Mita return 0; 31791da177e4SLinus Torvalds } 31801da177e4SLinus Torvalds 318158a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 3182c6a44287SMartin K. Petersen { 3183cbf67842SDouglas Gilbert int i, j, n; 3184c6a44287SMartin K. Petersen 3185cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 3186c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 3187cbf67842SDouglas Gilbert char b[128]; 3188c6a44287SMartin K. Petersen 3189cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 3190c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 3191c6a44287SMartin K. Petersen 3192cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 3193cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 3194cbf67842SDouglas Gilbert " %c ", buf[i+j]); 3195cbf67842SDouglas Gilbert else 3196cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 3197cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 3198cbf67842SDouglas Gilbert } 3199cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 3200c6a44287SMartin K. Petersen } 3201c6a44287SMartin K. Petersen } 3202c6a44287SMartin K. Petersen 3203c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3204395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3205c6a44287SMartin K. Petersen { 3206be4e11beSAkinobu Mita int ret; 32076ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3208be4e11beSAkinobu Mita void *daddr; 320965f72f2aSAkinobu Mita sector_t sector = start_sec; 3210c6a44287SMartin K. Petersen int ppage_offset; 3211be4e11beSAkinobu Mita int dpage_offset; 3212be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3213be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3214c6a44287SMartin K. Petersen 3215c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3216c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3217c6a44287SMartin K. Petersen 3218be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3219be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3220be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3221be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3222be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3223c6a44287SMartin K. Petersen 3224be4e11beSAkinobu Mita /* For each protection page */ 3225be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3226be4e11beSAkinobu Mita dpage_offset = 0; 3227be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3228be4e11beSAkinobu Mita ret = 0x01; 3229be4e11beSAkinobu Mita goto out; 3230c6a44287SMartin K. Petersen } 3231c6a44287SMartin K. Petersen 3232be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 32336ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3234be4e11beSAkinobu Mita /* If we're at the end of the current 3235be4e11beSAkinobu Mita * data page advance to the next one 3236be4e11beSAkinobu Mita */ 3237be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3238be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3239be4e11beSAkinobu Mita ret = 0x01; 3240be4e11beSAkinobu Mita goto out; 3241be4e11beSAkinobu Mita } 3242be4e11beSAkinobu Mita dpage_offset = 0; 3243be4e11beSAkinobu Mita } 3244c6a44287SMartin K. Petersen 3245be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3246be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3247be4e11beSAkinobu Mita 3248be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3249beb40ea4SAkinobu Mita if (ret) { 3250773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 3251395cef03SMartin K. Petersen goto out; 3252395cef03SMartin K. Petersen } 3253395cef03SMartin K. Petersen 3254c6a44287SMartin K. Petersen sector++; 3255395cef03SMartin K. Petersen ei_lba++; 3256773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3257c6a44287SMartin K. Petersen } 3258be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3259be4e11beSAkinobu Mita sg_miter_stop(&diter); 3260c6a44287SMartin K. Petersen } 3261be4e11beSAkinobu Mita sg_miter_stop(&piter); 3262c6a44287SMartin K. Petersen 326365f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3264c6a44287SMartin K. Petersen dix_writes++; 3265c6a44287SMartin K. Petersen 3266c6a44287SMartin K. Petersen return 0; 3267c6a44287SMartin K. Petersen 3268c6a44287SMartin K. Petersen out: 3269c6a44287SMartin K. Petersen dif_errors++; 3270be4e11beSAkinobu Mita sg_miter_stop(&diter); 3271be4e11beSAkinobu Mita sg_miter_stop(&piter); 3272c6a44287SMartin K. Petersen return ret; 3273c6a44287SMartin K. Petersen } 3274c6a44287SMartin K. Petersen 3275b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3276b90ebc3dSAkinobu Mita { 3277773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3278773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3279773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3280b90ebc3dSAkinobu Mita return lba; 3281b90ebc3dSAkinobu Mita } 3282b90ebc3dSAkinobu Mita 3283b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3284b90ebc3dSAkinobu Mita { 3285773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3286a027b5b9SAkinobu Mita 3287773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3288773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3289a027b5b9SAkinobu Mita return lba; 3290a027b5b9SAkinobu Mita } 3291a027b5b9SAkinobu Mita 329287c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 329387c715dcSDouglas Gilbert unsigned int *num) 329444d92694SMartin K. Petersen { 3295b90ebc3dSAkinobu Mita sector_t end; 3296b90ebc3dSAkinobu Mita unsigned int mapped; 3297b90ebc3dSAkinobu Mita unsigned long index; 3298b90ebc3dSAkinobu Mita unsigned long next; 329944d92694SMartin K. Petersen 3300b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 330187c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 330244d92694SMartin K. Petersen 330344d92694SMartin K. Petersen if (mapped) 330487c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 330544d92694SMartin K. Petersen else 330687c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 330744d92694SMartin K. Petersen 3308b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 330944d92694SMartin K. Petersen *num = end - lba; 331044d92694SMartin K. Petersen return mapped; 331144d92694SMartin K. Petersen } 331244d92694SMartin K. Petersen 331387c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 331487c715dcSDouglas Gilbert unsigned int len) 331544d92694SMartin K. Petersen { 331644d92694SMartin K. Petersen sector_t end = lba + len; 331744d92694SMartin K. Petersen 331844d92694SMartin K. Petersen while (lba < end) { 3319b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 332044d92694SMartin K. Petersen 3321b90ebc3dSAkinobu Mita if (index < map_size) 332287c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 332344d92694SMartin K. Petersen 3324b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 332544d92694SMartin K. Petersen } 332644d92694SMartin K. Petersen } 332744d92694SMartin K. Petersen 332887c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 332987c715dcSDouglas Gilbert unsigned int len) 333044d92694SMartin K. Petersen { 333144d92694SMartin K. Petersen sector_t end = lba + len; 333287c715dcSDouglas Gilbert u8 *fsp = sip->storep; 333344d92694SMartin K. Petersen 333444d92694SMartin K. Petersen while (lba < end) { 3335b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 333644d92694SMartin K. Petersen 3337b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3338773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3339b90ebc3dSAkinobu Mita index < map_size) { 334087c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3341760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 334287c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3343760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3344773642d9SDouglas Gilbert sdebug_sector_size * 3345773642d9SDouglas Gilbert sdebug_unmap_granularity); 3346be1dd78dSEric Sandeen } 334787c715dcSDouglas Gilbert if (sip->dif_storep) { 334887c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 334987c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3350773642d9SDouglas Gilbert sdebug_unmap_granularity); 3351e9926b43SAkinobu Mita } 3352b90ebc3dSAkinobu Mita } 3353b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 335444d92694SMartin K. Petersen } 335544d92694SMartin K. Petersen } 335644d92694SMartin K. Petersen 3357fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 33581da177e4SLinus Torvalds { 335987c715dcSDouglas Gilbert bool check_prot; 3360c2248fc9SDouglas Gilbert u32 num; 3361c2248fc9SDouglas Gilbert u32 ei_lba; 336219789100SFUJITA Tomonori int ret; 336387c715dcSDouglas Gilbert u64 lba; 336487c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 336587c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 336687c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 33671da177e4SLinus Torvalds 3368c2248fc9SDouglas Gilbert switch (cmd[0]) { 3369c2248fc9SDouglas Gilbert case WRITE_16: 3370c2248fc9SDouglas Gilbert ei_lba = 0; 3371c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3372c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3373c2248fc9SDouglas Gilbert check_prot = true; 3374c2248fc9SDouglas Gilbert break; 3375c2248fc9SDouglas Gilbert case WRITE_10: 3376c2248fc9SDouglas Gilbert ei_lba = 0; 3377c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3378c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3379c2248fc9SDouglas Gilbert check_prot = true; 3380c2248fc9SDouglas Gilbert break; 3381c2248fc9SDouglas Gilbert case WRITE_6: 3382c2248fc9SDouglas Gilbert ei_lba = 0; 3383c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3384c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3385c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3386c2248fc9SDouglas Gilbert check_prot = true; 3387c2248fc9SDouglas Gilbert break; 3388c2248fc9SDouglas Gilbert case WRITE_12: 3389c2248fc9SDouglas Gilbert ei_lba = 0; 3390c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3391c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3392c2248fc9SDouglas Gilbert check_prot = true; 3393c2248fc9SDouglas Gilbert break; 3394c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3395c2248fc9SDouglas Gilbert ei_lba = 0; 3396c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3397c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3398c2248fc9SDouglas Gilbert check_prot = false; 3399c2248fc9SDouglas Gilbert break; 3400c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3401c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3402c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3403c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3404c2248fc9SDouglas Gilbert check_prot = false; 3405c2248fc9SDouglas Gilbert break; 3406c2248fc9SDouglas Gilbert } 3407f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 34088475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3409c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3410c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3411c2248fc9SDouglas Gilbert return check_condition_result; 3412c2248fc9SDouglas Gilbert } 34138475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 34148475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3415c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3416c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3417c2248fc9SDouglas Gilbert "to DIF device\n"); 3418c2248fc9SDouglas Gilbert } 3419f0d1cf93SDouglas Gilbert 342067da413fSDouglas Gilbert write_lock(macc_lckp); 3421f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3422f0d1cf93SDouglas Gilbert if (ret) { 3423f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3424f0d1cf93SDouglas Gilbert return ret; 3425f0d1cf93SDouglas Gilbert } 34266c78cc06SAkinobu Mita 3427c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3428f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3429c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 3430c6a44287SMartin K. Petersen 3431c6a44287SMartin K. Petersen if (prot_ret) { 343267da413fSDouglas Gilbert write_unlock(macc_lckp); 3433c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 3434c6a44287SMartin K. Petersen return illegal_condition_result; 3435c6a44287SMartin K. Petersen } 3436c6a44287SMartin K. Petersen } 3437c6a44287SMartin K. Petersen 343887c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3439f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 344087c715dcSDouglas Gilbert map_region(sip, lba, num); 3441f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3442f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3443f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 344467da413fSDouglas Gilbert write_unlock(macc_lckp); 3445f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3446773642d9SDouglas Gilbert return DID_ERROR << 16; 3447c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3448c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3449c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3450cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3451773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 345244d92694SMartin K. Petersen 3453f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3454c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3455c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3456c2248fc9SDouglas Gilbert 3457c4837394SDouglas Gilbert if (sqcp) { 3458c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3459c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3460c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3461c2248fc9SDouglas Gilbert return check_condition_result; 3462c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3463c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3464c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3465c2248fc9SDouglas Gilbert return illegal_condition_result; 3466c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3467c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3468c2248fc9SDouglas Gilbert return illegal_condition_result; 3469c2248fc9SDouglas Gilbert } 3470c2248fc9SDouglas Gilbert } 3471c4837394SDouglas Gilbert } 34721da177e4SLinus Torvalds return 0; 34731da177e4SLinus Torvalds } 34741da177e4SLinus Torvalds 3475481b5e5cSDouglas Gilbert /* 3476481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3477481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3478481b5e5cSDouglas Gilbert */ 3479481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3480481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3481481b5e5cSDouglas Gilbert { 3482481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3483481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3484481b5e5cSDouglas Gilbert u8 *up; 348587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 348687c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 3487481b5e5cSDouglas Gilbert u8 wrprotect; 3488481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3489481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3490481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3491481b5e5cSDouglas Gilbert u32 ei_lba; 3492481b5e5cSDouglas Gilbert u64 lba; 3493481b5e5cSDouglas Gilbert int ret, res; 3494481b5e5cSDouglas Gilbert bool is_16; 3495481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3496481b5e5cSDouglas Gilbert 3497481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3498481b5e5cSDouglas Gilbert is_16 = false; 3499481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3500481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3501481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3502481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3503481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3504481b5e5cSDouglas Gilbert is_16 = true; 3505481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3506481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3507481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3508481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3509481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3510481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3511481b5e5cSDouglas Gilbert wrprotect) { 3512481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3513481b5e5cSDouglas Gilbert return illegal_condition_result; 3514481b5e5cSDouglas Gilbert } 3515481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3516481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3517481b5e5cSDouglas Gilbert wrprotect == 0) 3518481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3519481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3520481b5e5cSDouglas Gilbert } 3521481b5e5cSDouglas Gilbert } 3522481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3523481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3524481b5e5cSDouglas Gilbert if (lbdof == 0) { 3525481b5e5cSDouglas Gilbert if (sdebug_verbose) 3526481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3527481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3528481b5e5cSDouglas Gilbert my_name, __func__); 3529481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3530481b5e5cSDouglas Gilbert return illegal_condition_result; 3531481b5e5cSDouglas Gilbert } 3532481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3533481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3534481b5e5cSDouglas Gilbert if (sdebug_verbose) 3535481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3536481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3537481b5e5cSDouglas Gilbert my_name, __func__); 3538481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3539481b5e5cSDouglas Gilbert return illegal_condition_result; 3540481b5e5cSDouglas Gilbert } 3541481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3542481b5e5cSDouglas Gilbert if (lrdp == NULL) 3543481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3544481b5e5cSDouglas Gilbert if (sdebug_verbose) 3545481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3546481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3547481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3548481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3549481b5e5cSDouglas Gilbert if (res == -1) { 3550481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3551481b5e5cSDouglas Gilbert goto err_out; 3552481b5e5cSDouglas Gilbert } 3553481b5e5cSDouglas Gilbert 355467da413fSDouglas Gilbert write_lock(macc_lckp); 3555481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3556481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3557481b5e5cSDouglas Gilbert cum_lb = 0; 3558481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3559481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3560481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3561481b5e5cSDouglas Gilbert if (sdebug_verbose) 3562481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3563481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3564481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3565481b5e5cSDouglas Gilbert if (num == 0) 3566481b5e5cSDouglas Gilbert continue; 35679447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3568481b5e5cSDouglas Gilbert if (ret) 3569481b5e5cSDouglas Gilbert goto err_out_unlock; 3570481b5e5cSDouglas Gilbert num_by = num * lb_size; 3571481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3572481b5e5cSDouglas Gilbert 3573481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3574481b5e5cSDouglas Gilbert if (sdebug_verbose) 3575481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3576481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3577481b5e5cSDouglas Gilbert my_name, __func__); 3578481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3579481b5e5cSDouglas Gilbert 0); 3580481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3581481b5e5cSDouglas Gilbert goto err_out_unlock; 3582481b5e5cSDouglas Gilbert } 3583481b5e5cSDouglas Gilbert 3584481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3585481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3586481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3587481b5e5cSDouglas Gilbert ei_lba); 3588481b5e5cSDouglas Gilbert 3589481b5e5cSDouglas Gilbert if (prot_ret) { 3590481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3591481b5e5cSDouglas Gilbert prot_ret); 3592481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3593481b5e5cSDouglas Gilbert goto err_out_unlock; 3594481b5e5cSDouglas Gilbert } 3595481b5e5cSDouglas Gilbert } 3596481b5e5cSDouglas Gilbert 359787c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3598f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3599f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3600f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3601481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 360287c715dcSDouglas Gilbert map_region(sip, lba, num); 3603481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3604481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3605481b5e5cSDouglas Gilbert goto err_out_unlock; 3606481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3607481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3608481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3609481b5e5cSDouglas Gilbert my_name, num_by, ret); 3610481b5e5cSDouglas Gilbert 3611481b5e5cSDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3612481b5e5cSDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3613481b5e5cSDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3614481b5e5cSDouglas Gilbert 3615481b5e5cSDouglas Gilbert if (sqcp) { 3616481b5e5cSDouglas Gilbert if (sqcp->inj_recovered) { 3617481b5e5cSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3618481b5e5cSDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3619481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3620481b5e5cSDouglas Gilbert goto err_out_unlock; 3621481b5e5cSDouglas Gilbert } else if (sqcp->inj_dif) { 3622481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 3623481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 3624481b5e5cSDouglas Gilbert 0x10, 1); 3625481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3626481b5e5cSDouglas Gilbert goto err_out_unlock; 3627481b5e5cSDouglas Gilbert } else if (sqcp->inj_dix) { 3628481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 3629481b5e5cSDouglas Gilbert 0x10, 1); 3630481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3631481b5e5cSDouglas Gilbert goto err_out_unlock; 3632481b5e5cSDouglas Gilbert } 3633481b5e5cSDouglas Gilbert } 3634481b5e5cSDouglas Gilbert } 3635481b5e5cSDouglas Gilbert sg_off += num_by; 3636481b5e5cSDouglas Gilbert cum_lb += num; 3637481b5e5cSDouglas Gilbert } 3638481b5e5cSDouglas Gilbert ret = 0; 3639481b5e5cSDouglas Gilbert err_out_unlock: 364067da413fSDouglas Gilbert write_unlock(macc_lckp); 3641481b5e5cSDouglas Gilbert err_out: 3642481b5e5cSDouglas Gilbert kfree(lrdp); 3643481b5e5cSDouglas Gilbert return ret; 3644481b5e5cSDouglas Gilbert } 3645481b5e5cSDouglas Gilbert 3646fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3647fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 364844d92694SMartin K. Petersen { 3649f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3650f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 365144d92694SMartin K. Petersen unsigned long long i; 365240d07b52SDouglas Gilbert u64 block, lbaa; 365387c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 365487c715dcSDouglas Gilbert int ret; 365587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 365687c715dcSDouglas Gilbert scp->device->hostdata); 365787c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 365840d07b52SDouglas Gilbert u8 *fs1p; 365987c715dcSDouglas Gilbert u8 *fsp; 366044d92694SMartin K. Petersen 366167da413fSDouglas Gilbert write_lock(macc_lckp); 366244d92694SMartin K. Petersen 3663f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3664f0d1cf93SDouglas Gilbert if (ret) { 3665f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3666f0d1cf93SDouglas Gilbert return ret; 3667f0d1cf93SDouglas Gilbert } 3668f0d1cf93SDouglas Gilbert 36699ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 367087c715dcSDouglas Gilbert unmap_region(sip, lba, num); 367144d92694SMartin K. Petersen goto out; 367244d92694SMartin K. Petersen } 367340d07b52SDouglas Gilbert lbaa = lba; 367440d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3675c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 367687c715dcSDouglas Gilbert fsp = sip->storep; 367787c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3678c2248fc9SDouglas Gilbert if (ndob) { 367940d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3680c2248fc9SDouglas Gilbert ret = 0; 3681c2248fc9SDouglas Gilbert } else 368240d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 368344d92694SMartin K. Petersen 368444d92694SMartin K. Petersen if (-1 == ret) { 368567da413fSDouglas Gilbert write_unlock(&sip->macc_lck); 3686773642d9SDouglas Gilbert return DID_ERROR << 16; 368740d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3688c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3689e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 369040d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 369144d92694SMartin K. Petersen 369244d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 369340d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 369440d07b52SDouglas Gilbert lbaa = lba + i; 369540d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 369687c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 369740d07b52SDouglas Gilbert } 36989ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 369987c715dcSDouglas Gilbert map_region(sip, lba, num); 3700f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3701f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3702f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 370344d92694SMartin K. Petersen out: 370467da413fSDouglas Gilbert write_unlock(macc_lckp); 370544d92694SMartin K. Petersen 370644d92694SMartin K. Petersen return 0; 370744d92694SMartin K. Petersen } 370844d92694SMartin K. Petersen 3709fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3710fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3711c2248fc9SDouglas Gilbert { 3712c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3713c2248fc9SDouglas Gilbert u32 lba; 3714c2248fc9SDouglas Gilbert u16 num; 3715c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3716c2248fc9SDouglas Gilbert bool unmap = false; 3717c2248fc9SDouglas Gilbert 3718c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3719773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3720c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3721c2248fc9SDouglas Gilbert return check_condition_result; 3722c2248fc9SDouglas Gilbert } else 3723c2248fc9SDouglas Gilbert unmap = true; 3724c2248fc9SDouglas Gilbert } 3725c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3726c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3727773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3728c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3729c2248fc9SDouglas Gilbert return check_condition_result; 3730c2248fc9SDouglas Gilbert } 3731c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3732c2248fc9SDouglas Gilbert } 3733c2248fc9SDouglas Gilbert 3734fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3735fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3736c2248fc9SDouglas Gilbert { 3737c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3738c2248fc9SDouglas Gilbert u64 lba; 3739c2248fc9SDouglas Gilbert u32 num; 3740c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3741c2248fc9SDouglas Gilbert bool unmap = false; 3742c2248fc9SDouglas Gilbert bool ndob = false; 3743c2248fc9SDouglas Gilbert 3744c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3745773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3746c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3747c2248fc9SDouglas Gilbert return check_condition_result; 3748c2248fc9SDouglas Gilbert } else 3749c2248fc9SDouglas Gilbert unmap = true; 3750c2248fc9SDouglas Gilbert } 3751c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3752c2248fc9SDouglas Gilbert ndob = true; 3753c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3754c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3755773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3756c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3757c2248fc9SDouglas Gilbert return check_condition_result; 3758c2248fc9SDouglas Gilbert } 3759c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3760c2248fc9SDouglas Gilbert } 3761c2248fc9SDouglas Gilbert 3762acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3763acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3764acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3765fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3766fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3767acafd0b9SEwan D. Milne { 3768acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3769acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3770acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3771acafd0b9SEwan D. Milne u8 mode; 3772acafd0b9SEwan D. Milne 3773acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3774acafd0b9SEwan D. Milne switch (mode) { 3775acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3776acafd0b9SEwan D. Milne /* set UAs on this device only */ 3777acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3778acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3779acafd0b9SEwan D. Milne break; 3780acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3781acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3782acafd0b9SEwan D. Milne break; 3783acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3784acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3785acafd0b9SEwan D. Milne list_for_each_entry(dp, 3786acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3787acafd0b9SEwan D. Milne dev_list) 3788acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3789acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3790acafd0b9SEwan D. Milne if (devip != dp) 3791acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3792acafd0b9SEwan D. Milne dp->uas_bm); 3793acafd0b9SEwan D. Milne } 3794acafd0b9SEwan D. Milne break; 3795acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3796acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3797acafd0b9SEwan D. Milne list_for_each_entry(dp, 3798acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3799acafd0b9SEwan D. Milne dev_list) 3800acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3801acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3802acafd0b9SEwan D. Milne dp->uas_bm); 3803acafd0b9SEwan D. Milne break; 3804acafd0b9SEwan D. Milne default: 3805acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3806acafd0b9SEwan D. Milne break; 3807acafd0b9SEwan D. Milne } 3808acafd0b9SEwan D. Milne return 0; 3809acafd0b9SEwan D. Milne } 3810acafd0b9SEwan D. Milne 3811fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3812fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 381338d5c833SDouglas Gilbert { 381438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 381538d5c833SDouglas Gilbert u8 *arr; 381687c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 381787c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 381838d5c833SDouglas Gilbert u64 lba; 381938d5c833SDouglas Gilbert u32 dnum; 3820773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 382138d5c833SDouglas Gilbert u8 num; 382238d5c833SDouglas Gilbert int ret; 3823d467d31fSDouglas Gilbert int retval = 0; 382438d5c833SDouglas Gilbert 3825d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 382638d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 382738d5c833SDouglas Gilbert if (0 == num) 382838d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 38298475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 383038d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 383138d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 383238d5c833SDouglas Gilbert return check_condition_result; 383338d5c833SDouglas Gilbert } 38348475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 38358475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 383638d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 383738d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 383838d5c833SDouglas Gilbert "to DIF device\n"); 38399447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 38409447b6ceSMartin K. Petersen if (ret) 38419447b6ceSMartin K. Petersen return ret; 3842d467d31fSDouglas Gilbert dnum = 2 * num; 38436396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 3844d467d31fSDouglas Gilbert if (NULL == arr) { 3845d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3846d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3847d467d31fSDouglas Gilbert return check_condition_result; 3848d467d31fSDouglas Gilbert } 384938d5c833SDouglas Gilbert 385067da413fSDouglas Gilbert write_lock(macc_lckp); 385138d5c833SDouglas Gilbert 385287c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 385338d5c833SDouglas Gilbert if (ret == -1) { 3854d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3855d467d31fSDouglas Gilbert goto cleanup; 3856773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 385738d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 385838d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 385938d5c833SDouglas Gilbert dnum * lb_size, ret); 3860c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 386138d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3862d467d31fSDouglas Gilbert retval = check_condition_result; 3863d467d31fSDouglas Gilbert goto cleanup; 386438d5c833SDouglas Gilbert } 386538d5c833SDouglas Gilbert if (scsi_debug_lbp()) 386687c715dcSDouglas Gilbert map_region(sip, lba, num); 3867d467d31fSDouglas Gilbert cleanup: 386867da413fSDouglas Gilbert write_unlock(macc_lckp); 3869d467d31fSDouglas Gilbert kfree(arr); 3870d467d31fSDouglas Gilbert return retval; 387138d5c833SDouglas Gilbert } 387238d5c833SDouglas Gilbert 387344d92694SMartin K. Petersen struct unmap_block_desc { 387444d92694SMartin K. Petersen __be64 lba; 387544d92694SMartin K. Petersen __be32 blocks; 387644d92694SMartin K. Petersen __be32 __reserved; 387744d92694SMartin K. Petersen }; 387844d92694SMartin K. Petersen 3879fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 388044d92694SMartin K. Petersen { 388144d92694SMartin K. Petersen unsigned char *buf; 388244d92694SMartin K. Petersen struct unmap_block_desc *desc; 388387c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 388487c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 388544d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 388644d92694SMartin K. Petersen int ret; 388744d92694SMartin K. Petersen 3888c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3889c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3890c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3891c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 389244d92694SMartin K. Petersen 389344d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3894773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3895c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 389644d92694SMartin K. Petersen return check_condition_result; 3897c2248fc9SDouglas Gilbert } 389844d92694SMartin K. Petersen 3899b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3900c2248fc9SDouglas Gilbert if (!buf) { 3901c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3902c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3903c2248fc9SDouglas Gilbert return check_condition_result; 3904c2248fc9SDouglas Gilbert } 3905c2248fc9SDouglas Gilbert 3906c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 390744d92694SMartin K. Petersen 390844d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 390944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 391044d92694SMartin K. Petersen 391144d92694SMartin K. Petersen desc = (void *)&buf[8]; 391244d92694SMartin K. Petersen 391367da413fSDouglas Gilbert write_lock(macc_lckp); 39146c78cc06SAkinobu Mita 391544d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 391644d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 391744d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 391844d92694SMartin K. Petersen 39199447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 392044d92694SMartin K. Petersen if (ret) 392144d92694SMartin K. Petersen goto out; 392244d92694SMartin K. Petersen 392387c715dcSDouglas Gilbert unmap_region(sip, lba, num); 392444d92694SMartin K. Petersen } 392544d92694SMartin K. Petersen 392644d92694SMartin K. Petersen ret = 0; 392744d92694SMartin K. Petersen 392844d92694SMartin K. Petersen out: 392967da413fSDouglas Gilbert write_unlock(macc_lckp); 393044d92694SMartin K. Petersen kfree(buf); 393144d92694SMartin K. Petersen 393244d92694SMartin K. Petersen return ret; 393344d92694SMartin K. Petersen } 393444d92694SMartin K. Petersen 393544d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 393644d92694SMartin K. Petersen 3937fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3938fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 393944d92694SMartin K. Petersen { 3940c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 394187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 3942c2248fc9SDouglas Gilbert u64 lba; 3943c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 394444d92694SMartin K. Petersen int ret; 394587c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 394644d92694SMartin K. Petersen 3947c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3948c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 394944d92694SMartin K. Petersen 395044d92694SMartin K. Petersen if (alloc_len < 24) 395144d92694SMartin K. Petersen return 0; 395244d92694SMartin K. Petersen 39539447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 395444d92694SMartin K. Petersen if (ret) 395544d92694SMartin K. Petersen return ret; 395644d92694SMartin K. Petersen 3957c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 395887c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 3959c2248fc9SDouglas Gilbert else { 3960c2248fc9SDouglas Gilbert mapped = 1; 3961c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3962c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3963c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3964c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3965c2248fc9SDouglas Gilbert else 3966c2248fc9SDouglas Gilbert num = 0xffffffff; 3967c2248fc9SDouglas Gilbert } 396844d92694SMartin K. Petersen 396944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3970c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3971c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3972c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3973c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 397444d92694SMartin K. Petersen 3975c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 397644d92694SMartin K. Petersen } 397744d92694SMartin K. Petersen 397880c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 397980c49563SDouglas Gilbert struct sdebug_dev_info *devip) 398080c49563SDouglas Gilbert { 39814f2c8bf6SDouglas Gilbert int res = 0; 398280c49563SDouglas Gilbert u64 lba; 398380c49563SDouglas Gilbert u32 num_blocks; 398480c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 398580c49563SDouglas Gilbert 398680c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 398780c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 398880c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 398980c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 399080c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 399180c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 399280c49563SDouglas Gilbert } 399380c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 399480c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 399580c49563SDouglas Gilbert return check_condition_result; 399680c49563SDouglas Gilbert } 39974f2c8bf6SDouglas Gilbert if (!write_since_sync || cmd[1] & 0x2) 39984f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 39994f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 40004f2c8bf6SDouglas Gilbert write_since_sync = false; 40014f2c8bf6SDouglas Gilbert return res; 400280c49563SDouglas Gilbert } 400380c49563SDouglas Gilbert 4004ed9f3e25SDouglas Gilbert /* 4005ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4006ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4007ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4008ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4009ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4010ed9f3e25SDouglas Gilbert */ 4011ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4012ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4013ed9f3e25SDouglas Gilbert { 4014ed9f3e25SDouglas Gilbert int res = 0; 4015ed9f3e25SDouglas Gilbert u64 lba; 4016ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4017ed9f3e25SDouglas Gilbert u32 nblks; 4018ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4019ed9f3e25SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4020ed9f3e25SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4021ed9f3e25SDouglas Gilbert u8 *fsp = sip ? sip->storep : NULL; 4022ed9f3e25SDouglas Gilbert 4023ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4024ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4025ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4026ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4027ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4028ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4029ed9f3e25SDouglas Gilbert } 4030ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4031ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4032ed9f3e25SDouglas Gilbert return check_condition_result; 4033ed9f3e25SDouglas Gilbert } 4034ed9f3e25SDouglas Gilbert if (!fsp) 4035ed9f3e25SDouglas Gilbert goto fini; 4036ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4037ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4038ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4039ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4040ed9f3e25SDouglas Gilbert 4041ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 4042ed9f3e25SDouglas Gilbert read_lock(macc_lckp); 4043ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4044ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4045ed9f3e25SDouglas Gilbert if (rest) 4046ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 4047ed9f3e25SDouglas Gilbert read_unlock(macc_lckp); 4048ed9f3e25SDouglas Gilbert fini: 4049ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4050ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4051ed9f3e25SDouglas Gilbert return res | condition_met_result; 4052ed9f3e25SDouglas Gilbert } 4053ed9f3e25SDouglas Gilbert 4054fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4055fb0cc8d1SDouglas Gilbert 40568d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 40578d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 40588d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 40598d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 40608d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 40618d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 40628d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 40638d039e22SDouglas Gilbert */ 40641da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 40651da177e4SLinus Torvalds struct sdebug_dev_info *devip) 40661da177e4SLinus Torvalds { 406701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 40688d039e22SDouglas Gilbert unsigned int alloc_len; 40698d039e22SDouglas Gilbert unsigned char select_report; 40708d039e22SDouglas Gilbert u64 lun; 40718d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4072fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 40738d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 40748d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 40758d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 40768d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4077fb0cc8d1SDouglas Gilbert int k, j, n, res; 4078fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4079fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 40801da177e4SLinus Torvalds 408119c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 40828d039e22SDouglas Gilbert 40838d039e22SDouglas Gilbert select_report = cmd[2]; 40848d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 40858d039e22SDouglas Gilbert 40868d039e22SDouglas Gilbert if (alloc_len < 4) { 40878d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 40888d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 40891da177e4SLinus Torvalds return check_condition_result; 40901da177e4SLinus Torvalds } 40918d039e22SDouglas Gilbert 40928d039e22SDouglas Gilbert switch (select_report) { 40938d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4094773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 40958d039e22SDouglas Gilbert wlun_cnt = 0; 40968d039e22SDouglas Gilbert break; 40978d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4098c65b1445SDouglas Gilbert lun_cnt = 0; 40998d039e22SDouglas Gilbert wlun_cnt = 1; 41008d039e22SDouglas Gilbert break; 41018d039e22SDouglas Gilbert case 2: /* all LUNs */ 41028d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 41038d039e22SDouglas Gilbert wlun_cnt = 1; 41048d039e22SDouglas Gilbert break; 41058d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 41068d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 41078d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 41088d039e22SDouglas Gilbert default: 41098d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 41108d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 41118d039e22SDouglas Gilbert return check_condition_result; 41128d039e22SDouglas Gilbert } 41138d039e22SDouglas Gilbert 41148d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4115c65b1445SDouglas Gilbert --lun_cnt; 41168d039e22SDouglas Gilbert 41178d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4118fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4119fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 41208d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 41218d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 41228d039e22SDouglas Gilbert 4123fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 41248d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4125fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4126fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4127fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4128fb0cc8d1SDouglas Gilbert if (k == 0) { 4129fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4130fb0cc8d1SDouglas Gilbert ++lun_p; 4131fb0cc8d1SDouglas Gilbert j = 1; 4132fb0cc8d1SDouglas Gilbert } 4133fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4134fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4135fb0cc8d1SDouglas Gilbert break; 4136fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4137fb0cc8d1SDouglas Gilbert } 4138fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4139fb0cc8d1SDouglas Gilbert break; 4140fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4141fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4142fb0cc8d1SDouglas Gilbert if (res) 4143fb0cc8d1SDouglas Gilbert return res; 4144fb0cc8d1SDouglas Gilbert off_rsp += n; 4145fb0cc8d1SDouglas Gilbert } 4146fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4147fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4148fb0cc8d1SDouglas Gilbert ++j; 4149fb0cc8d1SDouglas Gilbert } 4150fb0cc8d1SDouglas Gilbert if (j > 0) 4151fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 41528d039e22SDouglas Gilbert return res; 41531da177e4SLinus Torvalds } 41541da177e4SLinus Torvalds 4155c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4156c3e2fe92SDouglas Gilbert { 4157c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4158c3e2fe92SDouglas Gilbert u8 bytchk; 4159c3e2fe92SDouglas Gilbert int ret, j; 4160c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4161c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4162c3e2fe92SDouglas Gilbert u64 lba; 4163c3e2fe92SDouglas Gilbert u8 *arr; 4164c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4165c3e2fe92SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4166c3e2fe92SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4167c3e2fe92SDouglas Gilbert 4168c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4169c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4170c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4171c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4172c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4173c3e2fe92SDouglas Gilbert return check_condition_result; 4174c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4175c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4176c3e2fe92SDouglas Gilbert } 4177c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4178c3e2fe92SDouglas Gilbert case VERIFY_16: 4179c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4180c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4181c3e2fe92SDouglas Gilbert break; 4182c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4183c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4184c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4185c3e2fe92SDouglas Gilbert break; 4186c3e2fe92SDouglas Gilbert default: 4187c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4188c3e2fe92SDouglas Gilbert return check_condition_result; 4189c3e2fe92SDouglas Gilbert } 4190c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4191c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4192c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4193c3e2fe92SDouglas Gilbert if (ret) 4194c3e2fe92SDouglas Gilbert return ret; 4195c3e2fe92SDouglas Gilbert 4196c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4197c3e2fe92SDouglas Gilbert if (!arr) { 4198c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4199c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4200c3e2fe92SDouglas Gilbert return check_condition_result; 4201c3e2fe92SDouglas Gilbert } 4202c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 420367da413fSDouglas Gilbert read_lock(macc_lckp); 4204c3e2fe92SDouglas Gilbert 4205c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4206c3e2fe92SDouglas Gilbert if (ret == -1) { 4207c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4208c3e2fe92SDouglas Gilbert goto cleanup; 4209c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4210c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4211c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4212c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4213c3e2fe92SDouglas Gilbert } 4214c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4215c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4216c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4217c3e2fe92SDouglas Gilbert } 4218c3e2fe92SDouglas Gilbert ret = 0; 4219c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4220c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4221c3e2fe92SDouglas Gilbert ret = check_condition_result; 4222c3e2fe92SDouglas Gilbert goto cleanup; 4223c3e2fe92SDouglas Gilbert } 4224c3e2fe92SDouglas Gilbert cleanup: 422567da413fSDouglas Gilbert read_unlock(macc_lckp); 4226c3e2fe92SDouglas Gilbert kfree(arr); 4227c3e2fe92SDouglas Gilbert return ret; 4228c3e2fe92SDouglas Gilbert } 4229c3e2fe92SDouglas Gilbert 4230f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4231f0d1cf93SDouglas Gilbert 4232f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */ 4233f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4234f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4235f0d1cf93SDouglas Gilbert { 4236f0d1cf93SDouglas Gilbert unsigned int i, max_zones, rep_max_zones, nrz = 0; 4237f0d1cf93SDouglas Gilbert int ret = 0; 4238f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4239f0d1cf93SDouglas Gilbert bool partial; 4240f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4241f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4242f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4243f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4244f0d1cf93SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4245f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4246f0d1cf93SDouglas Gilbert 4247f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4248f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4249f0d1cf93SDouglas Gilbert return check_condition_result; 4250f0d1cf93SDouglas Gilbert } 4251f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4252f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 4253f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4254f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4255f0d1cf93SDouglas Gilbert 4256f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4257f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4258f0d1cf93SDouglas Gilbert return check_condition_result; 4259f0d1cf93SDouglas Gilbert } 4260f0d1cf93SDouglas Gilbert 4261f0d1cf93SDouglas Gilbert max_zones = devip->nr_zones - zs_lba / devip->zsize; 4262f0d1cf93SDouglas Gilbert rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), 4263f0d1cf93SDouglas Gilbert max_zones); 4264f0d1cf93SDouglas Gilbert 4265f0d1cf93SDouglas Gilbert arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC); 4266f0d1cf93SDouglas Gilbert if (!arr) { 4267f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4268f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4269f0d1cf93SDouglas Gilbert return check_condition_result; 4270f0d1cf93SDouglas Gilbert } 4271f0d1cf93SDouglas Gilbert 4272f0d1cf93SDouglas Gilbert read_lock(macc_lckp); 4273f0d1cf93SDouglas Gilbert 4274f0d1cf93SDouglas Gilbert desc = arr + 64; 4275f0d1cf93SDouglas Gilbert for (i = 0; i < max_zones; i++) { 4276f0d1cf93SDouglas Gilbert lba = zs_lba + devip->zsize * i; 4277f0d1cf93SDouglas Gilbert if (lba > sdebug_capacity) 4278f0d1cf93SDouglas Gilbert break; 4279f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4280f0d1cf93SDouglas Gilbert switch (rep_opts) { 4281f0d1cf93SDouglas Gilbert case 0x00: 4282f0d1cf93SDouglas Gilbert /* All zones */ 4283f0d1cf93SDouglas Gilbert break; 4284f0d1cf93SDouglas Gilbert case 0x01: 4285f0d1cf93SDouglas Gilbert /* Empty zones */ 4286f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4287f0d1cf93SDouglas Gilbert continue; 4288f0d1cf93SDouglas Gilbert break; 4289f0d1cf93SDouglas Gilbert case 0x02: 4290f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4291f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4292f0d1cf93SDouglas Gilbert continue; 4293f0d1cf93SDouglas Gilbert break; 4294f0d1cf93SDouglas Gilbert case 0x03: 4295f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4296f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4297f0d1cf93SDouglas Gilbert continue; 4298f0d1cf93SDouglas Gilbert break; 4299f0d1cf93SDouglas Gilbert case 0x04: 4300f0d1cf93SDouglas Gilbert /* Closed zones */ 4301f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4302f0d1cf93SDouglas Gilbert continue; 4303f0d1cf93SDouglas Gilbert break; 4304f0d1cf93SDouglas Gilbert case 0x05: 4305f0d1cf93SDouglas Gilbert /* Full zones */ 4306f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4307f0d1cf93SDouglas Gilbert continue; 4308f0d1cf93SDouglas Gilbert break; 4309f0d1cf93SDouglas Gilbert case 0x06: 4310f0d1cf93SDouglas Gilbert case 0x07: 4311f0d1cf93SDouglas Gilbert case 0x10: 4312f0d1cf93SDouglas Gilbert case 0x11: 4313f0d1cf93SDouglas Gilbert /* 4314f0d1cf93SDouglas Gilbert * Read-only, offline, reset WP recommended and 4315f0d1cf93SDouglas Gilbert * non-seq-resource-used are not emulated: no zones 4316f0d1cf93SDouglas Gilbert * to report; 4317f0d1cf93SDouglas Gilbert */ 4318f0d1cf93SDouglas Gilbert continue; 4319f0d1cf93SDouglas Gilbert case 0x3f: 4320f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 4321f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp)) 4322f0d1cf93SDouglas Gilbert continue; 4323f0d1cf93SDouglas Gilbert break; 4324f0d1cf93SDouglas Gilbert default: 4325f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4326f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4327f0d1cf93SDouglas Gilbert ret = check_condition_result; 4328f0d1cf93SDouglas Gilbert goto fini; 4329f0d1cf93SDouglas Gilbert } 4330f0d1cf93SDouglas Gilbert 4331f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4332f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 4333f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4334f0d1cf93SDouglas Gilbert desc[0] = 0x1; 4335f0d1cf93SDouglas Gilbert else 4336f0d1cf93SDouglas Gilbert desc[0] = 0x2; 4337f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 4338f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4339f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4340f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4341f0d1cf93SDouglas Gilbert desc += 64; 4342f0d1cf93SDouglas Gilbert } 4343f0d1cf93SDouglas Gilbert 4344f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4345f0d1cf93SDouglas Gilbert break; 4346f0d1cf93SDouglas Gilbert 4347f0d1cf93SDouglas Gilbert nrz++; 4348f0d1cf93SDouglas Gilbert } 4349f0d1cf93SDouglas Gilbert 4350f0d1cf93SDouglas Gilbert /* Report header */ 4351f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 4352f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 4353f0d1cf93SDouglas Gilbert 4354f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 4355f0d1cf93SDouglas Gilbert ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len)); 4356f0d1cf93SDouglas Gilbert 4357f0d1cf93SDouglas Gilbert fini: 4358f0d1cf93SDouglas Gilbert read_unlock(macc_lckp); 4359f0d1cf93SDouglas Gilbert kfree(arr); 4360f0d1cf93SDouglas Gilbert return ret; 4361f0d1cf93SDouglas Gilbert } 4362f0d1cf93SDouglas Gilbert 4363f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4364f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4365f0d1cf93SDouglas Gilbert { 4366f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4367f0d1cf93SDouglas Gilbert unsigned int i; 4368f0d1cf93SDouglas Gilbert 4369f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4370f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4371f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4372f0d1cf93SDouglas Gilbert } 4373f0d1cf93SDouglas Gilbert } 4374f0d1cf93SDouglas Gilbert 4375f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4376f0d1cf93SDouglas Gilbert { 4377f0d1cf93SDouglas Gilbert int res = 0; 4378f0d1cf93SDouglas Gilbert u64 z_id; 4379f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4380f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4381f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4382f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4383f0d1cf93SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4384f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4385f0d1cf93SDouglas Gilbert 4386f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4387f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4388f0d1cf93SDouglas Gilbert return check_condition_result; 4389f0d1cf93SDouglas Gilbert } 4390f0d1cf93SDouglas Gilbert 4391f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4392f0d1cf93SDouglas Gilbert 4393f0d1cf93SDouglas Gilbert if (all) { 4394f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4395f0d1cf93SDouglas Gilbert if (devip->max_open && 4396f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4397f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4398f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4399f0d1cf93SDouglas Gilbert res = check_condition_result; 4400f0d1cf93SDouglas Gilbert goto fini; 4401f0d1cf93SDouglas Gilbert } 4402f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4403f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4404f0d1cf93SDouglas Gilbert goto fini; 4405f0d1cf93SDouglas Gilbert } 4406f0d1cf93SDouglas Gilbert 4407f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4408f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4409f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4410f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4411f0d1cf93SDouglas Gilbert res = check_condition_result; 4412f0d1cf93SDouglas Gilbert goto fini; 4413f0d1cf93SDouglas Gilbert } 4414f0d1cf93SDouglas Gilbert 4415f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4416f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4417f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4418f0d1cf93SDouglas Gilbert res = check_condition_result; 4419f0d1cf93SDouglas Gilbert goto fini; 4420f0d1cf93SDouglas Gilbert } 4421f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4422f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4423f0d1cf93SDouglas Gilbert res = check_condition_result; 4424f0d1cf93SDouglas Gilbert goto fini; 4425f0d1cf93SDouglas Gilbert } 4426f0d1cf93SDouglas Gilbert 4427f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4428f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4429f0d1cf93SDouglas Gilbert goto fini; 4430f0d1cf93SDouglas Gilbert 4431f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4432f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4433f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4434f0d1cf93SDouglas Gilbert res = check_condition_result; 4435f0d1cf93SDouglas Gilbert goto fini; 4436f0d1cf93SDouglas Gilbert } 4437f0d1cf93SDouglas Gilbert 4438f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 4439f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4440f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4441f0d1cf93SDouglas Gilbert fini: 4442f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4443f0d1cf93SDouglas Gilbert return res; 4444f0d1cf93SDouglas Gilbert } 4445f0d1cf93SDouglas Gilbert 4446f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4447f0d1cf93SDouglas Gilbert { 4448f0d1cf93SDouglas Gilbert unsigned int i; 4449f0d1cf93SDouglas Gilbert 4450f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4451f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4452f0d1cf93SDouglas Gilbert } 4453f0d1cf93SDouglas Gilbert 4454f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4455f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4456f0d1cf93SDouglas Gilbert { 4457f0d1cf93SDouglas Gilbert int res = 0; 4458f0d1cf93SDouglas Gilbert u64 z_id; 4459f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4460f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4461f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4462f0d1cf93SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4463f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4464f0d1cf93SDouglas Gilbert 4465f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4466f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4467f0d1cf93SDouglas Gilbert return check_condition_result; 4468f0d1cf93SDouglas Gilbert } 4469f0d1cf93SDouglas Gilbert 4470f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4471f0d1cf93SDouglas Gilbert 4472f0d1cf93SDouglas Gilbert if (all) { 4473f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4474f0d1cf93SDouglas Gilbert goto fini; 4475f0d1cf93SDouglas Gilbert } 4476f0d1cf93SDouglas Gilbert 4477f0d1cf93SDouglas Gilbert /* Close specified zone */ 4478f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4479f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4480f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4481f0d1cf93SDouglas Gilbert res = check_condition_result; 4482f0d1cf93SDouglas Gilbert goto fini; 4483f0d1cf93SDouglas Gilbert } 4484f0d1cf93SDouglas Gilbert 4485f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4486f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4487f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4488f0d1cf93SDouglas Gilbert res = check_condition_result; 4489f0d1cf93SDouglas Gilbert goto fini; 4490f0d1cf93SDouglas Gilbert } 4491f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4492f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4493f0d1cf93SDouglas Gilbert res = check_condition_result; 4494f0d1cf93SDouglas Gilbert goto fini; 4495f0d1cf93SDouglas Gilbert } 4496f0d1cf93SDouglas Gilbert 4497f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4498f0d1cf93SDouglas Gilbert fini: 4499f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4500f0d1cf93SDouglas Gilbert return res; 4501f0d1cf93SDouglas Gilbert } 4502f0d1cf93SDouglas Gilbert 4503f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4504f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4505f0d1cf93SDouglas Gilbert { 4506f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4507f0d1cf93SDouglas Gilbert 4508f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4509f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4510f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4511f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4512f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4513f0d1cf93SDouglas Gilbert devip->nr_closed--; 4514f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4515f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4516f0d1cf93SDouglas Gilbert } 4517f0d1cf93SDouglas Gilbert } 4518f0d1cf93SDouglas Gilbert 4519f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4520f0d1cf93SDouglas Gilbert { 4521f0d1cf93SDouglas Gilbert unsigned int i; 4522f0d1cf93SDouglas Gilbert 4523f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4524f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4525f0d1cf93SDouglas Gilbert } 4526f0d1cf93SDouglas Gilbert 4527f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4528f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4529f0d1cf93SDouglas Gilbert { 4530f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4531f0d1cf93SDouglas Gilbert int res = 0; 4532f0d1cf93SDouglas Gilbert u64 z_id; 4533f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4534f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4535f0d1cf93SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4536f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4537f0d1cf93SDouglas Gilbert 4538f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4539f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4540f0d1cf93SDouglas Gilbert return check_condition_result; 4541f0d1cf93SDouglas Gilbert } 4542f0d1cf93SDouglas Gilbert 4543f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4544f0d1cf93SDouglas Gilbert 4545f0d1cf93SDouglas Gilbert if (all) { 4546f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4547f0d1cf93SDouglas Gilbert goto fini; 4548f0d1cf93SDouglas Gilbert } 4549f0d1cf93SDouglas Gilbert 4550f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4551f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4552f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4553f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4554f0d1cf93SDouglas Gilbert res = check_condition_result; 4555f0d1cf93SDouglas Gilbert goto fini; 4556f0d1cf93SDouglas Gilbert } 4557f0d1cf93SDouglas Gilbert 4558f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4559f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4560f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4561f0d1cf93SDouglas Gilbert res = check_condition_result; 4562f0d1cf93SDouglas Gilbert goto fini; 4563f0d1cf93SDouglas Gilbert } 4564f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4565f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4566f0d1cf93SDouglas Gilbert res = check_condition_result; 4567f0d1cf93SDouglas Gilbert goto fini; 4568f0d1cf93SDouglas Gilbert } 4569f0d1cf93SDouglas Gilbert 4570f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4571f0d1cf93SDouglas Gilbert fini: 4572f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4573f0d1cf93SDouglas Gilbert return res; 4574f0d1cf93SDouglas Gilbert } 4575f0d1cf93SDouglas Gilbert 4576f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4577f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4578f0d1cf93SDouglas Gilbert { 4579f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4580f0d1cf93SDouglas Gilbert 4581f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4582f0d1cf93SDouglas Gilbert return; 4583f0d1cf93SDouglas Gilbert 4584f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4585f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4586f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4587f0d1cf93SDouglas Gilbert 4588f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4589f0d1cf93SDouglas Gilbert devip->nr_closed--; 4590f0d1cf93SDouglas Gilbert 4591f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4592f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4593f0d1cf93SDouglas Gilbert } 4594f0d1cf93SDouglas Gilbert 4595f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4596f0d1cf93SDouglas Gilbert { 4597f0d1cf93SDouglas Gilbert unsigned int i; 4598f0d1cf93SDouglas Gilbert 4599f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4600f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4601f0d1cf93SDouglas Gilbert } 4602f0d1cf93SDouglas Gilbert 4603f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4604f0d1cf93SDouglas Gilbert { 4605f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4606f0d1cf93SDouglas Gilbert int res = 0; 4607f0d1cf93SDouglas Gilbert u64 z_id; 4608f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4609f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4610f0d1cf93SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 4611f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4612f0d1cf93SDouglas Gilbert 4613f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4614f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4615f0d1cf93SDouglas Gilbert return check_condition_result; 4616f0d1cf93SDouglas Gilbert } 4617f0d1cf93SDouglas Gilbert 4618f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4619f0d1cf93SDouglas Gilbert 4620f0d1cf93SDouglas Gilbert if (all) { 4621f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4622f0d1cf93SDouglas Gilbert goto fini; 4623f0d1cf93SDouglas Gilbert } 4624f0d1cf93SDouglas Gilbert 4625f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4626f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4627f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4628f0d1cf93SDouglas Gilbert res = check_condition_result; 4629f0d1cf93SDouglas Gilbert goto fini; 4630f0d1cf93SDouglas Gilbert } 4631f0d1cf93SDouglas Gilbert 4632f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4633f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4634f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4635f0d1cf93SDouglas Gilbert res = check_condition_result; 4636f0d1cf93SDouglas Gilbert goto fini; 4637f0d1cf93SDouglas Gilbert } 4638f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4639f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4640f0d1cf93SDouglas Gilbert res = check_condition_result; 4641f0d1cf93SDouglas Gilbert goto fini; 4642f0d1cf93SDouglas Gilbert } 4643f0d1cf93SDouglas Gilbert 4644f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4645f0d1cf93SDouglas Gilbert fini: 4646f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4647f0d1cf93SDouglas Gilbert return res; 4648f0d1cf93SDouglas Gilbert } 4649f0d1cf93SDouglas Gilbert 4650c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4651c4837394SDouglas Gilbert { 4652c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 4653c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 4654c4837394SDouglas Gilbert 4655458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4656458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4657458df78bSBart Van Assche hwq = 0; 4658458df78bSBart Van Assche return sdebug_q_arr + hwq; 4659c4837394SDouglas Gilbert } 4660c4837394SDouglas Gilbert 4661c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4662fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 46631da177e4SLinus Torvalds { 46647382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4665c4837394SDouglas Gilbert int qc_idx; 4666cbf67842SDouglas Gilbert int retiring = 0; 46671da177e4SLinus Torvalds unsigned long iflags; 4668c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4669cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4670cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4671cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 46721da177e4SLinus Torvalds 467310bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 46747382f9d8SDouglas Gilbert if (unlikely(aborted)) 46757382f9d8SDouglas Gilbert sd_dp->aborted = false; 4676c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4677c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4678c4837394SDouglas Gilbert if (sdebug_statistics) { 4679cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4680c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4681c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4682c4837394SDouglas Gilbert } 4683c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4684c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 46851da177e4SLinus Torvalds return; 46861da177e4SLinus Torvalds } 4687c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4688c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4689cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4690b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4691c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4692c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 4693c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 46941da177e4SLinus Torvalds return; 46951da177e4SLinus Torvalds } 4696cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4697f46eb0e9SDouglas Gilbert if (likely(devip)) 4698cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4699cbf67842SDouglas Gilbert else 4700c1287970STomas Winkler pr_err("devip=NULL\n"); 4701f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4702cbf67842SDouglas Gilbert retiring = 1; 4703cbf67842SDouglas Gilbert 4704cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4705c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4706c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4707c1287970STomas Winkler pr_err("Unexpected completion\n"); 4708cbf67842SDouglas Gilbert return; 47091da177e4SLinus Torvalds } 47101da177e4SLinus Torvalds 4711cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4712cbf67842SDouglas Gilbert int k, retval; 4713cbf67842SDouglas Gilbert 4714cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4715c4837394SDouglas Gilbert if (qc_idx >= retval) { 4716c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4717c1287970STomas Winkler pr_err("index %d too large\n", retval); 4718cbf67842SDouglas Gilbert return; 4719cbf67842SDouglas Gilbert } 4720c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4721773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4722cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4723cbf67842SDouglas Gilbert else 4724cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4725cbf67842SDouglas Gilbert } 4726c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 47277382f9d8SDouglas Gilbert if (unlikely(aborted)) { 47287382f9d8SDouglas Gilbert if (sdebug_verbose) 47297382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 47307382f9d8SDouglas Gilbert return; 47317382f9d8SDouglas Gilbert } 4732cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 4733cbf67842SDouglas Gilbert } 4734cbf67842SDouglas Gilbert 4735cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4736fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4737cbf67842SDouglas Gilbert { 4738a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4739a10bc12aSDouglas Gilbert hrt); 4740a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4741cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4742cbf67842SDouglas Gilbert } 47431da177e4SLinus Torvalds 4744a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4745fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4746a10bc12aSDouglas Gilbert { 4747a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4748a10bc12aSDouglas Gilbert ew.work); 4749a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4750a10bc12aSDouglas Gilbert } 4751a10bc12aSDouglas Gilbert 475209ba24c1SDouglas Gilbert static bool got_shared_uuid; 4753bf476433SChristoph Hellwig static uuid_t shared_uuid; 475409ba24c1SDouglas Gilbert 4755f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 4756f0d1cf93SDouglas Gilbert { 4757f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4758f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 4759f0d1cf93SDouglas Gilbert sector_t zstart = 0; 4760f0d1cf93SDouglas Gilbert unsigned int i; 4761f0d1cf93SDouglas Gilbert 4762f0d1cf93SDouglas Gilbert /* 4763f0d1cf93SDouglas Gilbert * Set the zone size: if zbc_zone_size_mb is not set, figure out a 4764f0d1cf93SDouglas Gilbert * zone size allowing for at least 4 zones on the device. Otherwise, 4765f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 4766f0d1cf93SDouglas Gilbert * created for the device. 4767f0d1cf93SDouglas Gilbert */ 4768f0d1cf93SDouglas Gilbert if (!zbc_zone_size_mb) { 4769f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 4770f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4771f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 4772f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 4773f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 4774f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 4775f0d1cf93SDouglas Gilbert return -EINVAL; 4776f0d1cf93SDouglas Gilbert } 4777f0d1cf93SDouglas Gilbert } else { 4778f0d1cf93SDouglas Gilbert devip->zsize = (zbc_zone_size_mb * SZ_1M) 4779f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4780f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 4781f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 4782f0d1cf93SDouglas Gilbert return -EINVAL; 4783f0d1cf93SDouglas Gilbert } 4784f0d1cf93SDouglas Gilbert } 4785f0d1cf93SDouglas Gilbert 4786f0d1cf93SDouglas Gilbert if (is_power_of_2(devip->zsize)) 4787f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 4788f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 4789f0d1cf93SDouglas Gilbert 4790f0d1cf93SDouglas Gilbert /* zbc_max_open_zones can be 0, meaning "not reported" (no limit) */ 4791f0d1cf93SDouglas Gilbert if (zbc_max_open_zones >= devip->nr_zones - 1) 4792f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 4793f0d1cf93SDouglas Gilbert else 4794f0d1cf93SDouglas Gilbert devip->max_open = zbc_max_open_zones; 4795f0d1cf93SDouglas Gilbert 4796f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 4797f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 4798f0d1cf93SDouglas Gilbert if (!devip->zstate) 4799f0d1cf93SDouglas Gilbert return -ENOMEM; 4800f0d1cf93SDouglas Gilbert 4801f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 4802f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 4803f0d1cf93SDouglas Gilbert 4804f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 4805f0d1cf93SDouglas Gilbert 4806f0d1cf93SDouglas Gilbert if (i == 0) { 4807f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 4808f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 4809f0d1cf93SDouglas Gilbert } else { 4810f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4811f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4812f0d1cf93SDouglas Gilbert } 4813f0d1cf93SDouglas Gilbert 4814f0d1cf93SDouglas Gilbert if (zsp->z_start + devip->zsize < capacity) 4815f0d1cf93SDouglas Gilbert zsp->z_size = devip->zsize; 4816f0d1cf93SDouglas Gilbert else 4817f0d1cf93SDouglas Gilbert zsp->z_size = capacity - zsp->z_start; 4818f0d1cf93SDouglas Gilbert 4819f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 4820f0d1cf93SDouglas Gilbert } 4821f0d1cf93SDouglas Gilbert 4822f0d1cf93SDouglas Gilbert return 0; 4823f0d1cf93SDouglas Gilbert } 4824f0d1cf93SDouglas Gilbert 4825fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 4826fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 48275cb2fc06SFUJITA Tomonori { 48285cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 48295cb2fc06SFUJITA Tomonori 48305cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 48315cb2fc06SFUJITA Tomonori if (devip) { 483209ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 4833bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 483409ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 483509ba24c1SDouglas Gilbert if (got_shared_uuid) 483609ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 483709ba24c1SDouglas Gilbert else { 4838bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 483909ba24c1SDouglas Gilbert got_shared_uuid = true; 484009ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 484109ba24c1SDouglas Gilbert } 484209ba24c1SDouglas Gilbert } 48435cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 4844f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 4845f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 4846f0d1cf93SDouglas Gilbert kfree(devip); 4847f0d1cf93SDouglas Gilbert return NULL; 4848f0d1cf93SDouglas Gilbert } 4849f0d1cf93SDouglas Gilbert } 4850f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 48515cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 48525cb2fc06SFUJITA Tomonori } 48535cb2fc06SFUJITA Tomonori return devip; 48545cb2fc06SFUJITA Tomonori } 48555cb2fc06SFUJITA Tomonori 4856f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 48571da177e4SLinus Torvalds { 48581da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 48591da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 4860f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 48611da177e4SLinus Torvalds 4862d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 48631da177e4SLinus Torvalds if (!sdbg_host) { 4864c1287970STomas Winkler pr_err("Host info NULL\n"); 48651da177e4SLinus Torvalds return NULL; 48661da177e4SLinus Torvalds } 48671da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 48681da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 48691da177e4SLinus Torvalds (devip->target == sdev->id) && 48701da177e4SLinus Torvalds (devip->lun == sdev->lun)) 48711da177e4SLinus Torvalds return devip; 48721da177e4SLinus Torvalds else { 48731da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 48741da177e4SLinus Torvalds open_devip = devip; 48751da177e4SLinus Torvalds } 48761da177e4SLinus Torvalds } 48775cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 48785cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 48795cb2fc06SFUJITA Tomonori if (!open_devip) { 4880c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 48811da177e4SLinus Torvalds return NULL; 48821da177e4SLinus Torvalds } 48831da177e4SLinus Torvalds } 4884a75869d1SFUJITA Tomonori 48851da177e4SLinus Torvalds open_devip->channel = sdev->channel; 48861da177e4SLinus Torvalds open_devip->target = sdev->id; 48871da177e4SLinus Torvalds open_devip->lun = sdev->lun; 48881da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 4889cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 4890cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 4891c2248fc9SDouglas Gilbert open_devip->used = true; 48921da177e4SLinus Torvalds return open_devip; 48931da177e4SLinus Torvalds } 48941da177e4SLinus Torvalds 48958dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 48961da177e4SLinus Torvalds { 4897773642d9SDouglas Gilbert if (sdebug_verbose) 4898c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 48998dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 49008dea0d02SFUJITA Tomonori return 0; 49018dea0d02SFUJITA Tomonori } 49021da177e4SLinus Torvalds 49038dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 49048dea0d02SFUJITA Tomonori { 4905f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 4906f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 4907a34c4e98SFUJITA Tomonori 4908773642d9SDouglas Gilbert if (sdebug_verbose) 4909c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 49108dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 4911b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 4912b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 4913b01f6f83SDouglas Gilbert if (devip == NULL) { 4914f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 4915b01f6f83SDouglas Gilbert if (devip == NULL) 49168dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 4917f46eb0e9SDouglas Gilbert } 4918c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 4919773642d9SDouglas Gilbert if (sdebug_no_uld) 492078d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 49219b760fd8SDouglas Gilbert config_cdb_len(sdp); 49228dea0d02SFUJITA Tomonori return 0; 49238dea0d02SFUJITA Tomonori } 49248dea0d02SFUJITA Tomonori 49258dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 49268dea0d02SFUJITA Tomonori { 49278dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 49288dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 49298dea0d02SFUJITA Tomonori 4930773642d9SDouglas Gilbert if (sdebug_verbose) 4931c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 49328dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 49338dea0d02SFUJITA Tomonori if (devip) { 493425985edcSLucas De Marchi /* make this slot available for re-use */ 4935c2248fc9SDouglas Gilbert devip->used = false; 49368dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 49378dea0d02SFUJITA Tomonori } 49388dea0d02SFUJITA Tomonori } 49398dea0d02SFUJITA Tomonori 494010bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 494110bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 4942c4837394SDouglas Gilbert { 4943c4837394SDouglas Gilbert if (!sd_dp) 4944c4837394SDouglas Gilbert return; 494510bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 4946c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 494710bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 4948c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 4949c4837394SDouglas Gilbert } 4950c4837394SDouglas Gilbert 4951a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 4952a10bc12aSDouglas Gilbert returns false */ 4953a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 49548dea0d02SFUJITA Tomonori { 49558dea0d02SFUJITA Tomonori unsigned long iflags; 4956c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 495710bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 4958c4837394SDouglas Gilbert struct sdebug_queue *sqp; 49598dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 4960cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4961a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 49628dea0d02SFUJITA Tomonori 4963c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4964c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4965773642d9SDouglas Gilbert qmax = sdebug_max_queue; 4966cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 4967cbf67842SDouglas Gilbert if (r_qmax > qmax) 4968cbf67842SDouglas Gilbert qmax = r_qmax; 4969cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 4970c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 4971c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 4972a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 4973a10bc12aSDouglas Gilbert continue; 4974c4837394SDouglas Gilbert /* found */ 4975db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 4976db525fceSDouglas Gilbert cmnd->device->hostdata; 4977db525fceSDouglas Gilbert if (devip) 4978db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 4979db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 4980a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 498110bde980SDouglas Gilbert if (sd_dp) { 498210bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 498310bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 498410bde980SDouglas Gilbert } else 498510bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 4986c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 498710bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 4988c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 4989a10bc12aSDouglas Gilbert return true; 49908dea0d02SFUJITA Tomonori } 4991cbf67842SDouglas Gilbert } 4992c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4993c4837394SDouglas Gilbert } 4994a10bc12aSDouglas Gilbert return false; 49958dea0d02SFUJITA Tomonori } 49968dea0d02SFUJITA Tomonori 4997a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 49988dea0d02SFUJITA Tomonori static void stop_all_queued(void) 49998dea0d02SFUJITA Tomonori { 50008dea0d02SFUJITA Tomonori unsigned long iflags; 5001c4837394SDouglas Gilbert int j, k; 500210bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5003c4837394SDouglas Gilbert struct sdebug_queue *sqp; 50048dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5005cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5006a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 50078dea0d02SFUJITA Tomonori 5008c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5009c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5010c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5011c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5012c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5013c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 5014a10bc12aSDouglas Gilbert continue; 5015db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5016db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5017db525fceSDouglas Gilbert if (devip) 5018db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5019db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5020a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 502110bde980SDouglas Gilbert if (sd_dp) { 502210bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 502310bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 502410bde980SDouglas Gilbert } else 502510bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5026c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 502710bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5028c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5029c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 50308dea0d02SFUJITA Tomonori } 50318dea0d02SFUJITA Tomonori } 5032c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5033c4837394SDouglas Gilbert } 5034cbf67842SDouglas Gilbert } 5035cbf67842SDouglas Gilbert 5036cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5037cbf67842SDouglas Gilbert static void free_all_queued(void) 5038cbf67842SDouglas Gilbert { 5039c4837394SDouglas Gilbert int j, k; 5040c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5041cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5042cbf67842SDouglas Gilbert 5043c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5044c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5045c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5046a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5047a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5048cbf67842SDouglas Gilbert } 50491da177e4SLinus Torvalds } 5050c4837394SDouglas Gilbert } 50511da177e4SLinus Torvalds 50521da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 50531da177e4SLinus Torvalds { 5054a10bc12aSDouglas Gilbert bool ok; 5055a10bc12aSDouglas Gilbert 50561da177e4SLinus Torvalds ++num_aborts; 5057cbf67842SDouglas Gilbert if (SCpnt) { 5058a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5059a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5060a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5061a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5062a10bc12aSDouglas Gilbert ok ? "" : " not"); 5063cbf67842SDouglas Gilbert } 50641da177e4SLinus Torvalds return SUCCESS; 50651da177e4SLinus Torvalds } 50661da177e4SLinus Torvalds 50671da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 50681da177e4SLinus Torvalds { 50691da177e4SLinus Torvalds ++num_dev_resets; 5070cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5071cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5072f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5073f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5074cbf67842SDouglas Gilbert 5075773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5076cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 50771da177e4SLinus Torvalds if (devip) 5078cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 50791da177e4SLinus Torvalds } 50801da177e4SLinus Torvalds return SUCCESS; 50811da177e4SLinus Torvalds } 50821da177e4SLinus Torvalds 5083cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5084cbf67842SDouglas Gilbert { 5085cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5086cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5087cbf67842SDouglas Gilbert struct scsi_device *sdp; 5088cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5089cbf67842SDouglas Gilbert int k = 0; 5090cbf67842SDouglas Gilbert 5091cbf67842SDouglas Gilbert ++num_target_resets; 5092cbf67842SDouglas Gilbert if (!SCpnt) 5093cbf67842SDouglas Gilbert goto lie; 5094cbf67842SDouglas Gilbert sdp = SCpnt->device; 5095cbf67842SDouglas Gilbert if (!sdp) 5096cbf67842SDouglas Gilbert goto lie; 5097773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5098cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5099cbf67842SDouglas Gilbert hp = sdp->host; 5100cbf67842SDouglas Gilbert if (!hp) 5101cbf67842SDouglas Gilbert goto lie; 5102cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5103cbf67842SDouglas Gilbert if (sdbg_host) { 5104cbf67842SDouglas Gilbert list_for_each_entry(devip, 5105cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5106cbf67842SDouglas Gilbert dev_list) 5107cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5108cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5109cbf67842SDouglas Gilbert ++k; 5110cbf67842SDouglas Gilbert } 5111cbf67842SDouglas Gilbert } 5112773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5113cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5114cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5115cbf67842SDouglas Gilbert lie: 5116cbf67842SDouglas Gilbert return SUCCESS; 5117cbf67842SDouglas Gilbert } 5118cbf67842SDouglas Gilbert 51191da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 51201da177e4SLinus Torvalds { 51211da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5122cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 51231da177e4SLinus Torvalds struct scsi_device *sdp; 51241da177e4SLinus Torvalds struct Scsi_Host *hp; 5125cbf67842SDouglas Gilbert int k = 0; 51261da177e4SLinus Torvalds 51271da177e4SLinus Torvalds ++num_bus_resets; 5128cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5129cbf67842SDouglas Gilbert goto lie; 5130cbf67842SDouglas Gilbert sdp = SCpnt->device; 5131773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5132cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5133cbf67842SDouglas Gilbert hp = sdp->host; 5134cbf67842SDouglas Gilbert if (hp) { 5135d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 51361da177e4SLinus Torvalds if (sdbg_host) { 5137cbf67842SDouglas Gilbert list_for_each_entry(devip, 51381da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5139cbf67842SDouglas Gilbert dev_list) { 5140cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5141cbf67842SDouglas Gilbert ++k; 51421da177e4SLinus Torvalds } 51431da177e4SLinus Torvalds } 5144cbf67842SDouglas Gilbert } 5145773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5146cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5147cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5148cbf67842SDouglas Gilbert lie: 51491da177e4SLinus Torvalds return SUCCESS; 51501da177e4SLinus Torvalds } 51511da177e4SLinus Torvalds 51521da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 51531da177e4SLinus Torvalds { 51541da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5155cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5156cbf67842SDouglas Gilbert int k = 0; 51571da177e4SLinus Torvalds 51581da177e4SLinus Torvalds ++num_host_resets; 5159773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5160cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 51611da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51621da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5163cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5164cbf67842SDouglas Gilbert dev_list) { 5165cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5166cbf67842SDouglas Gilbert ++k; 5167cbf67842SDouglas Gilbert } 51681da177e4SLinus Torvalds } 51691da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51701da177e4SLinus Torvalds stop_all_queued(); 5171773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5172cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5173cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 51741da177e4SLinus Torvalds return SUCCESS; 51751da177e4SLinus Torvalds } 51761da177e4SLinus Torvalds 517787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 51781da177e4SLinus Torvalds { 51791442f76dSChristoph Hellwig struct msdos_partition *pp; 51801da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 51811da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 51821da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 51831da177e4SLinus Torvalds 51841da177e4SLinus Torvalds /* assume partition table already zeroed */ 5185773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 51861da177e4SLinus Torvalds return; 5187773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5188773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5189c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 51901da177e4SLinus Torvalds } 5191c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 51921da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5193773642d9SDouglas Gilbert / sdebug_num_parts; 51941da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 51951da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5196773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 51971da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 51981da177e4SLinus Torvalds * heads_by_sects; 5199773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5200773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 52011da177e4SLinus Torvalds 52021da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 52031da177e4SLinus Torvalds ramp[511] = 0xAA; 52041442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 52051da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 52061da177e4SLinus Torvalds start_sec = starts[k]; 52071da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 52081da177e4SLinus Torvalds pp->boot_ind = 0; 52091da177e4SLinus Torvalds 52101da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 52111da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 52121da177e4SLinus Torvalds / sdebug_sectors_per; 52131da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 52141da177e4SLinus Torvalds 52151da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 52161da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 52171da177e4SLinus Torvalds / sdebug_sectors_per; 52181da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 52191da177e4SLinus Torvalds 5220150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5221150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 52221da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 52231da177e4SLinus Torvalds } 52241da177e4SLinus Torvalds } 52251da177e4SLinus Torvalds 5226c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 5227c4837394SDouglas Gilbert { 5228c4837394SDouglas Gilbert int j; 5229c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5230c4837394SDouglas Gilbert 5231c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 5232c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 5233c4837394SDouglas Gilbert } 5234c4837394SDouglas Gilbert 5235c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5236c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5237c4837394SDouglas Gilbert */ 5238c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5239c4837394SDouglas Gilbert { 5240c4837394SDouglas Gilbert int count, modulo; 5241c4837394SDouglas Gilbert 5242c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5243c4837394SDouglas Gilbert if (modulo < 2) 5244c4837394SDouglas Gilbert return; 5245c4837394SDouglas Gilbert block_unblock_all_queues(true); 5246c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5247c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5248c4837394SDouglas Gilbert block_unblock_all_queues(false); 5249c4837394SDouglas Gilbert } 5250c4837394SDouglas Gilbert 5251c4837394SDouglas Gilbert static void clear_queue_stats(void) 5252c4837394SDouglas Gilbert { 5253c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5254c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5255c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5256c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5257c4837394SDouglas Gilbert } 5258c4837394SDouglas Gilbert 5259c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 5260c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 5261c4837394SDouglas Gilbert { 5262f9ba7af8SMartin Wilck if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) { 5263f9ba7af8SMartin Wilck if (sdebug_every_nth > 0) 5264f9ba7af8SMartin Wilck sqcp->inj_recovered = sqcp->inj_transport 5265f9ba7af8SMartin Wilck = sqcp->inj_dif 52667382f9d8SDouglas Gilbert = sqcp->inj_dix = sqcp->inj_short 52677382f9d8SDouglas Gilbert = sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0; 5268c4837394SDouglas Gilbert return; 5269f9ba7af8SMartin Wilck } 5270c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 5271c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 5272c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 5273c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 5274c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 52757ee6d1b4SBart Van Assche sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts); 52767382f9d8SDouglas Gilbert sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts); 5277c4837394SDouglas Gilbert } 5278c4837394SDouglas Gilbert 5279a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5280a2aede97SDouglas Gilbert 5281c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5282c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5283c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5284c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5285c4837394SDouglas Gilbert */ 5286fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5287f66b8517SMartin Wilck int scsi_result, 5288f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, 5289f66b8517SMartin Wilck struct sdebug_dev_info *), 5290f66b8517SMartin Wilck int delta_jiff, int ndelay) 52911da177e4SLinus Torvalds { 5292a2aede97SDouglas Gilbert bool new_sd_dp; 5293cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 5294a2aede97SDouglas Gilbert unsigned long iflags; 5295a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5296c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5297c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5298299b6c07STomas Winkler struct scsi_device *sdp; 5299a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 53001da177e4SLinus Torvalds 5301b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5302b01f6f83SDouglas Gilbert if (scsi_result == 0) 5303f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5304f46eb0e9SDouglas Gilbert goto respond_in_thread; 53051da177e4SLinus Torvalds } 5306299b6c07STomas Winkler sdp = cmnd->device; 5307299b6c07STomas Winkler 5308cd62b7daSDouglas Gilbert if (delta_jiff == 0) 5309cd62b7daSDouglas Gilbert goto respond_in_thread; 53101da177e4SLinus Torvalds 5311c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5312c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5313c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5314c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5315c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5316c4837394SDouglas Gilbert } 5317cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5318cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5319cbf67842SDouglas Gilbert inject = 0; 5320f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5321cd62b7daSDouglas Gilbert if (scsi_result) { 5322c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5323cd62b7daSDouglas Gilbert goto respond_in_thread; 5324cd62b7daSDouglas Gilbert } else 5325cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5326c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5327773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5328f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5329cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5330cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5331773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5332cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5333cbf67842SDouglas Gilbert inject = 1; 5334cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 53351da177e4SLinus Torvalds } 5336cbf67842SDouglas Gilbert } 5337cbf67842SDouglas Gilbert 5338c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5339f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5340c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5341cd62b7daSDouglas Gilbert if (scsi_result) 5342cd62b7daSDouglas Gilbert goto respond_in_thread; 5343773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 5344cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5345773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 5346cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5347cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 5348773642d9SDouglas Gilbert __func__, sdebug_max_queue, 5349cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 5350cbf67842SDouglas Gilbert "report: host busy")); 5351cd62b7daSDouglas Gilbert if (scsi_result) 5352cd62b7daSDouglas Gilbert goto respond_in_thread; 5353cd62b7daSDouglas Gilbert else 5354cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 53551da177e4SLinus Torvalds } 5356c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 5357cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5358c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 53591da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5360c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5361a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5362c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5363c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 5364c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 536510bde980SDouglas Gilbert if (sd_dp == NULL) { 536610bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 536710bde980SDouglas Gilbert if (sd_dp == NULL) 536810bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5369a2aede97SDouglas Gilbert new_sd_dp = true; 5370a2aede97SDouglas Gilbert } else { 5371a2aede97SDouglas Gilbert new_sd_dp = false; 537210bde980SDouglas Gilbert } 5373f66b8517SMartin Wilck 5374a2aede97SDouglas Gilbert if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS) 5375a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5376a2aede97SDouglas Gilbert 5377a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 5378f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5379f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5380f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5381f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5382f66b8517SMartin Wilck } 5383f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5384f66b8517SMartin Wilck cmnd->result = scsi_result; 5385f66b8517SMartin Wilck 5386f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5387f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5388f66b8517SMartin Wilck __func__, cmnd->result); 5389f66b8517SMartin Wilck 539010bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5391b333a819SDouglas Gilbert ktime_t kt; 5392cbf67842SDouglas Gilbert 5393b333a819SDouglas Gilbert if (delta_jiff > 0) { 53940c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 53950c4bc91dSDouglas Gilbert 53960c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 53970c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 53980c4bc91dSDouglas Gilbert } else if (sdebug_random) { 53990c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 54000c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 54010c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 54020c4bc91dSDouglas Gilbert ns <<= 12; 54030c4bc91dSDouglas Gilbert } 54040c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 54050c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 54060c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 54070c4bc91dSDouglas Gilbert (u32)ndelay; 5408a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5409a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5410a2aede97SDouglas Gilbert 5411a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5412a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5413a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5414a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5415a2aede97SDouglas Gilbert if (new_sd_dp) 5416a2aede97SDouglas Gilbert kfree(sd_dp); 5417a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 5418a2aede97SDouglas Gilbert cmnd->scsi_done(cmnd); 5419a2aede97SDouglas Gilbert return 0; 5420a2aede97SDouglas Gilbert } 5421a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5422a2aede97SDouglas Gilbert kt -= d; 5423a2aede97SDouglas Gilbert } 54240c4bc91dSDouglas Gilbert } 542510bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 542610bde980SDouglas Gilbert sd_dp->init_hrt = true; 5427a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5428a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5429c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5430a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5431c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5432c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5433cbf67842SDouglas Gilbert } 5434c4837394SDouglas Gilbert if (sdebug_statistics) 5435c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 543610bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_HRT; 5437a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5438c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 5439c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 544010bde980SDouglas Gilbert if (!sd_dp->init_wq) { 544110bde980SDouglas Gilbert sd_dp->init_wq = true; 5442a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5443c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5444c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5445a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5446cbf67842SDouglas Gilbert } 5447c4837394SDouglas Gilbert if (sdebug_statistics) 5448c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 544910bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_WQ; 54507382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) 54517382f9d8SDouglas Gilbert sd_dp->aborted = true; 5452a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 54537382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) { 54547382f9d8SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 54557382f9d8SDouglas Gilbert cmnd->request->tag); 54567382f9d8SDouglas Gilbert blk_abort_request(cmnd->request); 54577382f9d8SDouglas Gilbert } 5458cbf67842SDouglas Gilbert } 5459f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 5460f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 5461cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5462cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 5463cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 5464cbf67842SDouglas Gilbert "status: TASK SET FULL"); 54651da177e4SLinus Torvalds return 0; 5466cd62b7daSDouglas Gilbert 5467cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5468f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5469f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5470f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5471cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 5472cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 5473cd62b7daSDouglas Gilbert return 0; 54741da177e4SLinus Torvalds } 5475cbf67842SDouglas Gilbert 547623183910SDouglas Gilbert /* Note: The following macros create attribute files in the 547723183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 547823183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 547923183910SDouglas Gilbert as it can when the corresponding attribute in the 548023183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 548123183910SDouglas Gilbert */ 5482773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5483773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 54849b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5485773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5486c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5487773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5488773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5489773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5490773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5491773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5492773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5493773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5494773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5495e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5496e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5497e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5498e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 54995d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 55005d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 55015d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5502773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5503773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5504773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5505773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5506773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5507773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 55085d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 55095d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 55105d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 55115d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5512773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5513773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 5514773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5515773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5516773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5517773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 55185d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5519773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 552087c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 552187c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5522773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5523773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 55240c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5525773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5526773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5527773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5528c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5529773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5530c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5531773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5532773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5533773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5534773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 553509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 55365d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5537773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 553823183910SDouglas Gilbert S_IRUGO | S_IWUSR); 55399447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5540773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 55415b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 55429267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 55431da177e4SLinus Torvalds 55441da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 55451da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 55461da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5547b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 55481da177e4SLinus Torvalds 55495d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 55505b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 55519b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 55520759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5553cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5554c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 55555b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 55565b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5557c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5558beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 555923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 55605b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5561185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5562e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 55639b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 55649b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 55655d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 55665d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 55675d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 55685b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 55695b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 55705b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 55715b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5572c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5573cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5574d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 55755d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5576cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5577c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 557878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 55791da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5580c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 558132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 558286e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 55835d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 55845d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 55855d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 55861da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 55870c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5588d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5589760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5590ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5591c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5592c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5593c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 55945b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 55955b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 55966014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 55976014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 559809ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 559909ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5600c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 56015b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 56029447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 56035b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 56049267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 56051da177e4SLinus Torvalds 5606760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5607760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 56081da177e4SLinus Torvalds 56091da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 56101da177e4SLinus Torvalds { 5611c4837394SDouglas Gilbert int k; 5612c4837394SDouglas Gilbert 5613760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5614760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5615760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5616c4837394SDouglas Gilbert return sdebug_info; 5617760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5618760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5619760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5620760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 56211da177e4SLinus Torvalds return sdebug_info; 56221da177e4SLinus Torvalds } 56231da177e4SLinus Torvalds 5624cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5625fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5626fd32119bSDouglas Gilbert int length) 56271da177e4SLinus Torvalds { 56281da177e4SLinus Torvalds char arr[16]; 5629c8ed555aSAl Viro int opts; 56301da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 56311da177e4SLinus Torvalds 56321da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 56331da177e4SLinus Torvalds return -EACCES; 56341da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 56351da177e4SLinus Torvalds arr[minLen] = '\0'; 5636c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 56371da177e4SLinus Torvalds return -EINVAL; 5638773642d9SDouglas Gilbert sdebug_opts = opts; 5639773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5640773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5641773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5642c4837394SDouglas Gilbert tweak_cmnd_count(); 56431da177e4SLinus Torvalds return length; 56441da177e4SLinus Torvalds } 5645c8ed555aSAl Viro 5646cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5647cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5648cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5649c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5650c8ed555aSAl Viro { 5651c4837394SDouglas Gilbert int f, j, l; 5652c4837394SDouglas Gilbert struct sdebug_queue *sqp; 565387c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5654cbf67842SDouglas Gilbert 5655c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5656c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5657c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5658c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5659c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 5660c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 5661c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 5662c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 5663c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 5664c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 5665c4837394SDouglas Gilbert num_aborts); 5666c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 5667c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 5668c4837394SDouglas Gilbert num_host_resets); 5669c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 5670c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 5671458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 5672458df78bSBart Van Assche sdebug_statistics); 5673c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 5674c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 5675c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 5676c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 5677c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 5678cbf67842SDouglas Gilbert 5679c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 5680c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5681c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 5682c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 5683773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 5684c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 5685c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 5686c4837394SDouglas Gilbert "first,last bits", f, l); 5687c4837394SDouglas Gilbert } 5688cbf67842SDouglas Gilbert } 568987c715dcSDouglas Gilbert 569087c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 569187c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 569287c715dcSDouglas Gilbert bool niu; 569387c715dcSDouglas Gilbert int idx; 569487c715dcSDouglas Gilbert unsigned long l_idx; 569587c715dcSDouglas Gilbert struct sdeb_store_info *sip; 569687c715dcSDouglas Gilbert 569787c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 569887c715dcSDouglas Gilbert j = 0; 569987c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 570087c715dcSDouglas Gilbert idx = sdhp->si_idx; 570187c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 570287c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 570387c715dcSDouglas Gilbert ++j; 570487c715dcSDouglas Gilbert } 570587c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 570687c715dcSDouglas Gilbert sdeb_most_recent_idx); 570787c715dcSDouglas Gilbert j = 0; 570887c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 570987c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 571087c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 571187c715dcSDouglas Gilbert idx = (int)l_idx; 571287c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 571387c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 571487c715dcSDouglas Gilbert ++j; 571587c715dcSDouglas Gilbert } 571687c715dcSDouglas Gilbert } 5717c8ed555aSAl Viro return 0; 57181da177e4SLinus Torvalds } 57191da177e4SLinus Torvalds 572082069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 57211da177e4SLinus Torvalds { 5722c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 57231da177e4SLinus Torvalds } 5724c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 5725c4837394SDouglas Gilbert * of delay is jiffies. 5726c4837394SDouglas Gilbert */ 572782069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 572882069379SAkinobu Mita size_t count) 57291da177e4SLinus Torvalds { 5730c2206098SDouglas Gilbert int jdelay, res; 57311da177e4SLinus Torvalds 5732b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 5733cbf67842SDouglas Gilbert res = count; 5734c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 5735c4837394SDouglas Gilbert int j, k; 5736c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5737cbf67842SDouglas Gilbert 5738c4837394SDouglas Gilbert block_unblock_all_queues(true); 5739c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5740c4837394SDouglas Gilbert ++j, ++sqp) { 5741c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5742c4837394SDouglas Gilbert sdebug_max_queue); 5743c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5744c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5745c4837394SDouglas Gilbert break; 5746c4837394SDouglas Gilbert } 5747c4837394SDouglas Gilbert } 5748c4837394SDouglas Gilbert if (res > 0) { 5749c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 5750773642d9SDouglas Gilbert sdebug_ndelay = 0; 57511da177e4SLinus Torvalds } 5752c4837394SDouglas Gilbert block_unblock_all_queues(false); 5753cbf67842SDouglas Gilbert } 5754cbf67842SDouglas Gilbert return res; 57551da177e4SLinus Torvalds } 57561da177e4SLinus Torvalds return -EINVAL; 57571da177e4SLinus Torvalds } 575882069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 57591da177e4SLinus Torvalds 5760cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 5761cbf67842SDouglas Gilbert { 5762773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 5763cbf67842SDouglas Gilbert } 5764cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 5765c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 5766cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 5767cbf67842SDouglas Gilbert size_t count) 5768cbf67842SDouglas Gilbert { 5769c4837394SDouglas Gilbert int ndelay, res; 5770cbf67842SDouglas Gilbert 5771cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 5772c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 5773cbf67842SDouglas Gilbert res = count; 5774773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 5775c4837394SDouglas Gilbert int j, k; 5776c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5777c4837394SDouglas Gilbert 5778c4837394SDouglas Gilbert block_unblock_all_queues(true); 5779c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5780c4837394SDouglas Gilbert ++j, ++sqp) { 5781c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5782c4837394SDouglas Gilbert sdebug_max_queue); 5783c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5784c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5785c4837394SDouglas Gilbert break; 5786c4837394SDouglas Gilbert } 5787c4837394SDouglas Gilbert } 5788c4837394SDouglas Gilbert if (res > 0) { 5789773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 5790c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 5791c2206098SDouglas Gilbert : DEF_JDELAY; 5792cbf67842SDouglas Gilbert } 5793c4837394SDouglas Gilbert block_unblock_all_queues(false); 5794cbf67842SDouglas Gilbert } 5795cbf67842SDouglas Gilbert return res; 5796cbf67842SDouglas Gilbert } 5797cbf67842SDouglas Gilbert return -EINVAL; 5798cbf67842SDouglas Gilbert } 5799cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 5800cbf67842SDouglas Gilbert 580182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 58021da177e4SLinus Torvalds { 5803773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 58041da177e4SLinus Torvalds } 58051da177e4SLinus Torvalds 580682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 580782069379SAkinobu Mita size_t count) 58081da177e4SLinus Torvalds { 58091da177e4SLinus Torvalds int opts; 58101da177e4SLinus Torvalds char work[20]; 58111da177e4SLinus Torvalds 58129a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 58139a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 58149a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 58151da177e4SLinus Torvalds goto opts_done; 58161da177e4SLinus Torvalds } else { 58179a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 58181da177e4SLinus Torvalds goto opts_done; 58191da177e4SLinus Torvalds } 58201da177e4SLinus Torvalds } 58211da177e4SLinus Torvalds return -EINVAL; 58221da177e4SLinus Torvalds opts_done: 5823773642d9SDouglas Gilbert sdebug_opts = opts; 5824773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5825773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5826c4837394SDouglas Gilbert tweak_cmnd_count(); 58271da177e4SLinus Torvalds return count; 58281da177e4SLinus Torvalds } 582982069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 58301da177e4SLinus Torvalds 583182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 58321da177e4SLinus Torvalds { 5833773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 58341da177e4SLinus Torvalds } 583582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 583682069379SAkinobu Mita size_t count) 58371da177e4SLinus Torvalds { 58381da177e4SLinus Torvalds int n; 58391da177e4SLinus Torvalds 5840f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 5841f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 5842f0d1cf93SDouglas Gilbert return -EINVAL; 5843f0d1cf93SDouglas Gilbert 58441da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5845f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 5846f0d1cf93SDouglas Gilbert return -EINVAL; 5847773642d9SDouglas Gilbert sdebug_ptype = n; 58481da177e4SLinus Torvalds return count; 58491da177e4SLinus Torvalds } 58501da177e4SLinus Torvalds return -EINVAL; 58511da177e4SLinus Torvalds } 585282069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 58531da177e4SLinus Torvalds 585482069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 58551da177e4SLinus Torvalds { 5856773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 58571da177e4SLinus Torvalds } 585882069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 585982069379SAkinobu Mita size_t count) 58601da177e4SLinus Torvalds { 58611da177e4SLinus Torvalds int n; 58621da177e4SLinus Torvalds 58631da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5864773642d9SDouglas Gilbert sdebug_dsense = n; 58651da177e4SLinus Torvalds return count; 58661da177e4SLinus Torvalds } 58671da177e4SLinus Torvalds return -EINVAL; 58681da177e4SLinus Torvalds } 586982069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 58701da177e4SLinus Torvalds 587182069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 587223183910SDouglas Gilbert { 5873773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 587423183910SDouglas Gilbert } 587582069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 587682069379SAkinobu Mita size_t count) 587723183910SDouglas Gilbert { 587887c715dcSDouglas Gilbert int n, idx; 587923183910SDouglas Gilbert 588023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 588187c715dcSDouglas Gilbert bool want_store = (n == 0); 588287c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 588387c715dcSDouglas Gilbert 5884cbf67842SDouglas Gilbert n = (n > 0); 5885773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 588687c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 588787c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 5888cbf67842SDouglas Gilbert 588987c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 589087c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 589187c715dcSDouglas Gilbert idx = sdebug_add_store(); 589287c715dcSDouglas Gilbert if (idx < 0) 589387c715dcSDouglas Gilbert return idx; 589487c715dcSDouglas Gilbert } else { 589587c715dcSDouglas Gilbert idx = sdeb_first_idx; 589687c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 589787c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 5898cbf67842SDouglas Gilbert } 589987c715dcSDouglas Gilbert /* make all hosts use same store */ 590087c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 590187c715dcSDouglas Gilbert host_list) { 590287c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 590387c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 590487c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 590587c715dcSDouglas Gilbert sdhp->si_idx = idx; 590687c715dcSDouglas Gilbert } 590787c715dcSDouglas Gilbert } 590887c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 590987c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 591087c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 5911cbf67842SDouglas Gilbert } 5912773642d9SDouglas Gilbert sdebug_fake_rw = n; 591323183910SDouglas Gilbert return count; 591423183910SDouglas Gilbert } 591523183910SDouglas Gilbert return -EINVAL; 591623183910SDouglas Gilbert } 591782069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 591823183910SDouglas Gilbert 591982069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 5920c65b1445SDouglas Gilbert { 5921773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 5922c65b1445SDouglas Gilbert } 592382069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 592482069379SAkinobu Mita size_t count) 5925c65b1445SDouglas Gilbert { 5926c65b1445SDouglas Gilbert int n; 5927c65b1445SDouglas Gilbert 5928c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5929773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 5930c65b1445SDouglas Gilbert return count; 5931c65b1445SDouglas Gilbert } 5932c65b1445SDouglas Gilbert return -EINVAL; 5933c65b1445SDouglas Gilbert } 593482069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 5935c65b1445SDouglas Gilbert 593682069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 59371da177e4SLinus Torvalds { 5938773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 59391da177e4SLinus Torvalds } 594082069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 594182069379SAkinobu Mita size_t count) 59421da177e4SLinus Torvalds { 59431da177e4SLinus Torvalds int n; 59441da177e4SLinus Torvalds 59451da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5946773642d9SDouglas Gilbert sdebug_num_tgts = n; 59471da177e4SLinus Torvalds sdebug_max_tgts_luns(); 59481da177e4SLinus Torvalds return count; 59491da177e4SLinus Torvalds } 59501da177e4SLinus Torvalds return -EINVAL; 59511da177e4SLinus Torvalds } 595282069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 59531da177e4SLinus Torvalds 595482069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 59551da177e4SLinus Torvalds { 5956773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 59571da177e4SLinus Torvalds } 595882069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 59591da177e4SLinus Torvalds 596087c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 596187c715dcSDouglas Gilbert { 596287c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 596387c715dcSDouglas Gilbert } 596487c715dcSDouglas Gilbert 596587c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 596687c715dcSDouglas Gilbert size_t count) 596787c715dcSDouglas Gilbert { 596887c715dcSDouglas Gilbert bool v; 596987c715dcSDouglas Gilbert 597087c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 597187c715dcSDouglas Gilbert return -EINVAL; 597287c715dcSDouglas Gilbert 597387c715dcSDouglas Gilbert sdebug_per_host_store = v; 597487c715dcSDouglas Gilbert return count; 597587c715dcSDouglas Gilbert } 597687c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 597787c715dcSDouglas Gilbert 597882069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 59791da177e4SLinus Torvalds { 5980773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 59811da177e4SLinus Torvalds } 598282069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 59831da177e4SLinus Torvalds 598482069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 59851da177e4SLinus Torvalds { 5986773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 59871da177e4SLinus Torvalds } 598882069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 598982069379SAkinobu Mita size_t count) 59901da177e4SLinus Torvalds { 59911da177e4SLinus Torvalds int nth; 59921da177e4SLinus Torvalds 59931da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 5994773642d9SDouglas Gilbert sdebug_every_nth = nth; 5995c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 5996c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 5997c4837394SDouglas Gilbert sdebug_statistics = true; 5998c4837394SDouglas Gilbert } 5999c4837394SDouglas Gilbert tweak_cmnd_count(); 60001da177e4SLinus Torvalds return count; 60011da177e4SLinus Torvalds } 60021da177e4SLinus Torvalds return -EINVAL; 60031da177e4SLinus Torvalds } 600482069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 60051da177e4SLinus Torvalds 600682069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 60071da177e4SLinus Torvalds { 6008773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 60091da177e4SLinus Torvalds } 601082069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 601182069379SAkinobu Mita size_t count) 60121da177e4SLinus Torvalds { 60131da177e4SLinus Torvalds int n; 601419c8ead7SEwan D. Milne bool changed; 60151da177e4SLinus Torvalds 60161da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 60178d039e22SDouglas Gilbert if (n > 256) { 60188d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 60198d039e22SDouglas Gilbert return -EINVAL; 60208d039e22SDouglas Gilbert } 6021773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6022773642d9SDouglas Gilbert sdebug_max_luns = n; 60231da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6024773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 602519c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 602619c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 602719c8ead7SEwan D. Milne 602819c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 602919c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 603019c8ead7SEwan D. Milne host_list) { 603119c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 603219c8ead7SEwan D. Milne dev_list) { 603319c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 603419c8ead7SEwan D. Milne dp->uas_bm); 603519c8ead7SEwan D. Milne } 603619c8ead7SEwan D. Milne } 603719c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 603819c8ead7SEwan D. Milne } 60391da177e4SLinus Torvalds return count; 60401da177e4SLinus Torvalds } 60411da177e4SLinus Torvalds return -EINVAL; 60421da177e4SLinus Torvalds } 604382069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 60441da177e4SLinus Torvalds 604582069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 604678d4e5a0SDouglas Gilbert { 6047773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 604878d4e5a0SDouglas Gilbert } 6049cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6050cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 605182069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 605282069379SAkinobu Mita size_t count) 605378d4e5a0SDouglas Gilbert { 6054c4837394SDouglas Gilbert int j, n, k, a; 6055c4837394SDouglas Gilbert struct sdebug_queue *sqp; 605678d4e5a0SDouglas Gilbert 605778d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6058c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 6059c4837394SDouglas Gilbert block_unblock_all_queues(true); 6060c4837394SDouglas Gilbert k = 0; 6061c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6062c4837394SDouglas Gilbert ++j, ++sqp) { 6063c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6064c4837394SDouglas Gilbert if (a > k) 6065c4837394SDouglas Gilbert k = a; 6066c4837394SDouglas Gilbert } 6067773642d9SDouglas Gilbert sdebug_max_queue = n; 6068c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6069cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6070cbf67842SDouglas Gilbert else if (k >= n) 6071cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6072cbf67842SDouglas Gilbert else 6073cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6074c4837394SDouglas Gilbert block_unblock_all_queues(false); 607578d4e5a0SDouglas Gilbert return count; 607678d4e5a0SDouglas Gilbert } 607778d4e5a0SDouglas Gilbert return -EINVAL; 607878d4e5a0SDouglas Gilbert } 607982069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 608078d4e5a0SDouglas Gilbert 608182069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 608278d4e5a0SDouglas Gilbert { 6083773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 608478d4e5a0SDouglas Gilbert } 608582069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 608678d4e5a0SDouglas Gilbert 608782069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 60881da177e4SLinus Torvalds { 6089773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 60901da177e4SLinus Torvalds } 609182069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 60921da177e4SLinus Torvalds 609382069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6094c65b1445SDouglas Gilbert { 6095773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6096c65b1445SDouglas Gilbert } 609782069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 609882069379SAkinobu Mita size_t count) 6099c65b1445SDouglas Gilbert { 6100c65b1445SDouglas Gilbert int n; 61010d01c5dfSDouglas Gilbert bool changed; 6102c65b1445SDouglas Gilbert 6103f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6104f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6105f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6106f0d1cf93SDouglas Gilbert 6107c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6108773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6109773642d9SDouglas Gilbert sdebug_virtual_gb = n; 611028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 61110d01c5dfSDouglas Gilbert if (changed) { 61120d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 61130d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 611428898873SFUJITA Tomonori 61154bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 61160d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 61170d01c5dfSDouglas Gilbert host_list) { 61180d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 61190d01c5dfSDouglas Gilbert dev_list) { 61200d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 61210d01c5dfSDouglas Gilbert dp->uas_bm); 61220d01c5dfSDouglas Gilbert } 61230d01c5dfSDouglas Gilbert } 61244bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 61250d01c5dfSDouglas Gilbert } 6126c65b1445SDouglas Gilbert return count; 6127c65b1445SDouglas Gilbert } 6128c65b1445SDouglas Gilbert return -EINVAL; 6129c65b1445SDouglas Gilbert } 613082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6131c65b1445SDouglas Gilbert 613282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 61331da177e4SLinus Torvalds { 613487c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 613587c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 61361da177e4SLinus Torvalds } 61371da177e4SLinus Torvalds 613882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 613982069379SAkinobu Mita size_t count) 61401da177e4SLinus Torvalds { 614187c715dcSDouglas Gilbert bool found; 614287c715dcSDouglas Gilbert unsigned long idx; 614387c715dcSDouglas Gilbert struct sdeb_store_info *sip; 614487c715dcSDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 61451da177e4SLinus Torvalds int delta_hosts; 61461da177e4SLinus Torvalds 6147f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 61481da177e4SLinus Torvalds return -EINVAL; 61491da177e4SLinus Torvalds if (delta_hosts > 0) { 61501da177e4SLinus Torvalds do { 615187c715dcSDouglas Gilbert found = false; 615287c715dcSDouglas Gilbert if (want_phs) { 615387c715dcSDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, 615487c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE) { 615587c715dcSDouglas Gilbert sdeb_most_recent_idx = (int)idx; 615687c715dcSDouglas Gilbert found = true; 615787c715dcSDouglas Gilbert break; 615887c715dcSDouglas Gilbert } 615987c715dcSDouglas Gilbert if (found) /* re-use case */ 616087c715dcSDouglas Gilbert sdebug_add_host_helper((int)idx); 616187c715dcSDouglas Gilbert else 616287c715dcSDouglas Gilbert sdebug_do_add_host(true); 616387c715dcSDouglas Gilbert } else { 616487c715dcSDouglas Gilbert sdebug_do_add_host(false); 616587c715dcSDouglas Gilbert } 61661da177e4SLinus Torvalds } while (--delta_hosts); 61671da177e4SLinus Torvalds } else if (delta_hosts < 0) { 61681da177e4SLinus Torvalds do { 616987c715dcSDouglas Gilbert sdebug_do_remove_host(false); 61701da177e4SLinus Torvalds } while (++delta_hosts); 61711da177e4SLinus Torvalds } 61721da177e4SLinus Torvalds return count; 61731da177e4SLinus Torvalds } 617482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 61751da177e4SLinus Torvalds 617682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 617723183910SDouglas Gilbert { 6178773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 617923183910SDouglas Gilbert } 618082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 618182069379SAkinobu Mita size_t count) 618223183910SDouglas Gilbert { 618323183910SDouglas Gilbert int n; 618423183910SDouglas Gilbert 618523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6186773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 618723183910SDouglas Gilbert return count; 618823183910SDouglas Gilbert } 618923183910SDouglas Gilbert return -EINVAL; 619023183910SDouglas Gilbert } 619182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 619223183910SDouglas Gilbert 6193c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6194c4837394SDouglas Gilbert { 6195c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6196c4837394SDouglas Gilbert } 6197c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6198c4837394SDouglas Gilbert size_t count) 6199c4837394SDouglas Gilbert { 6200c4837394SDouglas Gilbert int n; 6201c4837394SDouglas Gilbert 6202c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6203c4837394SDouglas Gilbert if (n > 0) 6204c4837394SDouglas Gilbert sdebug_statistics = true; 6205c4837394SDouglas Gilbert else { 6206c4837394SDouglas Gilbert clear_queue_stats(); 6207c4837394SDouglas Gilbert sdebug_statistics = false; 6208c4837394SDouglas Gilbert } 6209c4837394SDouglas Gilbert return count; 6210c4837394SDouglas Gilbert } 6211c4837394SDouglas Gilbert return -EINVAL; 6212c4837394SDouglas Gilbert } 6213c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6214c4837394SDouglas Gilbert 621582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6216597136abSMartin K. Petersen { 6217773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6218597136abSMartin K. Petersen } 621982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6220597136abSMartin K. Petersen 6221c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6222c4837394SDouglas Gilbert { 6223c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6224c4837394SDouglas Gilbert } 6225c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6226c4837394SDouglas Gilbert 622782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6228c6a44287SMartin K. Petersen { 6229773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6230c6a44287SMartin K. Petersen } 623182069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6232c6a44287SMartin K. Petersen 623382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6234c6a44287SMartin K. Petersen { 6235773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6236c6a44287SMartin K. Petersen } 623782069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6238c6a44287SMartin K. Petersen 623982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6240c6a44287SMartin K. Petersen { 6241773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6242c6a44287SMartin K. Petersen } 624382069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6244c6a44287SMartin K. Petersen 624582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6246c6a44287SMartin K. Petersen { 6247773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6248c6a44287SMartin K. Petersen } 624982069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6250c6a44287SMartin K. Petersen 625182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 625244d92694SMartin K. Petersen { 625387c715dcSDouglas Gilbert ssize_t count = 0; 625444d92694SMartin K. Petersen 62555b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 625644d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 625744d92694SMartin K. Petersen sdebug_store_sectors); 625844d92694SMartin K. Petersen 625987c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 626087c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 626187c715dcSDouglas Gilbert 626287c715dcSDouglas Gilbert if (sip) 6263c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 626487c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 626587c715dcSDouglas Gilbert } 626644d92694SMartin K. Petersen buf[count++] = '\n'; 6267c7badc90STejun Heo buf[count] = '\0'; 626844d92694SMartin K. Petersen 626944d92694SMartin K. Petersen return count; 627044d92694SMartin K. Petersen } 627182069379SAkinobu Mita static DRIVER_ATTR_RO(map); 627244d92694SMartin K. Petersen 62730c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 62740c4bc91dSDouglas Gilbert { 62750c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 62760c4bc91dSDouglas Gilbert } 62770c4bc91dSDouglas Gilbert 62780c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 62790c4bc91dSDouglas Gilbert size_t count) 62800c4bc91dSDouglas Gilbert { 62810c4bc91dSDouglas Gilbert bool v; 62820c4bc91dSDouglas Gilbert 62830c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 62840c4bc91dSDouglas Gilbert return -EINVAL; 62850c4bc91dSDouglas Gilbert 62860c4bc91dSDouglas Gilbert sdebug_random = v; 62870c4bc91dSDouglas Gilbert return count; 62880c4bc91dSDouglas Gilbert } 62890c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 62900c4bc91dSDouglas Gilbert 629182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6292d986788bSMartin Pitt { 6293773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6294d986788bSMartin Pitt } 629582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 629682069379SAkinobu Mita size_t count) 6297d986788bSMartin Pitt { 6298d986788bSMartin Pitt int n; 6299d986788bSMartin Pitt 6300d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6301773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6302d986788bSMartin Pitt return count; 6303d986788bSMartin Pitt } 6304d986788bSMartin Pitt return -EINVAL; 6305d986788bSMartin Pitt } 630682069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6307d986788bSMartin Pitt 6308cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6309cbf67842SDouglas Gilbert { 6310773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6311cbf67842SDouglas Gilbert } 6312185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6313cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6314cbf67842SDouglas Gilbert size_t count) 6315cbf67842SDouglas Gilbert { 6316185dd232SDouglas Gilbert int n; 6317cbf67842SDouglas Gilbert 6318cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6319185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6320185dd232SDouglas Gilbert return count; 6321cbf67842SDouglas Gilbert } 6322cbf67842SDouglas Gilbert return -EINVAL; 6323cbf67842SDouglas Gilbert } 6324cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6325cbf67842SDouglas Gilbert 6326c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6327c2248fc9SDouglas Gilbert { 6328773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6329c2248fc9SDouglas Gilbert } 6330c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6331c2248fc9SDouglas Gilbert size_t count) 6332c2248fc9SDouglas Gilbert { 6333c2248fc9SDouglas Gilbert int n; 6334c2248fc9SDouglas Gilbert 6335c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6336773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6337c2248fc9SDouglas Gilbert return count; 6338c2248fc9SDouglas Gilbert } 6339c2248fc9SDouglas Gilbert return -EINVAL; 6340c2248fc9SDouglas Gilbert } 6341c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6342c2248fc9SDouglas Gilbert 634309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 634409ba24c1SDouglas Gilbert { 634509ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 634609ba24c1SDouglas Gilbert } 634709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 634809ba24c1SDouglas Gilbert 63499b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 63509b760fd8SDouglas Gilbert { 63519b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 63529b760fd8SDouglas Gilbert } 63539b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 63549b760fd8SDouglas Gilbert size_t count) 63559b760fd8SDouglas Gilbert { 63569b760fd8SDouglas Gilbert int ret, n; 63579b760fd8SDouglas Gilbert 63589b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 63599b760fd8SDouglas Gilbert if (ret) 63609b760fd8SDouglas Gilbert return ret; 63619b760fd8SDouglas Gilbert sdebug_cdb_len = n; 63629b760fd8SDouglas Gilbert all_config_cdb_len(); 63639b760fd8SDouglas Gilbert return count; 63649b760fd8SDouglas Gilbert } 63659b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 63669b760fd8SDouglas Gilbert 63679267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 63689267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 63699267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 63709267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 63719267e0ebSDouglas Gilbert }; 63729267e0ebSDouglas Gilbert 63739267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 63749267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 63759267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 63769267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 63779267e0ebSDouglas Gilbert }; 63789267e0ebSDouglas Gilbert 63799267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 63809267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 63819267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 63829267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 63839267e0ebSDouglas Gilbert }; 63849267e0ebSDouglas Gilbert 63859267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 63869267e0ebSDouglas Gilbert { 63879267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 63889267e0ebSDouglas Gilbert 63899267e0ebSDouglas Gilbert if (res < 0) { 63909267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 63919267e0ebSDouglas Gilbert if (res < 0) { 63929267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 63939267e0ebSDouglas Gilbert if (sdeb_zbc_model < 0) 63949267e0ebSDouglas Gilbert return -EINVAL; 63959267e0ebSDouglas Gilbert } 63969267e0ebSDouglas Gilbert } 63979267e0ebSDouglas Gilbert return res; 63989267e0ebSDouglas Gilbert } 63999267e0ebSDouglas Gilbert 64009267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 64019267e0ebSDouglas Gilbert { 64029267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 64039267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 64049267e0ebSDouglas Gilbert } 64059267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6406cbf67842SDouglas Gilbert 640782069379SAkinobu Mita /* Note: The following array creates attribute files in the 640823183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 640923183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 641023183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 641187c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 641223183910SDouglas Gilbert */ 64136ecaff7fSRandy Dunlap 641482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 641582069379SAkinobu Mita &driver_attr_delay.attr, 641682069379SAkinobu Mita &driver_attr_opts.attr, 641782069379SAkinobu Mita &driver_attr_ptype.attr, 641882069379SAkinobu Mita &driver_attr_dsense.attr, 641982069379SAkinobu Mita &driver_attr_fake_rw.attr, 642082069379SAkinobu Mita &driver_attr_no_lun_0.attr, 642182069379SAkinobu Mita &driver_attr_num_tgts.attr, 642282069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 642382069379SAkinobu Mita &driver_attr_num_parts.attr, 642482069379SAkinobu Mita &driver_attr_every_nth.attr, 642582069379SAkinobu Mita &driver_attr_max_luns.attr, 642682069379SAkinobu Mita &driver_attr_max_queue.attr, 642782069379SAkinobu Mita &driver_attr_no_uld.attr, 642882069379SAkinobu Mita &driver_attr_scsi_level.attr, 642982069379SAkinobu Mita &driver_attr_virtual_gb.attr, 643082069379SAkinobu Mita &driver_attr_add_host.attr, 643187c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 643282069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 643382069379SAkinobu Mita &driver_attr_sector_size.attr, 6434c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6435c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 643682069379SAkinobu Mita &driver_attr_dix.attr, 643782069379SAkinobu Mita &driver_attr_dif.attr, 643882069379SAkinobu Mita &driver_attr_guard.attr, 643982069379SAkinobu Mita &driver_attr_ato.attr, 644082069379SAkinobu Mita &driver_attr_map.attr, 64410c4bc91dSDouglas Gilbert &driver_attr_random.attr, 644282069379SAkinobu Mita &driver_attr_removable.attr, 6443cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6444cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6445c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 644609ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 64479b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 64489267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 644982069379SAkinobu Mita NULL, 645082069379SAkinobu Mita }; 645182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 64521da177e4SLinus Torvalds 645311ddcecaSAkinobu Mita static struct device *pseudo_primary; 64548dea0d02SFUJITA Tomonori 64551da177e4SLinus Torvalds static int __init scsi_debug_init(void) 64561da177e4SLinus Torvalds { 645787c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 64585f2578e5SFUJITA Tomonori unsigned long sz; 645987c715dcSDouglas Gilbert int k, ret, hosts_to_add; 646087c715dcSDouglas Gilbert int idx = -1; 64611da177e4SLinus Torvalds 646287c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 646387c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6464cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6465cbf67842SDouglas Gilbert 6466773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6467c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6468773642d9SDouglas Gilbert sdebug_ndelay = 0; 6469773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6470c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6471cbf67842SDouglas Gilbert 6472773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6473597136abSMartin K. Petersen case 512: 6474597136abSMartin K. Petersen case 1024: 6475597136abSMartin K. Petersen case 2048: 6476597136abSMartin K. Petersen case 4096: 6477597136abSMartin K. Petersen break; 6478597136abSMartin K. Petersen default: 6479773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6480597136abSMartin K. Petersen return -EINVAL; 6481597136abSMartin K. Petersen } 6482597136abSMartin K. Petersen 6483773642d9SDouglas Gilbert switch (sdebug_dif) { 64848475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6485f46eb0e9SDouglas Gilbert break; 64868475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 64878475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 64888475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6489f46eb0e9SDouglas Gilbert have_dif_prot = true; 6490c6a44287SMartin K. Petersen break; 6491c6a44287SMartin K. Petersen 6492c6a44287SMartin K. Petersen default: 6493c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6494c6a44287SMartin K. Petersen return -EINVAL; 6495c6a44287SMartin K. Petersen } 6496c6a44287SMartin K. Petersen 6497aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6498aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6499aa5334c4SMaurizio Lombardi return -EINVAL; 6500aa5334c4SMaurizio Lombardi } 6501aa5334c4SMaurizio Lombardi 6502773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6503c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6504c6a44287SMartin K. Petersen return -EINVAL; 6505c6a44287SMartin K. Petersen } 6506c6a44287SMartin K. Petersen 6507773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6508c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6509c6a44287SMartin K. Petersen return -EINVAL; 6510c6a44287SMartin K. Petersen } 6511c6a44287SMartin K. Petersen 6512773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6513773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6514ea61fca5SMartin K. Petersen return -EINVAL; 6515ea61fca5SMartin K. Petersen } 65168d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 65178d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 65188d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 65198d039e22SDouglas Gilbert } 6520ea61fca5SMartin K. Petersen 6521773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6522773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6523ea61fca5SMartin K. Petersen return -EINVAL; 6524ea61fca5SMartin K. Petersen } 6525ea61fca5SMartin K. Petersen 6526c4837394SDouglas Gilbert if (submit_queues < 1) { 6527c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6528c4837394SDouglas Gilbert return -EINVAL; 6529c4837394SDouglas Gilbert } 6530c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6531c4837394SDouglas Gilbert GFP_KERNEL); 6532c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6533c4837394SDouglas Gilbert return -ENOMEM; 6534c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6535c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6536c4837394SDouglas Gilbert 6537f0d1cf93SDouglas Gilbert /* 65389267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 65399267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 6540f0d1cf93SDouglas Gilbert */ 65419267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 65429267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 65439267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 65449267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 65459267e0ebSDouglas Gilbert if (k < 0) { 65469267e0ebSDouglas Gilbert ret = k; 65479267e0ebSDouglas Gilbert goto free_vm; 65489267e0ebSDouglas Gilbert } 65499267e0ebSDouglas Gilbert sdeb_zbc_model = k; 65509267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 65519267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 65529267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 65539267e0ebSDouglas Gilbert break; 65549267e0ebSDouglas Gilbert case BLK_ZONED_HM: 65559267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 65569267e0ebSDouglas Gilbert break; 65579267e0ebSDouglas Gilbert case BLK_ZONED_HA: 65589267e0ebSDouglas Gilbert default: 65599267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 65609267e0ebSDouglas Gilbert return -EINVAL; 65619267e0ebSDouglas Gilbert } 65629267e0ebSDouglas Gilbert } 65639267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 6564f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 65659267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 65669267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 65679267e0ebSDouglas Gilbert } 6568f0d1cf93SDouglas Gilbert 65699267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 65709267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 6571773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 6572773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 6573773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 6574773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 657528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 65761da177e4SLinus Torvalds 65771da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 65781da177e4SLinus Torvalds sdebug_heads = 8; 65791da177e4SLinus Torvalds sdebug_sectors_per = 32; 6580773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 65811da177e4SLinus Torvalds sdebug_heads = 64; 6582773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 6583fa785f0aSAndy Shevchenko sdebug_heads = 32; 65841da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 65851da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 65861da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 65871da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 65881da177e4SLinus Torvalds sdebug_heads = 255; 65891da177e4SLinus Torvalds sdebug_sectors_per = 63; 65901da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 65911da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 65921da177e4SLinus Torvalds } 65935b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 6594773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 6595773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 65966014759cSMartin K. Petersen 6597773642d9SDouglas Gilbert sdebug_unmap_max_desc = 6598773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 65996014759cSMartin K. Petersen 6600773642d9SDouglas Gilbert sdebug_unmap_granularity = 6601773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 66026014759cSMartin K. Petersen 6603773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 6604773642d9SDouglas Gilbert sdebug_unmap_granularity <= 6605773642d9SDouglas Gilbert sdebug_unmap_alignment) { 6606c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 6607c4837394SDouglas Gilbert ret = -EINVAL; 660887c715dcSDouglas Gilbert goto free_q_arr; 660944d92694SMartin K. Petersen } 661044d92694SMartin K. Petersen } 661187c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 661287c715dcSDouglas Gilbert if (want_store) { 661387c715dcSDouglas Gilbert idx = sdebug_add_store(); 661487c715dcSDouglas Gilbert if (idx < 0) { 661587c715dcSDouglas Gilbert ret = idx; 661687c715dcSDouglas Gilbert goto free_q_arr; 661787c715dcSDouglas Gilbert } 661844d92694SMartin K. Petersen } 661944d92694SMartin K. Petersen 66209b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 66219b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 6622c1287970STomas Winkler pr_warn("root_device_register() error\n"); 66239b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 66246ecaff7fSRandy Dunlap goto free_vm; 66256ecaff7fSRandy Dunlap } 66266ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 66276ecaff7fSRandy Dunlap if (ret < 0) { 6628c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 66296ecaff7fSRandy Dunlap goto dev_unreg; 66306ecaff7fSRandy Dunlap } 66316ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 66326ecaff7fSRandy Dunlap if (ret < 0) { 6633c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 66346ecaff7fSRandy Dunlap goto bus_unreg; 66356ecaff7fSRandy Dunlap } 66361da177e4SLinus Torvalds 663787c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 6638773642d9SDouglas Gilbert sdebug_add_host = 0; 66391da177e4SLinus Torvalds 664087c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 664187c715dcSDouglas Gilbert if (want_store && k == 0) { 664287c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 664387c715dcSDouglas Gilbert if (ret < 0) { 664487c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 664587c715dcSDouglas Gilbert k, -ret); 664687c715dcSDouglas Gilbert break; 664787c715dcSDouglas Gilbert } 664887c715dcSDouglas Gilbert } else { 664987c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 665087c715dcSDouglas Gilbert sdebug_per_host_store); 665187c715dcSDouglas Gilbert if (ret < 0) { 665287c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 66531da177e4SLinus Torvalds break; 66541da177e4SLinus Torvalds } 66551da177e4SLinus Torvalds } 665687c715dcSDouglas Gilbert } 6657773642d9SDouglas Gilbert if (sdebug_verbose) 665887c715dcSDouglas Gilbert pr_info("built %d host(s)\n", sdebug_num_hosts); 6659c1287970STomas Winkler 66601da177e4SLinus Torvalds return 0; 66616ecaff7fSRandy Dunlap 66626ecaff7fSRandy Dunlap bus_unreg: 66636ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 66646ecaff7fSRandy Dunlap dev_unreg: 66659b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 66666ecaff7fSRandy Dunlap free_vm: 666787c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 6668c4837394SDouglas Gilbert free_q_arr: 6669c4837394SDouglas Gilbert kfree(sdebug_q_arr); 66706ecaff7fSRandy Dunlap return ret; 66711da177e4SLinus Torvalds } 66721da177e4SLinus Torvalds 66731da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 66741da177e4SLinus Torvalds { 667587c715dcSDouglas Gilbert int k = sdebug_num_hosts; 66761da177e4SLinus Torvalds 66771da177e4SLinus Torvalds stop_all_queued(); 66781da177e4SLinus Torvalds for (; k; k--) 667987c715dcSDouglas Gilbert sdebug_do_remove_host(true); 668052ab9768SLuis Henriques free_all_queued(); 66811da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 66821da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 66839b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 66841da177e4SLinus Torvalds 668587c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 668687c715dcSDouglas Gilbert xa_destroy(per_store_ap); 66871da177e4SLinus Torvalds } 66881da177e4SLinus Torvalds 66891da177e4SLinus Torvalds device_initcall(scsi_debug_init); 66901da177e4SLinus Torvalds module_exit(scsi_debug_exit); 66911da177e4SLinus Torvalds 66921da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 66931da177e4SLinus Torvalds { 66941da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 66951da177e4SLinus Torvalds 66961da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 66971da177e4SLinus Torvalds kfree(sdbg_host); 66981da177e4SLinus Torvalds } 66991da177e4SLinus Torvalds 670087c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 670187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 67021da177e4SLinus Torvalds { 670387c715dcSDouglas Gilbert if (idx < 0) 670487c715dcSDouglas Gilbert return; 670587c715dcSDouglas Gilbert if (!sip) { 670687c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 670787c715dcSDouglas Gilbert return; 670887c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 670987c715dcSDouglas Gilbert if (!sip) 671087c715dcSDouglas Gilbert return; 671187c715dcSDouglas Gilbert } 671287c715dcSDouglas Gilbert vfree(sip->map_storep); 671387c715dcSDouglas Gilbert vfree(sip->dif_storep); 671487c715dcSDouglas Gilbert vfree(sip->storep); 671587c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 671687c715dcSDouglas Gilbert kfree(sip); 671787c715dcSDouglas Gilbert } 671887c715dcSDouglas Gilbert 671987c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 672087c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 672187c715dcSDouglas Gilbert { 672287c715dcSDouglas Gilbert unsigned long idx; 672387c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 672487c715dcSDouglas Gilbert 672587c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 672687c715dcSDouglas Gilbert if (apart_from_first) 672787c715dcSDouglas Gilbert apart_from_first = false; 672887c715dcSDouglas Gilbert else 672987c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 673087c715dcSDouglas Gilbert } 673187c715dcSDouglas Gilbert if (apart_from_first) 673287c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 673387c715dcSDouglas Gilbert } 673487c715dcSDouglas Gilbert 673587c715dcSDouglas Gilbert /* 673687c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 673787c715dcSDouglas Gilbert * Limit the number of stores to 65536. 673887c715dcSDouglas Gilbert */ 673987c715dcSDouglas Gilbert static int sdebug_add_store(void) 674087c715dcSDouglas Gilbert { 674187c715dcSDouglas Gilbert int res; 674287c715dcSDouglas Gilbert u32 n_idx; 674387c715dcSDouglas Gilbert unsigned long iflags; 674487c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 674587c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 674687c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 674787c715dcSDouglas Gilbert 674887c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 674987c715dcSDouglas Gilbert if (!sip) 675087c715dcSDouglas Gilbert return -ENOMEM; 675187c715dcSDouglas Gilbert 675287c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 675387c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 675487c715dcSDouglas Gilbert if (unlikely(res < 0)) { 675587c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 675687c715dcSDouglas Gilbert kfree(sip); 675787c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 675887c715dcSDouglas Gilbert return res; 675987c715dcSDouglas Gilbert } 676087c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 676187c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 676287c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 676387c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 676487c715dcSDouglas Gilbert 676587c715dcSDouglas Gilbert res = -ENOMEM; 676687c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 676787c715dcSDouglas Gilbert if (!sip->storep) { 676887c715dcSDouglas Gilbert pr_err("user data oom\n"); 676987c715dcSDouglas Gilbert goto err; 677087c715dcSDouglas Gilbert } 677187c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 677287c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 677387c715dcSDouglas Gilbert 677487c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 677587c715dcSDouglas Gilbert if (sdebug_dix) { 677687c715dcSDouglas Gilbert int dif_size; 677787c715dcSDouglas Gilbert 677887c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 677987c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 678087c715dcSDouglas Gilbert 678187c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 678287c715dcSDouglas Gilbert sip->dif_storep); 678387c715dcSDouglas Gilbert 678487c715dcSDouglas Gilbert if (!sip->dif_storep) { 678587c715dcSDouglas Gilbert pr_err("DIX oom\n"); 678687c715dcSDouglas Gilbert goto err; 678787c715dcSDouglas Gilbert } 678887c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 678987c715dcSDouglas Gilbert } 679087c715dcSDouglas Gilbert /* Logical Block Provisioning */ 679187c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 679287c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 679387c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 679487c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 679587c715dcSDouglas Gilbert 679687c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 679787c715dcSDouglas Gilbert 679887c715dcSDouglas Gilbert if (!sip->map_storep) { 679987c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 680087c715dcSDouglas Gilbert goto err; 680187c715dcSDouglas Gilbert } 680287c715dcSDouglas Gilbert 680387c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 680487c715dcSDouglas Gilbert 680587c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 680687c715dcSDouglas Gilbert if (sdebug_num_parts) 680787c715dcSDouglas Gilbert map_region(sip, 0, 2); 680887c715dcSDouglas Gilbert } 680987c715dcSDouglas Gilbert 681087c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 681187c715dcSDouglas Gilbert return (int)n_idx; 681287c715dcSDouglas Gilbert err: 681387c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 681487c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 681587c715dcSDouglas Gilbert return res; 681687c715dcSDouglas Gilbert } 681787c715dcSDouglas Gilbert 681887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 681987c715dcSDouglas Gilbert { 682087c715dcSDouglas Gilbert int k, devs_per_host, idx; 682187c715dcSDouglas Gilbert int error = -ENOMEM; 68221da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 68238b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 68241da177e4SLinus Torvalds 682524669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 682687c715dcSDouglas Gilbert if (!sdbg_host) 68271da177e4SLinus Torvalds return -ENOMEM; 682887c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 682987c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 683087c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 683187c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 68321da177e4SLinus Torvalds 68331da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 68341da177e4SLinus Torvalds 6835773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 68361da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 68375cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 683887c715dcSDouglas Gilbert if (!sdbg_devinfo) 68391da177e4SLinus Torvalds goto clean; 68401da177e4SLinus Torvalds } 68411da177e4SLinus Torvalds 68421da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 68431da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 68441da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 68451da177e4SLinus Torvalds 68461da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 68479b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 68481da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 684987c715dcSDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 68501da177e4SLinus Torvalds 68511da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 68521da177e4SLinus Torvalds if (error) 68531da177e4SLinus Torvalds goto clean; 68541da177e4SLinus Torvalds 685587c715dcSDouglas Gilbert ++sdebug_num_hosts; 685687c715dcSDouglas Gilbert return 0; 68571da177e4SLinus Torvalds 68581da177e4SLinus Torvalds clean: 68598b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 68608b40228fSFUJITA Tomonori dev_list) { 68611da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 6862f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 68631da177e4SLinus Torvalds kfree(sdbg_devinfo); 68641da177e4SLinus Torvalds } 68651da177e4SLinus Torvalds kfree(sdbg_host); 686687c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 68671da177e4SLinus Torvalds return error; 68681da177e4SLinus Torvalds } 68691da177e4SLinus Torvalds 687087c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 68711da177e4SLinus Torvalds { 687287c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 687387c715dcSDouglas Gilbert 687487c715dcSDouglas Gilbert if (mk_new_store) { 687587c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 687687c715dcSDouglas Gilbert if (ph_idx < 0) 687787c715dcSDouglas Gilbert return ph_idx; 687887c715dcSDouglas Gilbert } 687987c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 688087c715dcSDouglas Gilbert } 688187c715dcSDouglas Gilbert 688287c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 688387c715dcSDouglas Gilbert { 688487c715dcSDouglas Gilbert int idx = -1; 68851da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 688687c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 68871da177e4SLinus Torvalds 68881da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 68891da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 68901da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 68911da177e4SLinus Torvalds struct sdebug_host_info, host_list); 689287c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 68931da177e4SLinus Torvalds } 689487c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 689587c715dcSDouglas Gilbert bool unique = true; 689687c715dcSDouglas Gilbert 689787c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 689887c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 689987c715dcSDouglas Gilbert continue; 690087c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 690187c715dcSDouglas Gilbert unique = false; 690287c715dcSDouglas Gilbert break; 690387c715dcSDouglas Gilbert } 690487c715dcSDouglas Gilbert } 690587c715dcSDouglas Gilbert if (unique) { 690687c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 690787c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 690887c715dcSDouglas Gilbert --sdeb_most_recent_idx; 690987c715dcSDouglas Gilbert } 691087c715dcSDouglas Gilbert } 691187c715dcSDouglas Gilbert if (sdbg_host) 691287c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 69131da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 69141da177e4SLinus Torvalds 69151da177e4SLinus Torvalds if (!sdbg_host) 69161da177e4SLinus Torvalds return; 69171da177e4SLinus Torvalds 69181da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 691987c715dcSDouglas Gilbert --sdebug_num_hosts; 69201da177e4SLinus Torvalds } 69211da177e4SLinus Torvalds 6922fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 6923cbf67842SDouglas Gilbert { 6924cbf67842SDouglas Gilbert int num_in_q = 0; 6925cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 6926cbf67842SDouglas Gilbert 6927c4837394SDouglas Gilbert block_unblock_all_queues(true); 6928cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 6929cbf67842SDouglas Gilbert if (NULL == devip) { 6930c4837394SDouglas Gilbert block_unblock_all_queues(false); 6931cbf67842SDouglas Gilbert return -ENODEV; 6932cbf67842SDouglas Gilbert } 6933cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 6934c40ecc12SChristoph Hellwig 6935cbf67842SDouglas Gilbert if (qdepth < 1) 6936cbf67842SDouglas Gilbert qdepth = 1; 6937c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 6938c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 6939c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 6940db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 6941cbf67842SDouglas Gilbert 6942773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 6943c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 6944c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 6945cbf67842SDouglas Gilbert } 6946c4837394SDouglas Gilbert block_unblock_all_queues(false); 6947cbf67842SDouglas Gilbert return sdev->queue_depth; 6948cbf67842SDouglas Gilbert } 6949cbf67842SDouglas Gilbert 6950c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 6951817fd66bSDouglas Gilbert { 6952c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 6953773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 6954773642d9SDouglas Gilbert sdebug_every_nth = -1; 6955773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 6956c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 6957773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 6958817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 6959c4837394SDouglas Gilbert return true; /* time out reads and writes */ 6960817fd66bSDouglas Gilbert } 6961c4837394SDouglas Gilbert return false; 6962817fd66bSDouglas Gilbert } 6963817fd66bSDouglas Gilbert 69647ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp) 69657ee6d1b4SBart Van Assche { 69667ee6d1b4SBart Van Assche return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) && 69677ee6d1b4SBart Van Assche (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 69687ee6d1b4SBart Van Assche } 69697ee6d1b4SBart Van Assche 6970fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 6971fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 6972c2248fc9SDouglas Gilbert { 6973c2248fc9SDouglas Gilbert u8 sdeb_i; 6974c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 6975c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 6976c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 6977c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 697887c715dcSDouglas Gilbert 6979c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 6980c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 6981f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 6982c2248fc9SDouglas Gilbert int k, na; 6983c2248fc9SDouglas Gilbert int errsts = 0; 6984c2248fc9SDouglas Gilbert u32 flags; 6985c2248fc9SDouglas Gilbert u16 sa; 6986c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 6987c2248fc9SDouglas Gilbert bool has_wlun_rl; 6988c2248fc9SDouglas Gilbert 6989c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 6990c4837394SDouglas Gilbert if (sdebug_statistics) 6991c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 6992f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 6993f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 6994c2248fc9SDouglas Gilbert char b[120]; 6995c2248fc9SDouglas Gilbert int n, len, sb; 6996c2248fc9SDouglas Gilbert 6997c2248fc9SDouglas Gilbert len = scp->cmd_len; 6998c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 6999c2248fc9SDouglas Gilbert if (len > 32) 7000c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7001c2248fc9SDouglas Gilbert else { 7002c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7003c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7004c2248fc9SDouglas Gilbert (u32)cmd[k]); 7005c2248fc9SDouglas Gilbert } 7006458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7007458df78bSBart Van Assche blk_mq_unique_tag(scp->request), b); 7008c2248fc9SDouglas Gilbert } 70097ee6d1b4SBart Van Assche if (fake_host_busy(scp)) 70107ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 701134d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7012f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 7013f46eb0e9SDouglas Gilbert goto err_out; 7014c2248fc9SDouglas Gilbert 7015c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7016c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7017c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7018f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7019f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7020c2248fc9SDouglas Gilbert if (NULL == devip) 7021f46eb0e9SDouglas Gilbert goto err_out; 7022c2248fc9SDouglas Gilbert } 7023c2248fc9SDouglas Gilbert na = oip->num_attached; 7024c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7025c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7026c2248fc9SDouglas Gilbert r_oip = oip; 7027c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7028c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7029c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7030c2248fc9SDouglas Gilbert else 7031c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7032c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7033c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7034c2248fc9SDouglas Gilbert break; 7035c2248fc9SDouglas Gilbert } 7036c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7037c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7038c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7039c2248fc9SDouglas Gilbert break; 7040c2248fc9SDouglas Gilbert } 7041c2248fc9SDouglas Gilbert } 7042c2248fc9SDouglas Gilbert if (k > na) { 7043c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7044c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7045c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7046c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7047c2248fc9SDouglas Gilbert else 7048c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7049c2248fc9SDouglas Gilbert goto check_cond; 7050c2248fc9SDouglas Gilbert } 7051c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7052c2248fc9SDouglas Gilbert flags = oip->flags; 7053f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7054c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7055c2248fc9SDouglas Gilbert goto check_cond; 7056c2248fc9SDouglas Gilbert } 7057f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7058773642d9SDouglas Gilbert if (sdebug_verbose) 7059773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7060773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7061c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7062c2248fc9SDouglas Gilbert goto check_cond; 7063c2248fc9SDouglas Gilbert } 7064f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7065c2248fc9SDouglas Gilbert u8 rem; 7066c2248fc9SDouglas Gilbert int j; 7067c2248fc9SDouglas Gilbert 7068c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7069c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7070c2248fc9SDouglas Gilbert if (rem) { 7071c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7072c2248fc9SDouglas Gilbert if (0x80 & rem) 7073c2248fc9SDouglas Gilbert break; 7074c2248fc9SDouglas Gilbert } 7075c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7076c2248fc9SDouglas Gilbert goto check_cond; 7077c2248fc9SDouglas Gilbert } 7078c2248fc9SDouglas Gilbert } 7079c2248fc9SDouglas Gilbert } 7080f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7081b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7082b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7083f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7084c2248fc9SDouglas Gilbert if (errsts) 7085c2248fc9SDouglas Gilbert goto check_cond; 7086c2248fc9SDouglas Gilbert } 7087c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 7088c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7089773642d9SDouglas Gilbert if (sdebug_verbose) 7090c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 7091c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 7092c2248fc9SDouglas Gilbert "required"); 7093c2248fc9SDouglas Gilbert errsts = check_condition_result; 7094c2248fc9SDouglas Gilbert goto fini; 7095c2248fc9SDouglas Gilbert } 7096773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7097c2248fc9SDouglas Gilbert goto fini; 7098f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7099c4837394SDouglas Gilbert if (fake_timeout(scp)) 7100c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7101c2248fc9SDouglas Gilbert } 7102f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7103f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7104f66b8517SMartin Wilck else 7105f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7106c2248fc9SDouglas Gilbert 7107c2248fc9SDouglas Gilbert fini: 710867da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7109f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 711075aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 711175aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 711280c49563SDouglas Gilbert /* 711375aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 711475aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 711575aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 711675aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 711780c49563SDouglas Gilbert */ 711880c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 71194f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 712080c49563SDouglas Gilbert 71214f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7122f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 712380c49563SDouglas Gilbert } else 7124f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 712510bde980SDouglas Gilbert sdebug_ndelay); 7126c2248fc9SDouglas Gilbert check_cond: 7127f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7128f46eb0e9SDouglas Gilbert err_out: 7129f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7130c2248fc9SDouglas Gilbert } 7131c2248fc9SDouglas Gilbert 71329e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7133c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7134c8ed555aSAl Viro .write_info = scsi_debug_write_info, 71359e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 71369e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 71379e603ca0SFUJITA Tomonori .info = scsi_debug_info, 71389e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 71399e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 71409e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 71419e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7142185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7143cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 71449e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 71459e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7146cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7147cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 71489e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7149c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 71509e603ca0SFUJITA Tomonori .this_id = 7, 715165e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7152cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 71536bb5e6e7SAkinobu Mita .max_sectors = -1U, 715450c2e910SChristoph Hellwig .max_segment_size = -1U, 71559e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7156c40ecc12SChristoph Hellwig .track_queue_depth = 1, 71579e603ca0SFUJITA Tomonori }; 71589e603ca0SFUJITA Tomonori 71591da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 71601da177e4SLinus Torvalds { 71611da177e4SLinus Torvalds int error = 0; 71621da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71631da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7164f46eb0e9SDouglas Gilbert int hprot; 71651da177e4SLinus Torvalds 71661da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 71671da177e4SLinus Torvalds 7168773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 71692a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 71704af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 71714af14d11SChristoph Hellwig 71721da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 71731da177e4SLinus Torvalds if (NULL == hpnt) { 7174c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 71751da177e4SLinus Torvalds error = -ENODEV; 71761da177e4SLinus Torvalds return error; 71771da177e4SLinus Torvalds } 7178c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 71799b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7180c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7181c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7182c4837394SDouglas Gilbert } 7183c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 7184c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 7185c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 71861da177e4SLinus Torvalds 71871da177e4SLinus Torvalds sdbg_host->shost = hpnt; 71881da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7189773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7190773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 71911da177e4SLinus Torvalds else 7192773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7193773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7194f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 71951da177e4SLinus Torvalds 7196f46eb0e9SDouglas Gilbert hprot = 0; 7197c6a44287SMartin K. Petersen 7198773642d9SDouglas Gilbert switch (sdebug_dif) { 7199c6a44287SMartin K. Petersen 72008475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7201f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7202773642d9SDouglas Gilbert if (sdebug_dix) 7203f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7204c6a44287SMartin K. Petersen break; 7205c6a44287SMartin K. Petersen 72068475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7207f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7208773642d9SDouglas Gilbert if (sdebug_dix) 7209f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7210c6a44287SMartin K. Petersen break; 7211c6a44287SMartin K. Petersen 72128475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7213f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7214773642d9SDouglas Gilbert if (sdebug_dix) 7215f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7216c6a44287SMartin K. Petersen break; 7217c6a44287SMartin K. Petersen 7218c6a44287SMartin K. Petersen default: 7219773642d9SDouglas Gilbert if (sdebug_dix) 7220f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7221c6a44287SMartin K. Petersen break; 7222c6a44287SMartin K. Petersen } 7223c6a44287SMartin K. Petersen 7224f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7225c6a44287SMartin K. Petersen 7226f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7227c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7228f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7229f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7230f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7231f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7232f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7233f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7234f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7235c6a44287SMartin K. Petersen 7236773642d9SDouglas Gilbert if (sdebug_guard == 1) 7237c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7238c6a44287SMartin K. Petersen else 7239c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7240c6a44287SMartin K. Petersen 7241773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7242773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7243c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7244c4837394SDouglas Gilbert sdebug_statistics = true; 72451da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 72461da177e4SLinus Torvalds if (error) { 7247c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 72481da177e4SLinus Torvalds error = -ENODEV; 72491da177e4SLinus Torvalds scsi_host_put(hpnt); 725087c715dcSDouglas Gilbert } else { 72511da177e4SLinus Torvalds scsi_scan_host(hpnt); 725287c715dcSDouglas Gilbert } 72531da177e4SLinus Torvalds 72541da177e4SLinus Torvalds return error; 72551da177e4SLinus Torvalds } 72561da177e4SLinus Torvalds 72571da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev) 72581da177e4SLinus Torvalds { 72591da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72608b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 72611da177e4SLinus Torvalds 72621da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 72631da177e4SLinus Torvalds 72641da177e4SLinus Torvalds if (!sdbg_host) { 7265c1287970STomas Winkler pr_err("Unable to locate host info\n"); 72661da177e4SLinus Torvalds return -ENODEV; 72671da177e4SLinus Torvalds } 72681da177e4SLinus Torvalds 72691da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 72701da177e4SLinus Torvalds 72718b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 72728b40228fSFUJITA Tomonori dev_list) { 72731da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7274f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 72751da177e4SLinus Torvalds kfree(sdbg_devinfo); 72761da177e4SLinus Torvalds } 72771da177e4SLinus Torvalds 72781da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 72791da177e4SLinus Torvalds return 0; 72801da177e4SLinus Torvalds } 72811da177e4SLinus Torvalds 72828dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 72838dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 72841da177e4SLinus Torvalds { 72858dea0d02SFUJITA Tomonori return 1; 72868dea0d02SFUJITA Tomonori } 72871da177e4SLinus Torvalds 72888dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 72898dea0d02SFUJITA Tomonori .name = "pseudo", 72908dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 72918dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 72928dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 729382069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 72948dea0d02SFUJITA Tomonori }; 7295