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 * 1230f67481SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/scsi_debug.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 */ 6330f67481SDouglas Gilbert #define SDEBUG_VERSION "0190" /* format to fit INQUIRY revision field */ 6430f67481SDouglas Gilbert static const char *sdebug_version_date = "20200710"; 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 154fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0 15509ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 156c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1571da177e4SLinus Torvalds 158f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */ 159f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB 128 160f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES 8 161aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES 1 162f0d1cf93SDouglas Gilbert 163b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 164b01f6f83SDouglas Gilbert 165773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 166773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 167773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 168773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 169773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 170773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 171773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 173773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 174773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 175773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 176773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 177773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 178773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 179773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 180773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1817ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 1827382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT 0x10000 183773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 184773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 185773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 186773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 187773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1887ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1897382f9d8SDouglas Gilbert SDEBUG_OPT_HOST_BUSY | \ 1907382f9d8SDouglas Gilbert SDEBUG_OPT_CMD_ABORT) 1913a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \ 1923a90a63dSDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR) 1931da177e4SLinus Torvalds 194cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 195cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 196cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 197cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 198cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 199cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 200cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 2010d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 20219c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 203acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 205acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 206cbf67842SDouglas Gilbert 207773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2081da177e4SLinus Torvalds * sector on read commands: */ 2091da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 21032f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2111da177e4SLinus Torvalds 212c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 213c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 214c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 215c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 216c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 217c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 218c4837394SDouglas Gilbert */ 219c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 221fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN SDEBUG_CANQUEUE 222cbf67842SDouglas Gilbert 223b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */ 224b6ff8ca7SDouglas Gilbert #define F_D_IN 1 /* Data-in command (e.g. READ) */ 225b6ff8ca7SDouglas Gilbert #define F_D_OUT 2 /* Data-out command (e.g. WRITE) */ 226fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 227fd32119bSDouglas Gilbert #define F_D_UNKN 8 228b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK 0x10 /* allowed with REPORT LUNS W-LUN */ 229b6ff8ca7SDouglas Gilbert #define F_SKIP_UA 0x20 /* bypass UAs (e.g. INQUIRY command) */ 230b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR 0x40 /* for commands like INQUIRY */ 231b6ff8ca7SDouglas Gilbert #define F_SA_LOW 0x80 /* SA is in cdb byte 1, bits 4 to 0 */ 232b6ff8ca7SDouglas Gilbert #define F_SA_HIGH 0x100 /* SA is in cdb bytes 8 and 9 */ 233b6ff8ca7SDouglas Gilbert #define F_INV_OP 0x200 /* invalid opcode (not supported) */ 234b6ff8ca7SDouglas Gilbert #define F_FAKE_RW 0x400 /* bypass resp_*() when fake_rw set */ 235b6ff8ca7SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access, reacts to SSU state */ 236b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY 0x1000 /* SSU command delay (long-ish) */ 237b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY 0x2000 /* SYNCHRONIZE CACHE delay */ 238fd32119bSDouglas Gilbert 239b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */ 240fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 24146f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 242fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2434f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 244fd32119bSDouglas Gilbert 245fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 246fd32119bSDouglas Gilbert 247b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 248fd32119bSDouglas Gilbert 24987c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 25087c715dcSDouglas Gilbert 25164e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */ 25264e14eceSDamien Le Moal enum sdebug_z_type { 25364e14eceSDamien Le Moal ZBC_ZONE_TYPE_CNV = 0x1, 25464e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWR = 0x2, 25564e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWP = 0x3, 25664e14eceSDamien Le Moal }; 25764e14eceSDamien Le Moal 258f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 259f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 260f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 261f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 262f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 263f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 264f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 265f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 266f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 267f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 268f0d1cf93SDouglas Gilbert }; 269f0d1cf93SDouglas Gilbert 270f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 27164e14eceSDamien Le Moal enum sdebug_z_type z_type; 272f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 27364e14eceSDamien Le Moal bool z_non_seq_resource; 274f0d1cf93SDouglas Gilbert unsigned int z_size; 275f0d1cf93SDouglas Gilbert sector_t z_start; 276f0d1cf93SDouglas Gilbert sector_t z_wp; 277f0d1cf93SDouglas Gilbert }; 278fd32119bSDouglas Gilbert 279fd32119bSDouglas Gilbert struct sdebug_dev_info { 280fd32119bSDouglas Gilbert struct list_head dev_list; 281fd32119bSDouglas Gilbert unsigned int channel; 282fd32119bSDouglas Gilbert unsigned int target; 283fd32119bSDouglas Gilbert u64 lun; 284bf476433SChristoph Hellwig uuid_t lu_name; 285fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 286fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 287fd32119bSDouglas Gilbert atomic_t num_in_q; 288fc13638aSDouglas Gilbert atomic_t stopped; /* 1: by SSU, 2: device start */ 289fd32119bSDouglas Gilbert bool used; 290f0d1cf93SDouglas Gilbert 291f0d1cf93SDouglas Gilbert /* For ZBC devices */ 29264e14eceSDamien Le Moal enum blk_zoned_model zmodel; 293f0d1cf93SDouglas Gilbert unsigned int zsize; 294f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 295f0d1cf93SDouglas Gilbert unsigned int nr_zones; 296aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 297f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 298f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 299f0d1cf93SDouglas Gilbert unsigned int nr_closed; 300f0d1cf93SDouglas Gilbert unsigned int max_open; 301fc13638aSDouglas Gilbert ktime_t create_ts; /* time since bootup that this device was created */ 302f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 303fd32119bSDouglas Gilbert }; 304fd32119bSDouglas Gilbert 305fd32119bSDouglas Gilbert struct sdebug_host_info { 306fd32119bSDouglas Gilbert struct list_head host_list; 30787c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 308fd32119bSDouglas Gilbert struct Scsi_Host *shost; 309fd32119bSDouglas Gilbert struct device dev; 310fd32119bSDouglas Gilbert struct list_head dev_info_list; 311fd32119bSDouglas Gilbert }; 312fd32119bSDouglas Gilbert 31387c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 31487c715dcSDouglas Gilbert struct sdeb_store_info { 31587c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 31687c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 31787c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 31887c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 31987c715dcSDouglas Gilbert }; 32087c715dcSDouglas Gilbert 321fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 322fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 323fd32119bSDouglas Gilbert 32410bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 3254a0c6f43SDouglas Gilbert SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3}; 32610bde980SDouglas Gilbert 327fd32119bSDouglas Gilbert struct sdebug_defer { 328fd32119bSDouglas Gilbert struct hrtimer hrt; 329fd32119bSDouglas Gilbert struct execute_work ew; 3304a0c6f43SDouglas Gilbert ktime_t cmpl_ts;/* time since boot to complete this cmd */ 331c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 332c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 333c10fa55fSJohn Garry int hc_idx; /* hostwide tag index */ 334c4837394SDouglas Gilbert int issuing_cpu; 33510bde980SDouglas Gilbert bool init_hrt; 33610bde980SDouglas Gilbert bool init_wq; 3374a0c6f43SDouglas Gilbert bool init_poll; 3387382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 33910bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 340fd32119bSDouglas Gilbert }; 341fd32119bSDouglas Gilbert 342fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 343c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 344c4837394SDouglas Gilbert * instance indicates this slot is in use. 345c4837394SDouglas Gilbert */ 346fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 347fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 348fd32119bSDouglas Gilbert }; 349fd32119bSDouglas Gilbert 350c4837394SDouglas Gilbert struct sdebug_queue { 351c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 352c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 353c4837394SDouglas Gilbert spinlock_t qc_lock; 354c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 355fd32119bSDouglas Gilbert }; 356fd32119bSDouglas Gilbert 357c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 358c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 359c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 360c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 3613a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending; 3624a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */ 363c4837394SDouglas Gilbert 364fd32119bSDouglas Gilbert struct opcode_info_t { 365b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 366b01f6f83SDouglas Gilbert /* for terminating element */ 367fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 368fd32119bSDouglas Gilbert u16 sa; /* service action */ 369fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 370fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 371fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3729a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3739a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 374fd32119bSDouglas Gilbert }; 375fd32119bSDouglas Gilbert 376fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 377c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 378c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 379c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 380c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 381c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 382c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 383c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 384c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 385c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 386c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 387c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 388c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 389c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 39046f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 39146f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 392c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 393c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 394c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 395481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 396c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 397c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 398c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 399c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 400c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 401c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 402c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 403c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 404c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 405c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 406c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 407ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 408f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 409f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 410f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 411c2248fc9SDouglas Gilbert }; 412c2248fc9SDouglas Gilbert 413c4837394SDouglas Gilbert 414c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 415c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 416c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 417c2248fc9SDouglas Gilbert 0, 0, 0, 0, 418c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 419c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 420c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 421c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 422c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 423c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 424c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 425c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 426ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 427c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 428c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 429c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 430c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 431c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 432c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 433c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 434fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 435c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 436c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 437c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 438c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 439c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 440c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 441c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 442f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 443f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 44446f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 445c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 446c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 447c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 44846f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 44946f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 450c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 451c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 452c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 453c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 454c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 456c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 457c2248fc9SDouglas Gilbert }; 458c2248fc9SDouglas Gilbert 45980c49563SDouglas Gilbert /* 46080c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 46180c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 46280c49563SDouglas Gilbert * command completion, they can mask their return value with 46380c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 46480c49563SDouglas Gilbert */ 46580c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 46680c49563SDouglas Gilbert 467c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 468c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 469c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 470c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 471c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 472c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 473c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 474c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 475c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 476481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 477c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 478c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 479c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 48238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 48338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 484c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 485c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 486c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 48738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 488acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 48980c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 490ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 491f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 492f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 493f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 494f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 495f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 496c2248fc9SDouglas Gilbert 49787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 49887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 49987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 50087c715dcSDouglas Gilbert static int sdebug_add_store(void); 50187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 50287c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 50387c715dcSDouglas Gilbert 50446f64e70SDouglas Gilbert /* 50546f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 50646f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 50746f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 50846f64e70SDouglas Gilbert */ 50946f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 510c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 511c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 512c2248fc9SDouglas Gilbert }; 513c2248fc9SDouglas Gilbert 51446f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 515c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 516c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 517c2248fc9SDouglas Gilbert }; 518c2248fc9SDouglas Gilbert 51946f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 52046f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 521b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 522c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 52346f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 524c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 52546f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 526b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 527c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 528c2248fc9SDouglas Gilbert }; 529c2248fc9SDouglas Gilbert 53046f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 53146f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 53246f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 53346f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 53446f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 53546f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 53646f64e70SDouglas Gilbert 0, 0, 0} }, 53746f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 53846f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 53946f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 540c2248fc9SDouglas Gilbert }; 541c2248fc9SDouglas Gilbert 542c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 543c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 544c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 545c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 546c3e2fe92SDouglas Gilbert }; 547c3e2fe92SDouglas Gilbert 54846f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 549c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 550c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55146f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 552c2248fc9SDouglas Gilbert }; 553c2248fc9SDouglas Gilbert 55446f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 55546f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 556b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 557c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 558481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 559481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 560481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 561c2248fc9SDouglas Gilbert }; 562c2248fc9SDouglas Gilbert 56346f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 56438d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 565c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 56646f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 56738d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 568c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 56946f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 570c2248fc9SDouglas Gilbert }; 571c2248fc9SDouglas Gilbert 57246f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 57346f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 574c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57546f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 576c2248fc9SDouglas Gilbert }; 577c2248fc9SDouglas Gilbert 57846f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 579c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 580c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 581c2248fc9SDouglas Gilbert }; 582c2248fc9SDouglas Gilbert 58346f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 584c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 585c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 586c2248fc9SDouglas Gilbert }; 587c2248fc9SDouglas Gilbert 58880c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5894f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 59080c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59180c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 59280c49563SDouglas Gilbert }; 59380c49563SDouglas Gilbert 594ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 595b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 596ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 597ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 598ed9f3e25SDouglas Gilbert }; 599ed9f3e25SDouglas Gilbert 600f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 601b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 602f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 603f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 604b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 605f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 606f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 607b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 608f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 609f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 610f0d1cf93SDouglas Gilbert }; 611f0d1cf93SDouglas Gilbert 612f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 613b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 614f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 615f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 616f0d1cf93SDouglas Gilbert }; 617f0d1cf93SDouglas Gilbert 618c2248fc9SDouglas Gilbert 619c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 620c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 621c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 622ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 623c2248fc9SDouglas Gilbert /* 0 */ 62446f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 625c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 62646f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 627c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 628c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 629c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 63046f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 631c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 632c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 633c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 634c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63546f64e70SDouglas Gilbert /* 5 */ 63646f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 63746f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 63846f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 63946f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 64046f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 64146f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64246f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 643c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 644c2248fc9SDouglas Gilbert 0, 0, 0} }, 64546f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 646c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 647c2248fc9SDouglas Gilbert 0, 0} }, 64846f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 64946f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 65046f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 651c2248fc9SDouglas Gilbert /* 10 */ 65246f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 65346f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 65446f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65580c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6564f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 657c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 65846f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 65946f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 66046f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66146f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 662481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 663481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 664481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 66546f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 66646f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 66746f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 66846f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 66946f64e70SDouglas Gilbert /* 15 */ 670c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 671c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 672c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 673c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 674c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 675c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 67646f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 67746f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 67846f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 67946f64e70SDouglas Gilbert 0xff, 0xff} }, 68046f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 68146f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 682c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 683c2248fc9SDouglas Gilbert 0} }, 68446f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 68546f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 686c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 687c2248fc9SDouglas Gilbert 0} }, 688c2248fc9SDouglas Gilbert /* 20 */ 689f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 690f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 691c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 692c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 693c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 694c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 695c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 696c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 69746f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 698b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 69946f64e70SDouglas Gilbert /* 25 */ 700acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 701acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 702acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 70346f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 70446f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 70546f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 70646f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7074f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 70880c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 709b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 71080c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 71146f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 712c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 713b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 714b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 715ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 716ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 717ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 718c2248fc9SDouglas Gilbert 719ed9f3e25SDouglas Gilbert /* 30 */ 720b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 721f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 722f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 723f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 724b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 725f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 726f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 727f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 728f0d1cf93SDouglas Gilbert /* sentinel */ 729c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 730c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 731c2248fc9SDouglas Gilbert }; 732c2248fc9SDouglas Gilbert 73387c715dcSDouglas Gilbert static int sdebug_num_hosts; 73487c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 735773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7369b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 737c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7389267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 739773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 740773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 741773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 742773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 743773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 744773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 745c10fa55fSJohn Garry static int sdebug_host_max_queue; /* per host */ 746773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 747773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 748c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 749d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 750d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 751cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 752c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 753773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 754773642d9SDouglas Gilbert static int sdebug_no_uld; 755773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 756773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 757773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 758773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 759773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 76086e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 761b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 762773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 763773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 764fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY; 765773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 766773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 767773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 768773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 769773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 770773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 771773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 772773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 773773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 775773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 77609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7770c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 77887c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 779773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 780773642d9SDouglas Gilbert static bool sdebug_clustering; 781773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 782773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 783817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 784773642d9SDouglas Gilbert static bool sdebug_verbose; 785f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7864f2c8bf6SDouglas Gilbert static bool write_since_sync; 787c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7889447b6ceSMartin K. Petersen static bool sdebug_wp; 7899267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 7909267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 7919267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 7921da177e4SLinus Torvalds 793ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0, 794ad0c7775SDouglas Gilbert SAM_LUN_AM_FLAT = 0x1, 795ad0c7775SDouglas Gilbert SAM_LUN_AM_LOGICAL_UNIT = 0x2, 796ad0c7775SDouglas Gilbert SAM_LUN_AM_EXTENDED = 0x3}; 797ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 798ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL; 799ad0c7775SDouglas Gilbert 800c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8011da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8021da177e4SLinus Torvalds 8031da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8041da177e4SLinus Torvalds may still need them */ 8051da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8061da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8071da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8111da177e4SLinus Torvalds 81287c715dcSDouglas Gilbert static struct xarray per_store_arr; 81387c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 81487c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 81587c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 81687c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8171da177e4SLinus Torvalds 81844d92694SMartin K. Petersen static unsigned long map_size; 819cbf67842SDouglas Gilbert static int num_aborts; 820cbf67842SDouglas Gilbert static int num_dev_resets; 821cbf67842SDouglas Gilbert static int num_target_resets; 822cbf67842SDouglas Gilbert static int num_bus_resets; 823cbf67842SDouglas Gilbert static int num_host_resets; 824c6a44287SMartin K. Petersen static int dix_writes; 825c6a44287SMartin K. Petersen static int dix_reads; 826c6a44287SMartin K. Petersen static int dif_errors; 8271da177e4SLinus Torvalds 828f0d1cf93SDouglas Gilbert /* ZBC global data */ 82964e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 83098e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 831380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 832aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 833f0d1cf93SDouglas Gilbert 834c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 835c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/ 836c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 837fd32119bSDouglas Gilbert 8381da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 83987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 84087c715dcSDouglas Gilbert 84187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8421da177e4SLinus Torvalds 843cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 844cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8491da177e4SLinus Torvalds .name = sdebug_proc_name, 8501da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8511da177e4SLinus Torvalds }; 8521da177e4SLinus Torvalds 8531da177e4SLinus Torvalds static const int check_condition_result = 854464a00c9SHannes Reinecke SAM_STAT_CHECK_CONDITION; 8551da177e4SLinus Torvalds 856c6a44287SMartin K. Petersen static const int illegal_condition_result = 857464a00c9SHannes Reinecke (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 858c6a44287SMartin K. Petersen 859cbf67842SDouglas Gilbert static const int device_qfull_result = 8607a64c814SHannes Reinecke (DID_OK << 16) | SAM_STAT_TASK_SET_FULL; 861cbf67842SDouglas Gilbert 862ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 863ed9f3e25SDouglas Gilbert 864fd32119bSDouglas Gilbert 865760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 866760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 867760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 868760f3b03SDouglas Gilbert */ 869760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 870fd32119bSDouglas Gilbert { 871fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 872fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 873fd32119bSDouglas Gilbert } 874c65b1445SDouglas Gilbert 87587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 87687c715dcSDouglas Gilbert unsigned long long lba) 87714faa944SAkinobu Mita { 87887c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 87914faa944SAkinobu Mita 88087c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 88187c715dcSDouglas Gilbert if (!sip || !sip->storep) { 88287c715dcSDouglas Gilbert WARN_ON_ONCE(true); 88387c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 88487c715dcSDouglas Gilbert } 88587c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 88614faa944SAkinobu Mita } 88714faa944SAkinobu Mita 88887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 88987c715dcSDouglas Gilbert sector_t sector) 89014faa944SAkinobu Mita { 89149413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 89214faa944SAkinobu Mita 89387c715dcSDouglas Gilbert return sip->dif_storep + sector; 89414faa944SAkinobu Mita } 89514faa944SAkinobu Mita 8968dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 8978dea0d02SFUJITA Tomonori { 8988dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 8998dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9008dea0d02SFUJITA Tomonori 9018dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 9028dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9038dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9048dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 905773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 906773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9078dea0d02SFUJITA Tomonori else 908773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 909773642d9SDouglas Gilbert /* sdebug_max_luns; */ 910f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9118dea0d02SFUJITA Tomonori } 9128dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9138dea0d02SFUJITA Tomonori } 9148dea0d02SFUJITA Tomonori 91522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 91622017ed2SDouglas Gilbert 91722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 918fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 919fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 92022017ed2SDouglas Gilbert int in_byte, int in_bit) 92122017ed2SDouglas Gilbert { 92222017ed2SDouglas Gilbert unsigned char *sbuff; 92322017ed2SDouglas Gilbert u8 sks[4]; 92422017ed2SDouglas Gilbert int sl, asc; 92522017ed2SDouglas Gilbert 92622017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 92722017ed2SDouglas Gilbert if (!sbuff) { 92822017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 92922017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 93022017ed2SDouglas Gilbert return; 93122017ed2SDouglas Gilbert } 93222017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 93322017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 934f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0); 93522017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 93622017ed2SDouglas Gilbert sks[0] = 0x80; 93722017ed2SDouglas Gilbert if (c_d) 93822017ed2SDouglas Gilbert sks[0] |= 0x40; 93922017ed2SDouglas Gilbert if (in_bit >= 0) { 94022017ed2SDouglas Gilbert sks[0] |= 0x8; 94122017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 94222017ed2SDouglas Gilbert } 94322017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 944773642d9SDouglas Gilbert if (sdebug_dsense) { 94522017ed2SDouglas Gilbert sl = sbuff[7] + 8; 94622017ed2SDouglas Gilbert sbuff[7] = sl; 94722017ed2SDouglas Gilbert sbuff[sl] = 0x2; 94822017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 94922017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 95022017ed2SDouglas Gilbert } else 95122017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 952773642d9SDouglas Gilbert if (sdebug_verbose) 95322017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 95422017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 95522017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 95622017ed2SDouglas Gilbert } 95722017ed2SDouglas Gilbert 958cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9598dea0d02SFUJITA Tomonori { 960f2b1e9c6SHannes Reinecke if (!scp->sense_buffer) { 961cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 962cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 963cbf67842SDouglas Gilbert return; 964cbf67842SDouglas Gilbert } 965f2b1e9c6SHannes Reinecke memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 9668dea0d02SFUJITA Tomonori 967f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, key, asc, asq); 9688dea0d02SFUJITA Tomonori 969773642d9SDouglas Gilbert if (sdebug_verbose) 970cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 971cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 972cbf67842SDouglas Gilbert my_name, key, asc, asq); 9738dea0d02SFUJITA Tomonori } 9741da177e4SLinus Torvalds 975fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 97622017ed2SDouglas Gilbert { 97722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 97822017ed2SDouglas Gilbert } 97922017ed2SDouglas Gilbert 9806f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9816f4e626fSNathan Chancellor void __user *arg) 9821da177e4SLinus Torvalds { 983773642d9SDouglas Gilbert if (sdebug_verbose) { 984cbf67842SDouglas Gilbert if (0x1261 == cmd) 985cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 986cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 987cbf67842SDouglas Gilbert else if (0x5331 == cmd) 988cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 989cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 990cbf67842SDouglas Gilbert __func__); 991cbf67842SDouglas Gilbert else 992cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 993cbf67842SDouglas Gilbert __func__, cmd); 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds return -EINVAL; 9961da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 9999b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10009b760fd8SDouglas Gilbert { 10019b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10029b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10039b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10049b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10059b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10069b760fd8SDouglas Gilbert break; 10079b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 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 = false; 10119b760fd8SDouglas Gilbert break; 10129b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10139b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10149b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10159b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10169b760fd8SDouglas Gilbert break; 10179b760fd8SDouglas Gilbert case 16: 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 case 32: /* No knobs to suggest this so same as 16 for now */ 10239b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10249b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10259b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10269b760fd8SDouglas Gilbert break; 10279b760fd8SDouglas Gilbert default: 10289b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10299b760fd8SDouglas Gilbert sdebug_cdb_len); 10309b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10319b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10329b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10339b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10349b760fd8SDouglas Gilbert break; 10359b760fd8SDouglas Gilbert } 10369b760fd8SDouglas Gilbert } 10379b760fd8SDouglas Gilbert 10389b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10399b760fd8SDouglas Gilbert { 10409b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10419b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10429b760fd8SDouglas Gilbert struct scsi_device *sdev; 10439b760fd8SDouglas Gilbert 10449b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10459b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10469b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10479b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10489b760fd8SDouglas Gilbert config_cdb_len(sdev); 10499b760fd8SDouglas Gilbert } 10509b760fd8SDouglas Gilbert } 10519b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10529b760fd8SDouglas Gilbert } 10539b760fd8SDouglas Gilbert 105419c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 105519c8ead7SEwan D. Milne { 105619c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 105719c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 105819c8ead7SEwan D. Milne 105919c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 106019c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 106119c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 106219c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 106319c8ead7SEwan D. Milne (devip->target == dp->target)) 106419c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 106519c8ead7SEwan D. Milne } 106619c8ead7SEwan D. Milne } 106719c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 106819c8ead7SEwan D. Milne } 106919c8ead7SEwan D. Milne 1070f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10711da177e4SLinus Torvalds { 1072cbf67842SDouglas Gilbert int k; 1073cbf67842SDouglas Gilbert 1074cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1075cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1076cbf67842SDouglas Gilbert const char *cp = NULL; 1077cbf67842SDouglas Gilbert 1078cbf67842SDouglas Gilbert switch (k) { 1079cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1080f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1081f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1082773642d9SDouglas Gilbert if (sdebug_verbose) 1083cbf67842SDouglas Gilbert cp = "power on reset"; 1084cbf67842SDouglas Gilbert break; 1085cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1086f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1087f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1088773642d9SDouglas Gilbert if (sdebug_verbose) 1089cbf67842SDouglas Gilbert cp = "bus reset"; 1090cbf67842SDouglas Gilbert break; 1091cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1092f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1093f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1094773642d9SDouglas Gilbert if (sdebug_verbose) 1095cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1096cbf67842SDouglas Gilbert break; 10970d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1098f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1099f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1100773642d9SDouglas Gilbert if (sdebug_verbose) 11010d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1102f49accf1SEwan D. Milne break; 1103acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1104f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1105b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1106b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1107773642d9SDouglas Gilbert if (sdebug_verbose) 1108acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1109acafd0b9SEwan D. Milne break; 1110acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1111f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1112acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1113acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1114773642d9SDouglas Gilbert if (sdebug_verbose) 1115acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1116acafd0b9SEwan D. Milne break; 111719c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 111819c8ead7SEwan D. Milne /* 111919c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 112019c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 112119c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 112219c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1123773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 112419c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 112519c8ead7SEwan D. Milne */ 1126773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 112719c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1128f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 112919c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 113019c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1131773642d9SDouglas Gilbert if (sdebug_verbose) 113219c8ead7SEwan D. Milne cp = "reported luns data has changed"; 113319c8ead7SEwan D. Milne break; 1134cbf67842SDouglas Gilbert default: 1135773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1136773642d9SDouglas Gilbert if (sdebug_verbose) 1137cbf67842SDouglas Gilbert cp = "unknown"; 1138cbf67842SDouglas Gilbert break; 1139cbf67842SDouglas Gilbert } 1140cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1141773642d9SDouglas Gilbert if (sdebug_verbose) 1142f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1143cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1144cbf67842SDouglas Gilbert my_name, cp); 11451da177e4SLinus Torvalds return check_condition_result; 11461da177e4SLinus Torvalds } 11471da177e4SLinus Torvalds return 0; 11481da177e4SLinus Torvalds } 11491da177e4SLinus Torvalds 1150fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11511da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11521da177e4SLinus Torvalds int arr_len) 11531da177e4SLinus Torvalds { 115421a61829SFUJITA Tomonori int act_len; 1155ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11561da177e4SLinus Torvalds 1157072d0bb3SFUJITA Tomonori if (!sdb->length) 11581da177e4SLinus Torvalds return 0; 1159ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1160773642d9SDouglas Gilbert return DID_ERROR << 16; 116121a61829SFUJITA Tomonori 116221a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 116321a61829SFUJITA Tomonori arr, arr_len); 116442d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 116521a61829SFUJITA Tomonori 11661da177e4SLinus Torvalds return 0; 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 1169fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1170fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1171fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1172fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1173fb0cc8d1SDouglas Gilbert */ 1174fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1175fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1176fb0cc8d1SDouglas Gilbert { 11779237f04eSDamien Le Moal unsigned int act_len, n; 1178ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1179fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1180fb0cc8d1SDouglas Gilbert 1181fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1182fb0cc8d1SDouglas Gilbert return 0; 1183ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1184fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1185fb0cc8d1SDouglas Gilbert 1186fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1187fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1188fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 118942d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 119042d387beSBart Van Assche scsi_get_resid(scp)); 11919237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 119287c715dcSDouglas Gilbert scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n)); 1193fb0cc8d1SDouglas Gilbert return 0; 1194fb0cc8d1SDouglas Gilbert } 1195fb0cc8d1SDouglas Gilbert 1196fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1197fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1198fb0cc8d1SDouglas Gilbert */ 11991da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 120021a61829SFUJITA Tomonori int arr_len) 12011da177e4SLinus Torvalds { 120221a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12031da177e4SLinus Torvalds return 0; 1204ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12051da177e4SLinus Torvalds return -1; 120621a61829SFUJITA Tomonori 120721a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12081da177e4SLinus Torvalds } 12091da177e4SLinus Torvalds 12101da177e4SLinus Torvalds 1211e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1212e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12139b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12141b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12151b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12161b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12171b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12181da177e4SLinus Torvalds 1219cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1220760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12215a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 122209ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1223bf476433SChristoph Hellwig const uuid_t *lu_name) 12241da177e4SLinus Torvalds { 1225c65b1445SDouglas Gilbert int num, port_a; 1226c65b1445SDouglas Gilbert char b[32]; 12271da177e4SLinus Torvalds 1228c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12291da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12301da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12311da177e4SLinus Torvalds arr[1] = 0x1; 12321da177e4SLinus Torvalds arr[2] = 0x0; 1233e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1234e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12351da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12361da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12371da177e4SLinus Torvalds arr[3] = num; 12381da177e4SLinus Torvalds num += 4; 1239c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 124009ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 124109ba24c1SDouglas Gilbert /* Locally assigned UUID */ 124209ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 124309ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 124409ba24c1SDouglas Gilbert arr[num++] = 0x0; 124509ba24c1SDouglas Gilbert arr[num++] = 0x12; 124609ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 124709ba24c1SDouglas Gilbert arr[num++] = 0x0; 124809ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 124909ba24c1SDouglas Gilbert num += 16; 125009ba24c1SDouglas Gilbert } else { 12511b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1252c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1253c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1254c65b1445SDouglas Gilbert arr[num++] = 0x0; 1255c65b1445SDouglas Gilbert arr[num++] = 0x8; 12561b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1257773642d9SDouglas Gilbert num += 8; 125809ba24c1SDouglas Gilbert } 1259c65b1445SDouglas Gilbert /* Target relative port number */ 1260c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1261c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1262c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1263c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1264c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1265c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1266c65b1445SDouglas Gilbert arr[num++] = 0x0; 1267c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1268c65b1445SDouglas Gilbert } 12691b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1270c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1271c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1272c65b1445SDouglas Gilbert arr[num++] = 0x0; 1273c65b1445SDouglas Gilbert arr[num++] = 0x8; 12741b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1275773642d9SDouglas Gilbert num += 8; 12761b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12775a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12785a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12795a09e398SHannes Reinecke arr[num++] = 0x0; 12805a09e398SHannes Reinecke arr[num++] = 0x4; 12815a09e398SHannes Reinecke arr[num++] = 0; 12825a09e398SHannes Reinecke arr[num++] = 0; 1283773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1284773642d9SDouglas Gilbert num += 2; 12851b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1286c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1287c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1288c65b1445SDouglas Gilbert arr[num++] = 0x0; 1289c65b1445SDouglas Gilbert arr[num++] = 0x8; 12901b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1291773642d9SDouglas Gilbert num += 8; 1292c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1293c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1294c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1295c65b1445SDouglas Gilbert arr[num++] = 0x0; 1296c65b1445SDouglas Gilbert arr[num++] = 24; 12971b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1298c65b1445SDouglas Gilbert num += 12; 1299c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1300c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1301c65b1445SDouglas Gilbert num += 8; 1302c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1303c65b1445SDouglas Gilbert num += 4; 1304c65b1445SDouglas Gilbert return num; 1305c65b1445SDouglas Gilbert } 1306c65b1445SDouglas Gilbert 1307c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1308c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1309c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1310c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1311c65b1445SDouglas Gilbert }; 1312c65b1445SDouglas Gilbert 1313cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1314760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1315c65b1445SDouglas Gilbert { 1316c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1317c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1318c65b1445SDouglas Gilbert } 1319c65b1445SDouglas Gilbert 1320cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1321760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1322c65b1445SDouglas Gilbert { 1323c65b1445SDouglas Gilbert int num = 0; 1324c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1325c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1326c65b1445SDouglas Gilbert int plen, olen; 1327c65b1445SDouglas Gilbert 1328c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1329c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1330c65b1445SDouglas Gilbert arr[num++] = 0x0; 1331c65b1445SDouglas Gilbert olen = strlen(na1); 1332c65b1445SDouglas Gilbert plen = olen + 1; 1333c65b1445SDouglas Gilbert if (plen % 4) 1334c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1335c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1336c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1337c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1338c65b1445SDouglas Gilbert num += plen; 1339c65b1445SDouglas Gilbert 1340c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1341c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1342c65b1445SDouglas Gilbert arr[num++] = 0x0; 1343c65b1445SDouglas Gilbert olen = strlen(na2); 1344c65b1445SDouglas Gilbert plen = olen + 1; 1345c65b1445SDouglas Gilbert if (plen % 4) 1346c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1347c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1348c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1349c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1350c65b1445SDouglas Gilbert num += plen; 1351c65b1445SDouglas Gilbert 1352c65b1445SDouglas Gilbert return num; 1353c65b1445SDouglas Gilbert } 1354c65b1445SDouglas Gilbert 1355c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1356760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1357c65b1445SDouglas Gilbert { 1358c65b1445SDouglas Gilbert int num = 0; 1359c65b1445SDouglas Gilbert int port_a, port_b; 1360c65b1445SDouglas Gilbert 1361c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1362c65b1445SDouglas Gilbert port_b = port_a + 1; 1363c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1364c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1365c65b1445SDouglas Gilbert arr[num++] = 0x0; 1366c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1367c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1368c65b1445SDouglas Gilbert num += 6; 1369c65b1445SDouglas Gilbert arr[num++] = 0x0; 1370c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1371c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1372c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1373c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1374c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1375c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13761b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1377773642d9SDouglas Gilbert num += 8; 1378c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1379c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1380c65b1445SDouglas Gilbert arr[num++] = 0x0; 1381c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1382c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1383c65b1445SDouglas Gilbert num += 6; 1384c65b1445SDouglas Gilbert arr[num++] = 0x0; 1385c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1386c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1387c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1388c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1389c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1390c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13911b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1392773642d9SDouglas Gilbert num += 8; 1393c65b1445SDouglas Gilbert 1394c65b1445SDouglas Gilbert return num; 1395c65b1445SDouglas Gilbert } 1396c65b1445SDouglas Gilbert 1397c65b1445SDouglas Gilbert 1398c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1399c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1400c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1401c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1402c65b1445SDouglas Gilbert '1','2','3','4', 1403c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1404c65b1445SDouglas Gilbert 0xec,0,0,0, 1405c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1406c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1407c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1408c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1409c65b1445SDouglas Gilbert 0x53,0x41, 1410c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1411c65b1445SDouglas Gilbert 0x20,0x20, 1412c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1413c65b1445SDouglas Gilbert 0x10,0x80, 1414c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1415c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1416c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1417c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1418c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1419c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1420c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1422c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1423c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1424c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1425c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1426c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1427c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0, 1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1440c65b1445SDouglas Gilbert }; 1441c65b1445SDouglas Gilbert 1442cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1443760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1444c65b1445SDouglas Gilbert { 1445c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1446c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1447c65b1445SDouglas Gilbert } 1448c65b1445SDouglas Gilbert 1449c65b1445SDouglas Gilbert 1450c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14511e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14521e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14531e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14541e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1455c65b1445SDouglas Gilbert }; 1456c65b1445SDouglas Gilbert 1457cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1458760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1459c65b1445SDouglas Gilbert { 1460ea61fca5SMartin K. Petersen unsigned int gran; 1461ea61fca5SMartin K. Petersen 1462c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1463e308b3d1SMartin K. Petersen 1464e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 146586e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 146686e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 146786e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 146886e6828aSLukas Herbolt else 1469773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1470773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1471e308b3d1SMartin K. Petersen 1472e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1473773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1474773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 147544d92694SMartin K. Petersen 1476e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1477773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1478e308b3d1SMartin K. Petersen 1479773642d9SDouglas Gilbert if (sdebug_lbpu) { 1480e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1481773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1482e308b3d1SMartin K. Petersen 1483e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1484773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 148544d92694SMartin K. Petersen } 148644d92694SMartin K. Petersen 1487e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1488773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1489773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 149044d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 149144d92694SMartin K. Petersen } 149244d92694SMartin K. Petersen 1493e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1494773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 14956014759cSMartin K. Petersen 14965b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1497773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 14985b94e232SMartin K. Petersen 14995b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 150044d92694SMartin K. Petersen 1501c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 15021da177e4SLinus Torvalds } 15031da177e4SLinus Torvalds 15041e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 150564e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1506eac6e8e4SMatthew Wilcox { 1507eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1508eac6e8e4SMatthew Wilcox arr[0] = 0; 15091e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15101e49f785SDouglas Gilbert arr[2] = 0; 15111e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 151264e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 151364e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1514eac6e8e4SMatthew Wilcox 1515eac6e8e4SMatthew Wilcox return 0x3c; 1516eac6e8e4SMatthew Wilcox } 15171da177e4SLinus Torvalds 1518760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1519760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15206014759cSMartin K. Petersen { 15213f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15226014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1523773642d9SDouglas Gilbert if (sdebug_lbpu) 15246014759cSMartin K. Petersen arr[1] = 1 << 7; 1525773642d9SDouglas Gilbert if (sdebug_lbpws) 15266014759cSMartin K. Petersen arr[1] |= 1 << 6; 1527773642d9SDouglas Gilbert if (sdebug_lbpws10) 15285b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1529760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1530760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1531760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1532760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1533760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15343f0bc3b3SMartin K. Petersen return 0x4; 15356014759cSMartin K. Petersen } 15366014759cSMartin K. Petersen 1537d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1538f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1539d36da305SDouglas Gilbert { 1540d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1541d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1542d36da305SDouglas Gilbert /* 1543d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1544d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1545f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1546f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1547d36da305SDouglas Gilbert */ 1548d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1549d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 155064e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1551f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1552f0d1cf93SDouglas Gilbert else 1553d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 1554d36da305SDouglas Gilbert return 0x3c; 1555d36da305SDouglas Gilbert } 1556d36da305SDouglas Gilbert 15571da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1558c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15591da177e4SLinus Torvalds 1560c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds unsigned char pq_pdt; 15635a09e398SHannes Reinecke unsigned char *arr; 156401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15655a09e398SHannes Reinecke int alloc_len, n, ret; 1566d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15671da177e4SLinus Torvalds 1568773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15696f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15706f3cbf55SDouglas Gilbert if (! arr) 15716f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1572760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 157364e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1574d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1575b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1576c2248fc9SDouglas Gilbert if (have_wlun) 1577b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1578b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1579b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1580c65b1445SDouglas Gilbert else 1581773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 15821da177e4SLinus Torvalds arr[0] = pq_pdt; 15831da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 158422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 15855a09e398SHannes Reinecke kfree(arr); 15861da177e4SLinus Torvalds return check_condition_result; 15871da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 15885a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1589c65b1445SDouglas Gilbert char lu_id_str[6]; 1590c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 15911da177e4SLinus Torvalds 15925a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 15935a09e398SHannes Reinecke (devip->channel & 0x7f); 1594b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 159523183910SDouglas Gilbert host_no = 0; 1596c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1597c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1598c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1599c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1600c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16011da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1602c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1603c65b1445SDouglas Gilbert n = 4; 1604c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1605c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1606c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1607c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1608c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1609c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1610c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1611c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1612d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1613c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1614760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1615760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1616d36da305SDouglas Gilbert if (is_disk) 1617d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 161864e14eceSDamien Le Moal if (is_zbc) 1619d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1620760f3b03SDouglas Gilbert } 1621c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16221da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1623c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16241da177e4SLinus Torvalds arr[3] = len; 1625c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16261da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1627c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1628760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16295a09e398SHannes Reinecke target_dev_id, lu_id_num, 163009ba24c1SDouglas Gilbert lu_id_str, len, 163109ba24c1SDouglas Gilbert &devip->lu_name); 1632c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1633c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1634760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1635c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1636c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1637760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1638c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1639c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1640c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16418475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1642c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1643760f3b03SDouglas Gilbert else if (have_dif_prot) 1644c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1645c6a44287SMartin K. Petersen else 1646c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1647c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1648c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1649c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1650c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1651c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1652c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1653c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1654c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1655c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1656c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1657760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1658d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1659c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1660760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1661773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1662d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1663c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1664760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1665d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1666eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 166764e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1668760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16696014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1670760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1671d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1672d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1673f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16741da177e4SLinus Torvalds } else { 167522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16765a09e398SHannes Reinecke kfree(arr); 16771da177e4SLinus Torvalds return check_condition_result; 16781da177e4SLinus Torvalds } 1679773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 16805a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1681c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 16825a09e398SHannes Reinecke kfree(arr); 16835a09e398SHannes Reinecke return ret; 16841da177e4SLinus Torvalds } 16851da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1686773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1687773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 16881da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 16891da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1690f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1691b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 169270bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1693c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 16941da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1695c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1696e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1697e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1698e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 16999b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17009b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17011da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1702760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1703760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1704c65b1445SDouglas Gilbert n = 62; 1705760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1706760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1707760f3b03SDouglas Gilbert n += 2; 1708760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1709760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1710760f3b03SDouglas Gilbert n += 2; 1711d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1712d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1713d36da305SDouglas Gilbert n += 2; 17141da177e4SLinus Torvalds } 1715760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17165a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 171787c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ)); 17185a09e398SHannes Reinecke kfree(arr); 17195a09e398SHannes Reinecke return ret; 17201da177e4SLinus Torvalds } 17211da177e4SLinus Torvalds 172284905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */ 1723fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1724fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1725fd32119bSDouglas Gilbert 17261da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17271da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17281da177e4SLinus Torvalds { 172901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 173084905d34SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ 173184905d34SDouglas Gilbert bool dsense = !!(cmd[1] & 1); 173284905d34SDouglas Gilbert int alloc_len = cmd[4]; 17331da177e4SLinus Torvalds int len = 18; 173484905d34SDouglas Gilbert int stopped_state = atomic_read(&devip->stopped); 17351da177e4SLinus Torvalds 1736c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 173784905d34SDouglas Gilbert if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ 173884905d34SDouglas Gilbert if (dsense) { 173984905d34SDouglas Gilbert arr[0] = 0x72; 174084905d34SDouglas Gilbert arr[1] = NOT_READY; 174184905d34SDouglas Gilbert arr[2] = LOGICAL_UNIT_NOT_READY; 174284905d34SDouglas Gilbert arr[3] = (stopped_state == 2) ? 0x1 : 0x2; 174384905d34SDouglas Gilbert len = 8; 174484905d34SDouglas Gilbert } else { 174584905d34SDouglas Gilbert arr[0] = 0x70; 174684905d34SDouglas Gilbert arr[2] = NOT_READY; /* NO_SENSE in sense_key */ 174784905d34SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 174884905d34SDouglas Gilbert arr[12] = LOGICAL_UNIT_NOT_READY; 174984905d34SDouglas Gilbert arr[13] = (stopped_state == 2) ? 0x1 : 0x2; 175084905d34SDouglas Gilbert } 175184905d34SDouglas Gilbert } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 175284905d34SDouglas Gilbert /* Information exceptions control mode page: TEST=1, MRIE=6 */ 1753c2248fc9SDouglas Gilbert if (dsense) { 1754c65b1445SDouglas Gilbert arr[0] = 0x72; 1755c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1756c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 175784905d34SDouglas Gilbert arr[3] = 0xff; /* Failure prediction(false) */ 1758c2248fc9SDouglas Gilbert len = 8; 1759c65b1445SDouglas Gilbert } else { 1760c65b1445SDouglas Gilbert arr[0] = 0x70; 1761c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1762c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1763c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 176484905d34SDouglas Gilbert arr[13] = 0xff; /* Failure prediction(false) */ 1765c65b1445SDouglas Gilbert } 176684905d34SDouglas Gilbert } else { /* nothing to report */ 1767c2248fc9SDouglas Gilbert if (dsense) { 1768c2248fc9SDouglas Gilbert len = 8; 176984905d34SDouglas Gilbert memset(arr, 0, len); 177084905d34SDouglas Gilbert arr[0] = 0x72; 1771c2248fc9SDouglas Gilbert } else { 177284905d34SDouglas Gilbert memset(arr, 0, len); 1773c2248fc9SDouglas Gilbert arr[0] = 0x70; 1774c2248fc9SDouglas Gilbert arr[7] = 0xa; 1775c2248fc9SDouglas Gilbert } 1776c65b1445SDouglas Gilbert } 177784905d34SDouglas Gilbert return fill_from_dev_buffer(scp, arr, min_t(int, len, alloc_len)); 17781da177e4SLinus Torvalds } 17791da177e4SLinus Torvalds 1780fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 1781c65b1445SDouglas Gilbert { 178201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1783fc13638aSDouglas Gilbert int power_cond, want_stop, stopped_state; 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 } 1791fc13638aSDouglas Gilbert want_stop = !(cmd[4] & 1); 1792fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 1793fc13638aSDouglas Gilbert if (stopped_state == 2) { 1794fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 1795fc13638aSDouglas Gilbert 1796fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 1797fc13638aSDouglas Gilbert u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 1798fc13638aSDouglas Gilbert 1799fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 1800fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 1801fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 1802fc13638aSDouglas Gilbert stopped_state = 0; 1803fc13638aSDouglas Gilbert } 1804fc13638aSDouglas Gilbert } 1805fc13638aSDouglas Gilbert if (stopped_state == 2) { 1806fc13638aSDouglas Gilbert if (want_stop) { 1807fc13638aSDouglas Gilbert stopped_state = 1; /* dummy up success */ 1808fc13638aSDouglas Gilbert } else { /* Disallow tur_ms_to_ready delay to be overridden */ 1809fc13638aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */); 1810fc13638aSDouglas Gilbert return check_condition_result; 1811fc13638aSDouglas Gilbert } 1812fc13638aSDouglas Gilbert } 1813fc13638aSDouglas Gilbert } 1814fc13638aSDouglas Gilbert changing = (stopped_state != want_stop); 1815fc13638aSDouglas Gilbert if (changing) 1816fc13638aSDouglas Gilbert atomic_xchg(&devip->stopped, want_stop); 1817fc13638aSDouglas Gilbert if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ 18184f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18194f2c8bf6SDouglas Gilbert else 18204f2c8bf6SDouglas Gilbert return 0; 1821c65b1445SDouglas Gilbert } 1822c65b1445SDouglas Gilbert 182328898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 182428898873SFUJITA Tomonori { 1825773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1826773642d9SDouglas Gilbert 1827773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1828773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1829773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 183028898873SFUJITA Tomonori else 183128898873SFUJITA Tomonori return sdebug_store_sectors; 183228898873SFUJITA Tomonori } 183328898873SFUJITA Tomonori 18341da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18351da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18361da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18371da177e4SLinus Torvalds { 18381da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1839c65b1445SDouglas Gilbert unsigned int capac; 18401da177e4SLinus Torvalds 1841c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 184228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18431da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1844c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1845c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1846773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1847773642d9SDouglas Gilbert } else 1848773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1849773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18501da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18511da177e4SLinus Torvalds } 18521da177e4SLinus Torvalds 1853c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1854c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1855c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1856c65b1445SDouglas Gilbert { 185701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1858c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1859773642d9SDouglas Gilbert int alloc_len; 1860c65b1445SDouglas Gilbert 1861773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1862c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 186328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1864c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1865773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1866773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1867773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1868773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 186944d92694SMartin K. Petersen 1870be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18715b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1872760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1873760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1874760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1875760f3b03SDouglas Gilbert */ 1876760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1877760f3b03SDouglas Gilbert arr[14] |= 0x40; 1878be1dd78dSEric Sandeen } 187944d92694SMartin K. Petersen 1880773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1881c6a44287SMartin K. Petersen 1882760f3b03SDouglas Gilbert if (have_dif_prot) { 1883773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1884c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1885c6a44287SMartin K. Petersen } 1886c6a44287SMartin K. Petersen 1887c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 188887c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1889c65b1445SDouglas Gilbert } 1890c65b1445SDouglas Gilbert 18915a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 18925a09e398SHannes Reinecke 18935a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 18945a09e398SHannes Reinecke struct sdebug_dev_info *devip) 18955a09e398SHannes Reinecke { 189601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 18975a09e398SHannes Reinecke unsigned char *arr; 18985a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 18995a09e398SHannes Reinecke int n, ret, alen, rlen; 19005a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 19015a09e398SHannes Reinecke 1902773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19036f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19046f3cbf55SDouglas Gilbert if (! arr) 19056f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19065a09e398SHannes Reinecke /* 19075a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19085a09e398SHannes Reinecke * real and a fake port with no device connected. 19095a09e398SHannes Reinecke * So we create two port groups with one port each 19105a09e398SHannes Reinecke * and set the group with port B to unavailable. 19115a09e398SHannes Reinecke */ 19125a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19135a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19145a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19155a09e398SHannes Reinecke (devip->channel & 0x7f); 19165a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19175a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19185a09e398SHannes Reinecke 19195a09e398SHannes Reinecke /* 19205a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19215a09e398SHannes Reinecke */ 19225a09e398SHannes Reinecke n = 4; 1923b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19245a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19255a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19265a09e398SHannes Reinecke } else { 19275a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1928773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19295a09e398SHannes Reinecke } 1930773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1931773642d9SDouglas Gilbert n += 2; 19325a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19335a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19345a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19355a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19365a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19375a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1938773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1939773642d9SDouglas Gilbert n += 2; 19405a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19415a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1942773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1943773642d9SDouglas Gilbert n += 2; 19445a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19455a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19465a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19475a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19485a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19495a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1950773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1951773642d9SDouglas Gilbert n += 2; 19525a09e398SHannes Reinecke 19535a09e398SHannes Reinecke rlen = n - 4; 1954773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19555a09e398SHannes Reinecke 19565a09e398SHannes Reinecke /* 19575a09e398SHannes Reinecke * Return the smallest value of either 19585a09e398SHannes Reinecke * - The allocated length 19595a09e398SHannes Reinecke * - The constructed command length 19605a09e398SHannes Reinecke * - The maximum array size 19615a09e398SHannes Reinecke */ 196287c715dcSDouglas Gilbert rlen = min_t(int, alen, n); 19635a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 196487c715dcSDouglas Gilbert min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19655a09e398SHannes Reinecke kfree(arr); 19665a09e398SHannes Reinecke return ret; 19675a09e398SHannes Reinecke } 19685a09e398SHannes Reinecke 1969fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1970fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 197138d5c833SDouglas Gilbert { 197238d5c833SDouglas Gilbert bool rctd; 197338d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 197438d5c833SDouglas Gilbert u16 req_sa, u; 197538d5c833SDouglas Gilbert u32 alloc_len, a_len; 197638d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 197738d5c833SDouglas Gilbert const struct opcode_info_t *oip; 197838d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 197938d5c833SDouglas Gilbert u8 *arr; 198038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 198138d5c833SDouglas Gilbert 198238d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 198338d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 198438d5c833SDouglas Gilbert req_opcode = cmd[3]; 198538d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 198638d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 19876d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 198838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 198938d5c833SDouglas Gilbert return check_condition_result; 199038d5c833SDouglas Gilbert } 199138d5c833SDouglas Gilbert if (alloc_len > 8192) 199238d5c833SDouglas Gilbert a_len = 8192; 199338d5c833SDouglas Gilbert else 199438d5c833SDouglas Gilbert a_len = alloc_len; 199599531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 199638d5c833SDouglas Gilbert if (NULL == arr) { 199738d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 199838d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 199938d5c833SDouglas Gilbert return check_condition_result; 200038d5c833SDouglas Gilbert } 200138d5c833SDouglas Gilbert switch (reporting_opts) { 200238d5c833SDouglas Gilbert case 0: /* all commands */ 200338d5c833SDouglas Gilbert /* count number of commands */ 200438d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 200538d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 200638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 200738d5c833SDouglas Gilbert continue; 200838d5c833SDouglas Gilbert count += (oip->num_attached + 1); 200938d5c833SDouglas Gilbert } 201038d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 201138d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 201238d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 201338d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 201438d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 201538d5c833SDouglas Gilbert continue; 201638d5c833SDouglas Gilbert na = oip->num_attached; 201738d5c833SDouglas Gilbert arr[offset] = oip->opcode; 201838d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 201938d5c833SDouglas Gilbert if (rctd) 202038d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 202138d5c833SDouglas Gilbert if (FF_SA & oip->flags) 202238d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 202338d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 202438d5c833SDouglas Gilbert if (rctd) 202538d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 202638d5c833SDouglas Gilbert r_oip = oip; 202738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 202838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 202938d5c833SDouglas Gilbert continue; 203038d5c833SDouglas Gilbert offset += bump; 203138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 203238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 203338d5c833SDouglas Gilbert if (rctd) 203438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 203538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 203638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 203738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 203838d5c833SDouglas Gilbert arr + offset + 6); 203938d5c833SDouglas Gilbert if (rctd) 204038d5c833SDouglas Gilbert put_unaligned_be16(0xa, 204138d5c833SDouglas Gilbert arr + offset + 8); 204238d5c833SDouglas Gilbert } 204338d5c833SDouglas Gilbert oip = r_oip; 204438d5c833SDouglas Gilbert offset += bump; 204538d5c833SDouglas Gilbert } 204638d5c833SDouglas Gilbert break; 204738d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 204838d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 204938d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 205038d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 205138d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 205238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 205338d5c833SDouglas Gilbert supp = 1; 205438d5c833SDouglas Gilbert offset = 4; 205538d5c833SDouglas Gilbert } else { 205638d5c833SDouglas Gilbert if (1 == reporting_opts) { 205738d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 205838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 205938d5c833SDouglas Gilbert 2, 2); 206038d5c833SDouglas Gilbert kfree(arr); 206138d5c833SDouglas Gilbert return check_condition_result; 206238d5c833SDouglas Gilbert } 206338d5c833SDouglas Gilbert req_sa = 0; 206438d5c833SDouglas Gilbert } else if (2 == reporting_opts && 206538d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 206638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 206738d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 206838d5c833SDouglas Gilbert return check_condition_result; 206938d5c833SDouglas Gilbert } 207038d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 207138d5c833SDouglas Gilbert req_opcode == oip->opcode) 207238d5c833SDouglas Gilbert supp = 3; 207338d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 207438d5c833SDouglas Gilbert na = oip->num_attached; 207538d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 207638d5c833SDouglas Gilbert ++k, ++oip) { 207738d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 207838d5c833SDouglas Gilbert break; 207938d5c833SDouglas Gilbert } 208038d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 208138d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 208238d5c833SDouglas Gilbert na = oip->num_attached; 208338d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 208438d5c833SDouglas Gilbert ++k, ++oip) { 208538d5c833SDouglas Gilbert if (req_sa == oip->sa) 208638d5c833SDouglas Gilbert break; 208738d5c833SDouglas Gilbert } 208838d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 208938d5c833SDouglas Gilbert } else 209038d5c833SDouglas Gilbert supp = 3; 209138d5c833SDouglas Gilbert if (3 == supp) { 209238d5c833SDouglas Gilbert u = oip->len_mask[0]; 209338d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 209438d5c833SDouglas Gilbert arr[4] = oip->opcode; 209538d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 209638d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 209738d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 209838d5c833SDouglas Gilbert offset = 4 + u; 209938d5c833SDouglas Gilbert } else 210038d5c833SDouglas Gilbert offset = 4; 210138d5c833SDouglas Gilbert } 210238d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 210338d5c833SDouglas Gilbert if (rctd) { 210438d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 210538d5c833SDouglas Gilbert offset += 12; 210638d5c833SDouglas Gilbert } 210738d5c833SDouglas Gilbert break; 210838d5c833SDouglas Gilbert default: 210938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 211038d5c833SDouglas Gilbert kfree(arr); 211138d5c833SDouglas Gilbert return check_condition_result; 211238d5c833SDouglas Gilbert } 211338d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 211438d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 211538d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 211638d5c833SDouglas Gilbert kfree(arr); 211738d5c833SDouglas Gilbert return errsts; 211838d5c833SDouglas Gilbert } 211938d5c833SDouglas Gilbert 2120fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2121fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 212238d5c833SDouglas Gilbert { 212338d5c833SDouglas Gilbert bool repd; 212438d5c833SDouglas Gilbert u32 alloc_len, len; 212538d5c833SDouglas Gilbert u8 arr[16]; 212638d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 212738d5c833SDouglas Gilbert 212838d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 212938d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 213038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 213138d5c833SDouglas Gilbert if (alloc_len < 4) { 213238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 213338d5c833SDouglas Gilbert return check_condition_result; 213438d5c833SDouglas Gilbert } 213538d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 213638d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 213738d5c833SDouglas Gilbert if (repd) { 213838d5c833SDouglas Gilbert arr[3] = 0xc; 213938d5c833SDouglas Gilbert len = 16; 214038d5c833SDouglas Gilbert } else 214138d5c833SDouglas Gilbert len = 4; 214238d5c833SDouglas Gilbert 214338d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 214438d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 214538d5c833SDouglas Gilbert } 214638d5c833SDouglas Gilbert 21471da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21481da177e4SLinus Torvalds 21491da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21501da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21511da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21521da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21531da177e4SLinus Torvalds 21541da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21551da177e4SLinus Torvalds if (1 == pcontrol) 21561da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21571da177e4SLinus Torvalds return sizeof(err_recov_pg); 21581da177e4SLinus Torvalds } 21591da177e4SLinus Torvalds 21601da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21611da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21621da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21631da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21641da177e4SLinus Torvalds 21651da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21661da177e4SLinus Torvalds if (1 == pcontrol) 21671da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21681da177e4SLinus Torvalds return sizeof(disconnect_pg); 21691da177e4SLinus Torvalds } 21701da177e4SLinus Torvalds 21711da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21721da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21731da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21741da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21751da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2178773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2179773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2180773642d9SDouglas Gilbert if (sdebug_removable) 21811da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 21821da177e4SLinus Torvalds if (1 == pcontrol) 21831da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 21841da177e4SLinus Torvalds return sizeof(format_pg); 21851da177e4SLinus Torvalds } 21861da177e4SLinus Torvalds 2187fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2188fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2189fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2190fd32119bSDouglas Gilbert 21911da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 21921da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2193cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2194cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2195cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 21961da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 21971da177e4SLinus Torvalds 2198773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2199cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22001da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22011da177e4SLinus Torvalds if (1 == pcontrol) 2202cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2203cbf67842SDouglas Gilbert else if (2 == pcontrol) 2204cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22051da177e4SLinus Torvalds return sizeof(caching_pg); 22061da177e4SLinus Torvalds } 22071da177e4SLinus Torvalds 2208fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2209fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2210fd32119bSDouglas Gilbert 22111da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22121da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2213c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2214c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2215c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22161da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22171da177e4SLinus Torvalds 2218773642d9SDouglas Gilbert if (sdebug_dsense) 22191da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2220c65b1445SDouglas Gilbert else 2221c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2222c6a44287SMartin K. Petersen 2223773642d9SDouglas Gilbert if (sdebug_ato) 2224c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2225c6a44287SMartin K. Petersen 22261da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22271da177e4SLinus Torvalds if (1 == pcontrol) 2228c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2229c65b1445SDouglas Gilbert else if (2 == pcontrol) 2230c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22311da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22321da177e4SLinus Torvalds } 22331da177e4SLinus Torvalds 2234c65b1445SDouglas Gilbert 22351da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22361da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2237c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22381da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2239c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2240c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2241c65b1445SDouglas Gilbert 22421da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22431da177e4SLinus Torvalds if (1 == pcontrol) 2244c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2245c65b1445SDouglas Gilbert else if (2 == pcontrol) 2246c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22471da177e4SLinus Torvalds return sizeof(iec_m_pg); 22481da177e4SLinus Torvalds } 22491da177e4SLinus Torvalds 2250c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2251c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2252c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2253c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2254c65b1445SDouglas Gilbert 2255c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2256c65b1445SDouglas Gilbert if (1 == pcontrol) 2257c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2258c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2259c65b1445SDouglas Gilbert } 2260c65b1445SDouglas Gilbert 2261c65b1445SDouglas Gilbert 2262c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2263c65b1445SDouglas Gilbert int target_dev_id) 2264c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2265c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2266c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2267773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2268773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2269c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2270c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2271c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2272c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2273773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2274773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2275c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2276c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2277c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2278c65b1445SDouglas Gilbert }; 2279c65b1445SDouglas Gilbert int port_a, port_b; 2280c65b1445SDouglas Gilbert 22811b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 22821b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 22831b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 22841b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2285c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2286c65b1445SDouglas Gilbert port_b = port_a + 1; 2287c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2288773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2289773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2290c65b1445SDouglas Gilbert if (1 == pcontrol) 2291c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2292c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2293c65b1445SDouglas Gilbert } 2294c65b1445SDouglas Gilbert 2295c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2296c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2297c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2298c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2299c65b1445SDouglas Gilbert }; 2300c65b1445SDouglas Gilbert 2301c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2302c65b1445SDouglas Gilbert if (1 == pcontrol) 2303c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2304c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2305c65b1445SDouglas Gilbert } 2306c65b1445SDouglas Gilbert 23071da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23081da177e4SLinus Torvalds 2309fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2310fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23111da177e4SLinus Torvalds { 231223183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23131da177e4SLinus Torvalds unsigned char dev_spec; 2314760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2315c2248fc9SDouglas Gilbert int target = scp->device->id; 23161da177e4SLinus Torvalds unsigned char *ap; 23171da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 231801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2319d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23201da177e4SLinus Torvalds 2321760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23221da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23231da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23241da177e4SLinus Torvalds subpcode = cmd[3]; 23251da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2326760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2327760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 232864e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2329d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 233023183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 233123183910SDouglas Gilbert else 233223183910SDouglas Gilbert bd_len = 0; 2333773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23341da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23351da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2336cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23371da177e4SLinus Torvalds return check_condition_result; 23381da177e4SLinus Torvalds } 2339c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2340c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2341d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2342d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2343b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23449447b6ceSMartin K. Petersen if (sdebug_wp) 23459447b6ceSMartin K. Petersen dev_spec |= 0x80; 23469447b6ceSMartin K. Petersen } else 234723183910SDouglas Gilbert dev_spec = 0x0; 23481da177e4SLinus Torvalds if (msense_6) { 23491da177e4SLinus Torvalds arr[2] = dev_spec; 235023183910SDouglas Gilbert arr[3] = bd_len; 23511da177e4SLinus Torvalds offset = 4; 23521da177e4SLinus Torvalds } else { 23531da177e4SLinus Torvalds arr[3] = dev_spec; 235423183910SDouglas Gilbert if (16 == bd_len) 235523183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 235623183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23571da177e4SLinus Torvalds offset = 8; 23581da177e4SLinus Torvalds } 23591da177e4SLinus Torvalds ap = arr + offset; 236028898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 236128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 236228898873SFUJITA Tomonori 236323183910SDouglas Gilbert if (8 == bd_len) { 2364773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2365773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2366773642d9SDouglas Gilbert else 2367773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2368773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 236923183910SDouglas Gilbert offset += bd_len; 237023183910SDouglas Gilbert ap = arr + offset; 237123183910SDouglas Gilbert } else if (16 == bd_len) { 2372773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2373773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 237423183910SDouglas Gilbert offset += bd_len; 237523183910SDouglas Gilbert ap = arr + offset; 237623183910SDouglas Gilbert } 23771da177e4SLinus Torvalds 2378c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2379c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 238022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 23811da177e4SLinus Torvalds return check_condition_result; 23821da177e4SLinus Torvalds } 2383760f3b03SDouglas Gilbert bad_pcode = false; 2384760f3b03SDouglas Gilbert 23851da177e4SLinus Torvalds switch (pcode) { 23861da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 23871da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 23881da177e4SLinus Torvalds offset += len; 23891da177e4SLinus Torvalds break; 23901da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 23911da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 23921da177e4SLinus Torvalds offset += len; 23931da177e4SLinus Torvalds break; 23941da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2395760f3b03SDouglas Gilbert if (is_disk) { 23961da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 23971da177e4SLinus Torvalds offset += len; 2398760f3b03SDouglas Gilbert } else 2399760f3b03SDouglas Gilbert bad_pcode = true; 24001da177e4SLinus Torvalds break; 24011da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2402d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24031da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24041da177e4SLinus Torvalds offset += len; 2405760f3b03SDouglas Gilbert } else 2406760f3b03SDouglas Gilbert bad_pcode = true; 24071da177e4SLinus Torvalds break; 24081da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24091da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24101da177e4SLinus Torvalds offset += len; 24111da177e4SLinus Torvalds break; 2412c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2413c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 241422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2415c65b1445SDouglas Gilbert return check_condition_result; 2416c65b1445SDouglas Gilbert } 2417c65b1445SDouglas Gilbert len = 0; 2418c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2419c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2420c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2421c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2422c65b1445SDouglas Gilbert target_dev_id); 2423c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2424c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2425c65b1445SDouglas Gilbert offset += len; 2426c65b1445SDouglas Gilbert break; 24271da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24281da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24291da177e4SLinus Torvalds offset += len; 24301da177e4SLinus Torvalds break; 24311da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2432c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24331da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24341da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2435760f3b03SDouglas Gilbert if (is_disk) { 2436760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2437760f3b03SDouglas Gilbert target); 2438760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2439760f3b03SDouglas Gilbert target); 2440d36da305SDouglas Gilbert } else if (is_zbc) { 2441d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2442d36da305SDouglas Gilbert target); 2443760f3b03SDouglas Gilbert } 24441da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2445c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2446c65b1445SDouglas Gilbert if (0xff == subpcode) { 2447c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2448c65b1445SDouglas Gilbert target, target_dev_id); 2449c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2450c65b1445SDouglas Gilbert } 24511da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2452760f3b03SDouglas Gilbert offset += len; 2453c65b1445SDouglas Gilbert } else { 245422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2455c65b1445SDouglas Gilbert return check_condition_result; 2456c65b1445SDouglas Gilbert } 24571da177e4SLinus Torvalds break; 24581da177e4SLinus Torvalds default: 2459760f3b03SDouglas Gilbert bad_pcode = true; 2460760f3b03SDouglas Gilbert break; 2461760f3b03SDouglas Gilbert } 2462760f3b03SDouglas Gilbert if (bad_pcode) { 246322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24641da177e4SLinus Torvalds return check_condition_result; 24651da177e4SLinus Torvalds } 24661da177e4SLinus Torvalds if (msense_6) 24671da177e4SLinus Torvalds arr[0] = offset - 1; 2468773642d9SDouglas Gilbert else 2469773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 247087c715dcSDouglas Gilbert return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset)); 24711da177e4SLinus Torvalds } 24721da177e4SLinus Torvalds 2473c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2474c65b1445SDouglas Gilbert 2475fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2476fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2477c65b1445SDouglas Gilbert { 2478c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2479c2248fc9SDouglas Gilbert int param_len, res, mpage; 2480c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 248101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2482c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2483c65b1445SDouglas Gilbert 2484c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2485c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2486c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2487773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2488c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 248922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2490c65b1445SDouglas Gilbert return check_condition_result; 2491c65b1445SDouglas Gilbert } 2492c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2493c65b1445SDouglas Gilbert if (-1 == res) 2494773642d9SDouglas Gilbert return DID_ERROR << 16; 2495773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2496cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2497cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2498cbf67842SDouglas Gilbert __func__, param_len, res); 2499773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2500773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 250123183910SDouglas Gilbert if (md_len > 2) { 250222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2503c65b1445SDouglas Gilbert return check_condition_result; 2504c65b1445SDouglas Gilbert } 2505c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2506c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2507c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2508c65b1445SDouglas Gilbert if (ps) { 250922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2510c65b1445SDouglas Gilbert return check_condition_result; 2511c65b1445SDouglas Gilbert } 2512c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2513773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2514c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2515c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2516cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2517c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2518c65b1445SDouglas Gilbert return check_condition_result; 2519c65b1445SDouglas Gilbert } 2520c65b1445SDouglas Gilbert switch (mpage) { 2521cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2522cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2523cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2524cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2525cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2526cbf67842SDouglas Gilbert } 2527cbf67842SDouglas Gilbert break; 2528c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2529c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2530c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2531c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25329447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25339447b6ceSMartin K. Petersen sdebug_wp = true; 25349447b6ceSMartin K. Petersen else 25359447b6ceSMartin K. Petersen sdebug_wp = false; 2536773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2537cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2538c65b1445SDouglas Gilbert } 2539c65b1445SDouglas Gilbert break; 2540c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2541c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2542c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2543c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2544cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2545c65b1445SDouglas Gilbert } 2546c65b1445SDouglas Gilbert break; 2547c65b1445SDouglas Gilbert default: 2548c65b1445SDouglas Gilbert break; 2549c65b1445SDouglas Gilbert } 255022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2551c65b1445SDouglas Gilbert return check_condition_result; 2552cbf67842SDouglas Gilbert set_mode_changed_ua: 2553cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2554cbf67842SDouglas Gilbert return 0; 2555c65b1445SDouglas Gilbert } 2556c65b1445SDouglas Gilbert 2557c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2558c65b1445SDouglas Gilbert { 2559c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2560c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2561c65b1445SDouglas Gilbert }; 2562c65b1445SDouglas Gilbert 2563c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2564c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2565c65b1445SDouglas Gilbert } 2566c65b1445SDouglas Gilbert 2567c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2568c65b1445SDouglas Gilbert { 2569c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2570c65b1445SDouglas Gilbert }; 2571c65b1445SDouglas Gilbert 2572c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2573c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2574c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2575c65b1445SDouglas Gilbert arr[5] = 0xff; 2576c65b1445SDouglas Gilbert } 2577c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2578c65b1445SDouglas Gilbert } 2579c65b1445SDouglas Gilbert 2580c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2581c65b1445SDouglas Gilbert 2582c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2583c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2584c65b1445SDouglas Gilbert { 2585ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2586c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 258701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2588c65b1445SDouglas Gilbert 2589c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2590c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2591c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2592c65b1445SDouglas Gilbert if (ppc || sp) { 259322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2594c65b1445SDouglas Gilbert return check_condition_result; 2595c65b1445SDouglas Gilbert } 2596c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 259723183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2598773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2599c65b1445SDouglas Gilbert arr[0] = pcode; 260023183910SDouglas Gilbert if (0 == subpcode) { 2601c65b1445SDouglas Gilbert switch (pcode) { 2602c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2603c65b1445SDouglas Gilbert n = 4; 2604c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2605c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2606c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2607c65b1445SDouglas Gilbert arr[3] = n - 4; 2608c65b1445SDouglas Gilbert break; 2609c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2610c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2611c65b1445SDouglas Gilbert break; 2612c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2613c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2614c65b1445SDouglas Gilbert break; 2615c65b1445SDouglas Gilbert default: 261622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2617c65b1445SDouglas Gilbert return check_condition_result; 2618c65b1445SDouglas Gilbert } 261923183910SDouglas Gilbert } else if (0xff == subpcode) { 262023183910SDouglas Gilbert arr[0] |= 0x40; 262123183910SDouglas Gilbert arr[1] = subpcode; 262223183910SDouglas Gilbert switch (pcode) { 262323183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 262423183910SDouglas Gilbert n = 4; 262523183910SDouglas Gilbert arr[n++] = 0x0; 262623183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 262723183910SDouglas Gilbert arr[n++] = 0x0; 262823183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 262923183910SDouglas Gilbert arr[n++] = 0xd; 263023183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 263123183910SDouglas Gilbert arr[n++] = 0x2f; 263223183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 263323183910SDouglas Gilbert arr[3] = n - 4; 263423183910SDouglas Gilbert break; 263523183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 263623183910SDouglas Gilbert n = 4; 263723183910SDouglas Gilbert arr[n++] = 0xd; 263823183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 263923183910SDouglas Gilbert arr[3] = n - 4; 264023183910SDouglas Gilbert break; 264123183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 264223183910SDouglas Gilbert n = 4; 264323183910SDouglas Gilbert arr[n++] = 0x2f; 264423183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 264523183910SDouglas Gilbert arr[3] = n - 4; 264623183910SDouglas Gilbert break; 264723183910SDouglas Gilbert default: 264822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 264923183910SDouglas Gilbert return check_condition_result; 265023183910SDouglas Gilbert } 265123183910SDouglas Gilbert } else { 265222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 265323183910SDouglas Gilbert return check_condition_result; 265423183910SDouglas Gilbert } 265587c715dcSDouglas Gilbert len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len); 2656c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 265787c715dcSDouglas Gilbert min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ)); 2658c65b1445SDouglas Gilbert } 2659c65b1445SDouglas Gilbert 2660f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2661f0d1cf93SDouglas Gilbert { 2662f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2663f0d1cf93SDouglas Gilbert } 2664f0d1cf93SDouglas Gilbert 2665f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2666f0d1cf93SDouglas Gilbert unsigned long long lba) 2667f0d1cf93SDouglas Gilbert { 2668108e36f0SDamien Le Moal return &devip->zstate[lba >> devip->zsize_shift]; 2669f0d1cf93SDouglas Gilbert } 2670f0d1cf93SDouglas Gilbert 2671f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2672f0d1cf93SDouglas Gilbert { 267364e14eceSDamien Le Moal return zsp->z_type == ZBC_ZONE_TYPE_CNV; 2674f0d1cf93SDouglas Gilbert } 2675f0d1cf93SDouglas Gilbert 2676f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2677f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2678f0d1cf93SDouglas Gilbert { 2679f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2680f0d1cf93SDouglas Gilbert 2681f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2682f0d1cf93SDouglas Gilbert return; 2683f0d1cf93SDouglas Gilbert 2684f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2685f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2686f0d1cf93SDouglas Gilbert return; 2687f0d1cf93SDouglas Gilbert 2688f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2689f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2690f0d1cf93SDouglas Gilbert else 2691f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2692f0d1cf93SDouglas Gilbert 2693f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2694f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2695f0d1cf93SDouglas Gilbert } else { 2696f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2697f0d1cf93SDouglas Gilbert devip->nr_closed++; 2698f0d1cf93SDouglas Gilbert } 2699f0d1cf93SDouglas Gilbert } 2700f0d1cf93SDouglas Gilbert 2701f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2702f0d1cf93SDouglas Gilbert { 2703f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2704f0d1cf93SDouglas Gilbert unsigned int i; 2705f0d1cf93SDouglas Gilbert 2706f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2707f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2708f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2709f0d1cf93SDouglas Gilbert return; 2710f0d1cf93SDouglas Gilbert } 2711f0d1cf93SDouglas Gilbert } 2712f0d1cf93SDouglas Gilbert } 2713f0d1cf93SDouglas Gilbert 2714f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2715f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2716f0d1cf93SDouglas Gilbert { 2717f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2718f0d1cf93SDouglas Gilbert 2719f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2720f0d1cf93SDouglas Gilbert return; 2721f0d1cf93SDouglas Gilbert 2722f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2723f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2724f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2725f0d1cf93SDouglas Gilbert return; 2726f0d1cf93SDouglas Gilbert 2727f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2728f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2729f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2730f0d1cf93SDouglas Gilbert else if (devip->max_open && 2731f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2732f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2733f0d1cf93SDouglas Gilbert 2734f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2735f0d1cf93SDouglas Gilbert devip->nr_closed--; 2736f0d1cf93SDouglas Gilbert if (explicit) { 2737f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2738f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2739f0d1cf93SDouglas Gilbert } else { 2740f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2741f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2742f0d1cf93SDouglas Gilbert } 2743f0d1cf93SDouglas Gilbert } 2744f0d1cf93SDouglas Gilbert 2745f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2746f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2747f0d1cf93SDouglas Gilbert { 2748f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 274964e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2750f0d1cf93SDouglas Gilbert 2751f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2752f0d1cf93SDouglas Gilbert return; 2753f0d1cf93SDouglas Gilbert 275464e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2755f0d1cf93SDouglas Gilbert zsp->z_wp += num; 275664e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2757f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 275864e14eceSDamien Le Moal return; 275964e14eceSDamien Le Moal } 276064e14eceSDamien Le Moal 276164e14eceSDamien Le Moal while (num) { 276264e14eceSDamien Le Moal if (lba != zsp->z_wp) 276364e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 276464e14eceSDamien Le Moal 276564e14eceSDamien Le Moal end = lba + num; 276664e14eceSDamien Le Moal if (end >= zend) { 276764e14eceSDamien Le Moal n = zend - lba; 276864e14eceSDamien Le Moal zsp->z_wp = zend; 276964e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 277064e14eceSDamien Le Moal n = num; 277164e14eceSDamien Le Moal zsp->z_wp = end; 277264e14eceSDamien Le Moal } else { 277364e14eceSDamien Le Moal n = num; 277464e14eceSDamien Le Moal } 277564e14eceSDamien Le Moal if (zsp->z_wp >= zend) 277664e14eceSDamien Le Moal zsp->z_cond = ZC5_FULL; 277764e14eceSDamien Le Moal 277864e14eceSDamien Le Moal num -= n; 277964e14eceSDamien Le Moal lba += n; 278064e14eceSDamien Le Moal if (num) { 278164e14eceSDamien Le Moal zsp++; 278264e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 278364e14eceSDamien Le Moal } 278464e14eceSDamien Le Moal } 2785f0d1cf93SDouglas Gilbert } 2786f0d1cf93SDouglas Gilbert 2787f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 27889447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 27891da177e4SLinus Torvalds { 2790f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2791f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2792f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2793f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2794f0d1cf93SDouglas Gilbert 2795f0d1cf93SDouglas Gilbert if (!write) { 279664e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 279764e14eceSDamien Le Moal return 0; 279864e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 2799f0d1cf93SDouglas Gilbert if (zsp_end != zsp && 2800f0d1cf93SDouglas Gilbert zbc_zone_is_conv(zsp) && 2801f0d1cf93SDouglas Gilbert !zbc_zone_is_conv(zsp_end)) { 2802f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2803f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2804f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2805f0d1cf93SDouglas Gilbert return check_condition_result; 2806f0d1cf93SDouglas Gilbert } 2807f0d1cf93SDouglas Gilbert return 0; 2808f0d1cf93SDouglas Gilbert } 2809f0d1cf93SDouglas Gilbert 2810f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2811f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2812f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2813f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2814f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2815f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2816f0d1cf93SDouglas Gilbert return check_condition_result; 2817f0d1cf93SDouglas Gilbert } 2818f0d1cf93SDouglas Gilbert return 0; 2819f0d1cf93SDouglas Gilbert } 2820f0d1cf93SDouglas Gilbert 282164e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2822f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2823f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2824f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2825f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2826f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2827f0d1cf93SDouglas Gilbert return check_condition_result; 2828f0d1cf93SDouglas Gilbert } 2829f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2830f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2831f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2832f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2833f0d1cf93SDouglas Gilbert return check_condition_result; 2834f0d1cf93SDouglas Gilbert } 2835f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2836f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2837f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2838f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2839f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2840f0d1cf93SDouglas Gilbert return check_condition_result; 2841f0d1cf93SDouglas Gilbert } 284264e14eceSDamien Le Moal } 2843f0d1cf93SDouglas Gilbert 2844f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2845f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2846f0d1cf93SDouglas Gilbert if (devip->max_open && 2847f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2848f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2849f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2850f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2851f0d1cf93SDouglas Gilbert return check_condition_result; 2852f0d1cf93SDouglas Gilbert } 2853f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2854f0d1cf93SDouglas Gilbert } 2855f0d1cf93SDouglas Gilbert 2856f0d1cf93SDouglas Gilbert return 0; 2857f0d1cf93SDouglas Gilbert } 2858f0d1cf93SDouglas Gilbert 2859f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2860f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2861f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2862f0d1cf93SDouglas Gilbert { 2863f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2864f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2865f0d1cf93SDouglas Gilbert 2866c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 286722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 28681da177e4SLinus Torvalds return check_condition_result; 28691da177e4SLinus Torvalds } 2870c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2871c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 287222017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2873cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2874c65b1445SDouglas Gilbert return check_condition_result; 2875c65b1445SDouglas Gilbert } 28769447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 28779447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 28789447b6ceSMartin K. Petersen return check_condition_result; 28799447b6ceSMartin K. Petersen } 2880f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2881f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2882f0d1cf93SDouglas Gilbert 288319789100SFUJITA Tomonori return 0; 288419789100SFUJITA Tomonori } 288519789100SFUJITA Tomonori 2886b6ff8ca7SDouglas Gilbert /* 2887b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 2888b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 2889b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 2890b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 2891b6ff8ca7SDouglas Gilbert */ 2892b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 2893b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 289487c715dcSDouglas Gilbert { 2895b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 2896b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 2897b6ff8ca7SDouglas Gilbert return NULL; 2898b6ff8ca7SDouglas Gilbert } 2899b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 290087c715dcSDouglas Gilbert } 290187c715dcSDouglas Gilbert 2902a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 290387c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 290487c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 290519789100SFUJITA Tomonori { 290619789100SFUJITA Tomonori int ret; 2907c2248fc9SDouglas Gilbert u64 block, rest = 0; 2908a4517511SAkinobu Mita enum dma_data_direction dir; 290987c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 291087c715dcSDouglas Gilbert u8 *fsp; 291119789100SFUJITA Tomonori 2912c2248fc9SDouglas Gilbert if (do_write) { 2913a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 29144f2c8bf6SDouglas Gilbert write_since_sync = true; 2915a4517511SAkinobu Mita } else { 2916a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2917a4517511SAkinobu Mita } 2918a4517511SAkinobu Mita 291987c715dcSDouglas Gilbert if (!sdb->length || !sip) 2920a4517511SAkinobu Mita return 0; 292187c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2922a4517511SAkinobu Mita return -1; 292387c715dcSDouglas Gilbert fsp = sip->storep; 292419789100SFUJITA Tomonori 292519789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 292619789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 292719789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 292819789100SFUJITA Tomonori 2929386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 293087c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 29310a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2932773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2933a4517511SAkinobu Mita return ret; 2934a4517511SAkinobu Mita 2935a4517511SAkinobu Mita if (rest) { 2936386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 293787c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 29380a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 29390a7e69c7SDouglas Gilbert do_write); 2940a4517511SAkinobu Mita } 294119789100SFUJITA Tomonori 294219789100SFUJITA Tomonori return ret; 294319789100SFUJITA Tomonori } 294419789100SFUJITA Tomonori 294587c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 294687c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 294787c715dcSDouglas Gilbert { 294887c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 294987c715dcSDouglas Gilbert 295087c715dcSDouglas Gilbert if (!sdb->length) 295187c715dcSDouglas Gilbert return 0; 295287c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 295387c715dcSDouglas Gilbert return -1; 295487c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 295587c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 295687c715dcSDouglas Gilbert } 295787c715dcSDouglas Gilbert 295887c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 295987c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 296038d5c833SDouglas Gilbert * return false. */ 296187c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 2962c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 296338d5c833SDouglas Gilbert { 296438d5c833SDouglas Gilbert bool res; 296538d5c833SDouglas Gilbert u64 block, rest = 0; 296638d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2967773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 296887c715dcSDouglas Gilbert u8 *fsp = sip->storep; 296938d5c833SDouglas Gilbert 297038d5c833SDouglas Gilbert block = do_div(lba, store_blks); 297138d5c833SDouglas Gilbert if (block + num > store_blks) 297238d5c833SDouglas Gilbert rest = block + num - store_blks; 297338d5c833SDouglas Gilbert 297487c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 297538d5c833SDouglas Gilbert if (!res) 297638d5c833SDouglas Gilbert return res; 297738d5c833SDouglas Gilbert if (rest) 297887c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 297938d5c833SDouglas Gilbert rest * lb_size); 298038d5c833SDouglas Gilbert if (!res) 298138d5c833SDouglas Gilbert return res; 2982c3e2fe92SDouglas Gilbert if (compare_only) 2983c3e2fe92SDouglas Gilbert return true; 298438d5c833SDouglas Gilbert arr += num * lb_size; 298587c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 298638d5c833SDouglas Gilbert if (rest) 298787c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 298838d5c833SDouglas Gilbert return res; 298938d5c833SDouglas Gilbert } 299038d5c833SDouglas Gilbert 299151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2992beb40ea4SAkinobu Mita { 299351d648afSAkinobu Mita __be16 csum; 2994beb40ea4SAkinobu Mita 2995773642d9SDouglas Gilbert if (sdebug_guard) 299651d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 299751d648afSAkinobu Mita else 2998beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 299951d648afSAkinobu Mita 3000beb40ea4SAkinobu Mita return csum; 3001beb40ea4SAkinobu Mita } 3002beb40ea4SAkinobu Mita 30036ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3004beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3005beb40ea4SAkinobu Mita { 3006773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3007beb40ea4SAkinobu Mita 3008beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3009c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3010beb40ea4SAkinobu Mita (unsigned long)sector, 3011beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3012beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3013beb40ea4SAkinobu Mita return 0x01; 3014beb40ea4SAkinobu Mita } 30158475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3016beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3017c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3018c1287970STomas Winkler (unsigned long)sector); 3019beb40ea4SAkinobu Mita return 0x03; 3020beb40ea4SAkinobu Mita } 30218475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3022beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3023c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3024c1287970STomas Winkler (unsigned long)sector); 3025beb40ea4SAkinobu Mita return 0x03; 3026beb40ea4SAkinobu Mita } 3027beb40ea4SAkinobu Mita return 0; 3028beb40ea4SAkinobu Mita } 3029beb40ea4SAkinobu Mita 303087c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 303165f72f2aSAkinobu Mita unsigned int sectors, bool read) 3032c6a44287SMartin K. Petersen { 3033be4e11beSAkinobu Mita size_t resid; 3034c6a44287SMartin K. Petersen void *paddr; 303587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3036b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 303787c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 303814faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3039be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3040c6a44287SMartin K. Petersen 3041e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3042e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3043c6a44287SMartin K. Petersen 304487c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 304587c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3046be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3047be4e11beSAkinobu Mita 3048be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 304987c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 305087c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3051be4e11beSAkinobu Mita size_t rest = 0; 305214faa944SAkinobu Mita 305314faa944SAkinobu Mita if (dif_store_end < start + len) 305414faa944SAkinobu Mita rest = start + len - dif_store_end; 3055c6a44287SMartin K. Petersen 3056be4e11beSAkinobu Mita paddr = miter.addr; 305714faa944SAkinobu Mita 305865f72f2aSAkinobu Mita if (read) 305965f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 306065f72f2aSAkinobu Mita else 306165f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 306265f72f2aSAkinobu Mita 306365f72f2aSAkinobu Mita if (rest) { 306465f72f2aSAkinobu Mita if (read) 306514faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 306665f72f2aSAkinobu Mita else 306765f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 306865f72f2aSAkinobu Mita } 3069c6a44287SMartin K. Petersen 3070e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3071c6a44287SMartin K. Petersen resid -= len; 3072c6a44287SMartin K. Petersen } 3073be4e11beSAkinobu Mita sg_miter_stop(&miter); 3074bb8c063cSAkinobu Mita } 3075c6a44287SMartin K. Petersen 307687c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3077bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3078bb8c063cSAkinobu Mita { 3079f7be6772SMartin K. Petersen int ret = 0; 3080bb8c063cSAkinobu Mita unsigned int i; 3081bb8c063cSAkinobu Mita sector_t sector; 308287c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3083b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 308487c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3085bb8c063cSAkinobu Mita 3086c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3087bb8c063cSAkinobu Mita sector = start_sec + i; 308887c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3089bb8c063cSAkinobu Mita 309051d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3091bb8c063cSAkinobu Mita continue; 3092bb8c063cSAkinobu Mita 3093f7be6772SMartin K. Petersen /* 3094f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3095f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3096f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3097f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3098f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3099f7be6772SMartin K. Petersen */ 3100f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3101f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3102f7be6772SMartin K. Petersen sector, ei_lba); 3103bb8c063cSAkinobu Mita if (ret) { 3104bb8c063cSAkinobu Mita dif_errors++; 3105f7be6772SMartin K. Petersen break; 3106f7be6772SMartin K. Petersen } 3107bb8c063cSAkinobu Mita } 3108bb8c063cSAkinobu Mita } 3109bb8c063cSAkinobu Mita 311087c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3111c6a44287SMartin K. Petersen dix_reads++; 3112c6a44287SMartin K. Petersen 3113f7be6772SMartin K. Petersen return ret; 3114c6a44287SMartin K. Petersen } 3115c6a44287SMartin K. Petersen 3116fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 311719789100SFUJITA Tomonori { 311887c715dcSDouglas Gilbert bool check_prot; 3119c2248fc9SDouglas Gilbert u32 num; 3120c2248fc9SDouglas Gilbert u32 ei_lba; 312119789100SFUJITA Tomonori int ret; 312287c715dcSDouglas Gilbert u64 lba; 3123b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 312487c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 312587c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 312619789100SFUJITA Tomonori 3127c2248fc9SDouglas Gilbert switch (cmd[0]) { 3128c2248fc9SDouglas Gilbert case READ_16: 3129c2248fc9SDouglas Gilbert ei_lba = 0; 3130c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3131c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3132c2248fc9SDouglas Gilbert check_prot = true; 3133c2248fc9SDouglas Gilbert break; 3134c2248fc9SDouglas Gilbert case READ_10: 3135c2248fc9SDouglas Gilbert ei_lba = 0; 3136c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3137c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3138c2248fc9SDouglas Gilbert check_prot = true; 3139c2248fc9SDouglas Gilbert break; 3140c2248fc9SDouglas Gilbert case READ_6: 3141c2248fc9SDouglas Gilbert ei_lba = 0; 3142c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3143c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3144c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3145c2248fc9SDouglas Gilbert check_prot = true; 3146c2248fc9SDouglas Gilbert break; 3147c2248fc9SDouglas Gilbert case READ_12: 3148c2248fc9SDouglas Gilbert ei_lba = 0; 3149c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3150c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3151c2248fc9SDouglas Gilbert check_prot = true; 3152c2248fc9SDouglas Gilbert break; 3153c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3154c2248fc9SDouglas Gilbert ei_lba = 0; 3155c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3156c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3157c2248fc9SDouglas Gilbert check_prot = false; 3158c2248fc9SDouglas Gilbert break; 3159c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3160c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3161c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3162c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3163c2248fc9SDouglas Gilbert check_prot = false; 3164c2248fc9SDouglas Gilbert break; 3165c2248fc9SDouglas Gilbert } 3166f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 31678475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3168c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3169c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3170c2248fc9SDouglas Gilbert return check_condition_result; 3171c2248fc9SDouglas Gilbert } 31728475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31738475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3174c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3175c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3176c2248fc9SDouglas Gilbert "to DIF device\n"); 3177c2248fc9SDouglas Gilbert } 31783a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 31793a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3180c2248fc9SDouglas Gilbert num /= 2; 31813a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3182c2248fc9SDouglas Gilbert } 3183c2248fc9SDouglas Gilbert 31849447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 31859447b6ceSMartin K. Petersen if (ret) 31869447b6ceSMartin K. Petersen return ret; 3187f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3188d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3189d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3190c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3191c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3192c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3193c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3194c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 319532f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 319632f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3197c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3198c65b1445SDouglas Gilbert } 3199c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 32001da177e4SLinus Torvalds return check_condition_result; 32011da177e4SLinus Torvalds } 3202c6a44287SMartin K. Petersen 320367da413fSDouglas Gilbert read_lock(macc_lckp); 32046c78cc06SAkinobu Mita 3205c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3206f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3207f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3208f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3209f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 321067da413fSDouglas Gilbert read_unlock(macc_lckp); 3211f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3212f7be6772SMartin K. Petersen return check_condition_result; 3213f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 3214f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3215f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3216c6a44287SMartin K. Petersen return illegal_condition_result; 3217c6a44287SMartin K. Petersen } 3218f7be6772SMartin K. Petersen break; 3219f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3220f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 3221f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3222f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3223f7be6772SMartin K. Petersen return check_condition_result; 3224f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 3225f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3226f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3227f7be6772SMartin K. Petersen return illegal_condition_result; 3228f7be6772SMartin K. Petersen } 3229f7be6772SMartin K. Petersen break; 3230f7be6772SMartin K. Petersen } 3231c6a44287SMartin K. Petersen } 3232c6a44287SMartin K. Petersen 323387c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 323467da413fSDouglas Gilbert read_unlock(macc_lckp); 3235f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3236a4517511SAkinobu Mita return DID_ERROR << 16; 3237a4517511SAkinobu Mita 323842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3239a4517511SAkinobu Mita 32403a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 32413a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 32423a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 32433a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 32443a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3245c2248fc9SDouglas Gilbert return check_condition_result; 32463a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3247c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3248c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 32493a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3250c2248fc9SDouglas Gilbert return illegal_condition_result; 32513a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3252c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 32533a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3254c2248fc9SDouglas Gilbert return illegal_condition_result; 3255c2248fc9SDouglas Gilbert } 3256c2248fc9SDouglas Gilbert } 3257a4517511SAkinobu Mita return 0; 32581da177e4SLinus Torvalds } 32591da177e4SLinus Torvalds 3260c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3261395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3262c6a44287SMartin K. Petersen { 3263be4e11beSAkinobu Mita int ret; 32646ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3265be4e11beSAkinobu Mita void *daddr; 326665f72f2aSAkinobu Mita sector_t sector = start_sec; 3267c6a44287SMartin K. Petersen int ppage_offset; 3268be4e11beSAkinobu Mita int dpage_offset; 3269be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3270be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3271c6a44287SMartin K. Petersen 3272c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3273c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3274c6a44287SMartin K. Petersen 3275be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3276be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3277be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3278be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3279be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3280c6a44287SMartin K. Petersen 3281be4e11beSAkinobu Mita /* For each protection page */ 3282be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3283be4e11beSAkinobu Mita dpage_offset = 0; 3284be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3285be4e11beSAkinobu Mita ret = 0x01; 3286be4e11beSAkinobu Mita goto out; 3287c6a44287SMartin K. Petersen } 3288c6a44287SMartin K. Petersen 3289be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 32906ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3291be4e11beSAkinobu Mita /* If we're at the end of the current 3292be4e11beSAkinobu Mita * data page advance to the next one 3293be4e11beSAkinobu Mita */ 3294be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3295be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3296be4e11beSAkinobu Mita ret = 0x01; 3297be4e11beSAkinobu Mita goto out; 3298be4e11beSAkinobu Mita } 3299be4e11beSAkinobu Mita dpage_offset = 0; 3300be4e11beSAkinobu Mita } 3301c6a44287SMartin K. Petersen 3302be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3303be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3304be4e11beSAkinobu Mita 3305f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3306be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3307c78be80dSMartin K. Petersen if (ret) 3308395cef03SMartin K. Petersen goto out; 3309f7be6772SMartin K. Petersen } 3310395cef03SMartin K. Petersen 3311c6a44287SMartin K. Petersen sector++; 3312395cef03SMartin K. Petersen ei_lba++; 3313773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3314c6a44287SMartin K. Petersen } 3315be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3316be4e11beSAkinobu Mita sg_miter_stop(&diter); 3317c6a44287SMartin K. Petersen } 3318be4e11beSAkinobu Mita sg_miter_stop(&piter); 3319c6a44287SMartin K. Petersen 332065f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3321c6a44287SMartin K. Petersen dix_writes++; 3322c6a44287SMartin K. Petersen 3323c6a44287SMartin K. Petersen return 0; 3324c6a44287SMartin K. Petersen 3325c6a44287SMartin K. Petersen out: 3326c6a44287SMartin K. Petersen dif_errors++; 3327be4e11beSAkinobu Mita sg_miter_stop(&diter); 3328be4e11beSAkinobu Mita sg_miter_stop(&piter); 3329c6a44287SMartin K. Petersen return ret; 3330c6a44287SMartin K. Petersen } 3331c6a44287SMartin K. Petersen 3332b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3333b90ebc3dSAkinobu Mita { 3334773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3335773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3336773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3337b90ebc3dSAkinobu Mita return lba; 3338b90ebc3dSAkinobu Mita } 3339b90ebc3dSAkinobu Mita 3340b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3341b90ebc3dSAkinobu Mita { 3342773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3343a027b5b9SAkinobu Mita 3344773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3345773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3346a027b5b9SAkinobu Mita return lba; 3347a027b5b9SAkinobu Mita } 3348a027b5b9SAkinobu Mita 334987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 335087c715dcSDouglas Gilbert unsigned int *num) 335144d92694SMartin K. Petersen { 3352b90ebc3dSAkinobu Mita sector_t end; 3353b90ebc3dSAkinobu Mita unsigned int mapped; 3354b90ebc3dSAkinobu Mita unsigned long index; 3355b90ebc3dSAkinobu Mita unsigned long next; 335644d92694SMartin K. Petersen 3357b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 335887c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 335944d92694SMartin K. Petersen 336044d92694SMartin K. Petersen if (mapped) 336187c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 336244d92694SMartin K. Petersen else 336387c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 336444d92694SMartin K. Petersen 3365b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 336644d92694SMartin K. Petersen *num = end - lba; 336744d92694SMartin K. Petersen return mapped; 336844d92694SMartin K. Petersen } 336944d92694SMartin K. Petersen 337087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 337187c715dcSDouglas Gilbert unsigned int len) 337244d92694SMartin K. Petersen { 337344d92694SMartin K. Petersen sector_t end = lba + len; 337444d92694SMartin K. Petersen 337544d92694SMartin K. Petersen while (lba < end) { 3376b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 337744d92694SMartin K. Petersen 3378b90ebc3dSAkinobu Mita if (index < map_size) 337987c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 338044d92694SMartin K. Petersen 3381b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 338244d92694SMartin K. Petersen } 338344d92694SMartin K. Petersen } 338444d92694SMartin K. Petersen 338587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 338687c715dcSDouglas Gilbert unsigned int len) 338744d92694SMartin K. Petersen { 338844d92694SMartin K. Petersen sector_t end = lba + len; 338987c715dcSDouglas Gilbert u8 *fsp = sip->storep; 339044d92694SMartin K. Petersen 339144d92694SMartin K. Petersen while (lba < end) { 3392b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 339344d92694SMartin K. Petersen 3394b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3395773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3396b90ebc3dSAkinobu Mita index < map_size) { 339787c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3398760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 339987c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3400760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3401773642d9SDouglas Gilbert sdebug_sector_size * 3402773642d9SDouglas Gilbert sdebug_unmap_granularity); 3403be1dd78dSEric Sandeen } 340487c715dcSDouglas Gilbert if (sip->dif_storep) { 340587c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 340687c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3407773642d9SDouglas Gilbert sdebug_unmap_granularity); 3408e9926b43SAkinobu Mita } 3409b90ebc3dSAkinobu Mita } 3410b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 341144d92694SMartin K. Petersen } 341244d92694SMartin K. Petersen } 341344d92694SMartin K. Petersen 3414fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 34151da177e4SLinus Torvalds { 341687c715dcSDouglas Gilbert bool check_prot; 3417c2248fc9SDouglas Gilbert u32 num; 3418c2248fc9SDouglas Gilbert u32 ei_lba; 341919789100SFUJITA Tomonori int ret; 342087c715dcSDouglas Gilbert u64 lba; 3421b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3422b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 342387c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 34241da177e4SLinus Torvalds 3425c2248fc9SDouglas Gilbert switch (cmd[0]) { 3426c2248fc9SDouglas Gilbert case WRITE_16: 3427c2248fc9SDouglas Gilbert ei_lba = 0; 3428c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3429c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3430c2248fc9SDouglas Gilbert check_prot = true; 3431c2248fc9SDouglas Gilbert break; 3432c2248fc9SDouglas Gilbert case WRITE_10: 3433c2248fc9SDouglas Gilbert ei_lba = 0; 3434c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3435c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3436c2248fc9SDouglas Gilbert check_prot = true; 3437c2248fc9SDouglas Gilbert break; 3438c2248fc9SDouglas Gilbert case WRITE_6: 3439c2248fc9SDouglas Gilbert ei_lba = 0; 3440c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3441c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3442c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3443c2248fc9SDouglas Gilbert check_prot = true; 3444c2248fc9SDouglas Gilbert break; 3445c2248fc9SDouglas Gilbert case WRITE_12: 3446c2248fc9SDouglas Gilbert ei_lba = 0; 3447c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3448c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3449c2248fc9SDouglas Gilbert check_prot = true; 3450c2248fc9SDouglas Gilbert break; 3451c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3452c2248fc9SDouglas Gilbert ei_lba = 0; 3453c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3454c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3455c2248fc9SDouglas Gilbert check_prot = false; 3456c2248fc9SDouglas Gilbert break; 3457c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3458c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3459c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3460c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3461c2248fc9SDouglas Gilbert check_prot = false; 3462c2248fc9SDouglas Gilbert break; 3463c2248fc9SDouglas Gilbert } 3464f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 34658475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3466c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3467c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3468c2248fc9SDouglas Gilbert return check_condition_result; 3469c2248fc9SDouglas Gilbert } 34708475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 34718475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3472c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3473c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3474c2248fc9SDouglas Gilbert "to DIF device\n"); 3475c2248fc9SDouglas Gilbert } 3476f0d1cf93SDouglas Gilbert 347767da413fSDouglas Gilbert write_lock(macc_lckp); 3478f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3479f0d1cf93SDouglas Gilbert if (ret) { 3480f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3481f0d1cf93SDouglas Gilbert return ret; 3482f0d1cf93SDouglas Gilbert } 34836c78cc06SAkinobu Mita 3484c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3485f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3486f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3487f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3488f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 348967da413fSDouglas Gilbert write_unlock(macc_lckp); 3490f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3491c6a44287SMartin K. Petersen return illegal_condition_result; 3492f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 3493f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3494f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3495f7be6772SMartin K. Petersen return check_condition_result; 3496f7be6772SMartin K. Petersen } 3497f7be6772SMartin K. Petersen break; 3498f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3499f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 3500f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3501f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3502f7be6772SMartin K. Petersen return illegal_condition_result; 3503f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 3504f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3505f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3506f7be6772SMartin K. Petersen return check_condition_result; 3507f7be6772SMartin K. Petersen } 3508f7be6772SMartin K. Petersen break; 3509c6a44287SMartin K. Petersen } 3510c6a44287SMartin K. Petersen } 3511c6a44287SMartin K. Petersen 351287c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3513f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 351487c715dcSDouglas Gilbert map_region(sip, lba, num); 3515f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3516f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3517f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 351867da413fSDouglas Gilbert write_unlock(macc_lckp); 3519f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3520773642d9SDouglas Gilbert return DID_ERROR << 16; 3521c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3522c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3523c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3524cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3525773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 352644d92694SMartin K. Petersen 35273a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 35283a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 35293a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 35303a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 35313a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3532c2248fc9SDouglas Gilbert return check_condition_result; 35333a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3534c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3535c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 35363a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3537c2248fc9SDouglas Gilbert return illegal_condition_result; 35383a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3539c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 35403a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3541c2248fc9SDouglas Gilbert return illegal_condition_result; 3542c2248fc9SDouglas Gilbert } 3543c2248fc9SDouglas Gilbert } 35441da177e4SLinus Torvalds return 0; 35451da177e4SLinus Torvalds } 35461da177e4SLinus Torvalds 3547481b5e5cSDouglas Gilbert /* 3548481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3549481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3550481b5e5cSDouglas Gilbert */ 3551481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3552481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3553481b5e5cSDouglas Gilbert { 3554481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3555481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3556481b5e5cSDouglas Gilbert u8 *up; 3557b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3558b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 3559481b5e5cSDouglas Gilbert u8 wrprotect; 3560481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3561481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3562481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3563481b5e5cSDouglas Gilbert u32 ei_lba; 3564481b5e5cSDouglas Gilbert u64 lba; 3565481b5e5cSDouglas Gilbert int ret, res; 3566481b5e5cSDouglas Gilbert bool is_16; 3567481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3568481b5e5cSDouglas Gilbert 3569481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3570481b5e5cSDouglas Gilbert is_16 = false; 3571481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3572481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3573481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3574481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3575481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3576481b5e5cSDouglas Gilbert is_16 = true; 3577481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3578481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3579481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3580481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3581481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3582481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3583481b5e5cSDouglas Gilbert wrprotect) { 3584481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3585481b5e5cSDouglas Gilbert return illegal_condition_result; 3586481b5e5cSDouglas Gilbert } 3587481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3588481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3589481b5e5cSDouglas Gilbert wrprotect == 0) 3590481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3591481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3592481b5e5cSDouglas Gilbert } 3593481b5e5cSDouglas Gilbert } 3594481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3595481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3596481b5e5cSDouglas Gilbert if (lbdof == 0) { 3597481b5e5cSDouglas Gilbert if (sdebug_verbose) 3598481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3599481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3600481b5e5cSDouglas Gilbert my_name, __func__); 3601481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3602481b5e5cSDouglas Gilbert return illegal_condition_result; 3603481b5e5cSDouglas Gilbert } 3604481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3605481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3606481b5e5cSDouglas Gilbert if (sdebug_verbose) 3607481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3608481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3609481b5e5cSDouglas Gilbert my_name, __func__); 3610481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3611481b5e5cSDouglas Gilbert return illegal_condition_result; 3612481b5e5cSDouglas Gilbert } 3613481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3614481b5e5cSDouglas Gilbert if (lrdp == NULL) 3615481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3616481b5e5cSDouglas Gilbert if (sdebug_verbose) 3617481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3618481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3619481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3620481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3621481b5e5cSDouglas Gilbert if (res == -1) { 3622481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3623481b5e5cSDouglas Gilbert goto err_out; 3624481b5e5cSDouglas Gilbert } 3625481b5e5cSDouglas Gilbert 362667da413fSDouglas Gilbert write_lock(macc_lckp); 3627481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3628481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3629481b5e5cSDouglas Gilbert cum_lb = 0; 3630481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3631481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3632481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3633481b5e5cSDouglas Gilbert if (sdebug_verbose) 3634481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3635481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3636481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3637481b5e5cSDouglas Gilbert if (num == 0) 3638481b5e5cSDouglas Gilbert continue; 36399447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3640481b5e5cSDouglas Gilbert if (ret) 3641481b5e5cSDouglas Gilbert goto err_out_unlock; 3642481b5e5cSDouglas Gilbert num_by = num * lb_size; 3643481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3644481b5e5cSDouglas Gilbert 3645481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3646481b5e5cSDouglas Gilbert if (sdebug_verbose) 3647481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3648481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3649481b5e5cSDouglas Gilbert my_name, __func__); 3650481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3651481b5e5cSDouglas Gilbert 0); 3652481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3653481b5e5cSDouglas Gilbert goto err_out_unlock; 3654481b5e5cSDouglas Gilbert } 3655481b5e5cSDouglas Gilbert 3656481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3657481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3658481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3659481b5e5cSDouglas Gilbert ei_lba); 3660481b5e5cSDouglas Gilbert 3661481b5e5cSDouglas Gilbert if (prot_ret) { 3662481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3663481b5e5cSDouglas Gilbert prot_ret); 3664481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3665481b5e5cSDouglas Gilbert goto err_out_unlock; 3666481b5e5cSDouglas Gilbert } 3667481b5e5cSDouglas Gilbert } 3668481b5e5cSDouglas Gilbert 366987c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3670f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3671f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3672f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3673481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 367487c715dcSDouglas Gilbert map_region(sip, lba, num); 3675481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3676481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3677481b5e5cSDouglas Gilbert goto err_out_unlock; 3678481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3679481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3680481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3681481b5e5cSDouglas Gilbert my_name, num_by, ret); 3682481b5e5cSDouglas Gilbert 36833a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 36843a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 36853a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 36863a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 36873a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 36883a90a63dSDouglas Gilbert ret = check_condition_result; 3689481b5e5cSDouglas Gilbert goto err_out_unlock; 36903a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3691481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 36923a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 36933a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3694481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3695481b5e5cSDouglas Gilbert goto err_out_unlock; 36963a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 36973a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 36983a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3699481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3700481b5e5cSDouglas Gilbert goto err_out_unlock; 3701481b5e5cSDouglas Gilbert } 3702481b5e5cSDouglas Gilbert } 3703481b5e5cSDouglas Gilbert sg_off += num_by; 3704481b5e5cSDouglas Gilbert cum_lb += num; 3705481b5e5cSDouglas Gilbert } 3706481b5e5cSDouglas Gilbert ret = 0; 3707481b5e5cSDouglas Gilbert err_out_unlock: 370867da413fSDouglas Gilbert write_unlock(macc_lckp); 3709481b5e5cSDouglas Gilbert err_out: 3710481b5e5cSDouglas Gilbert kfree(lrdp); 3711481b5e5cSDouglas Gilbert return ret; 3712481b5e5cSDouglas Gilbert } 3713481b5e5cSDouglas Gilbert 3714fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3715fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 371644d92694SMartin K. Petersen { 3717f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3718f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 371944d92694SMartin K. Petersen unsigned long long i; 372040d07b52SDouglas Gilbert u64 block, lbaa; 372187c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 372287c715dcSDouglas Gilbert int ret; 372387c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3724b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 3725b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 372640d07b52SDouglas Gilbert u8 *fs1p; 372787c715dcSDouglas Gilbert u8 *fsp; 372844d92694SMartin K. Petersen 372967da413fSDouglas Gilbert write_lock(macc_lckp); 373044d92694SMartin K. Petersen 3731f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3732f0d1cf93SDouglas Gilbert if (ret) { 3733f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3734f0d1cf93SDouglas Gilbert return ret; 3735f0d1cf93SDouglas Gilbert } 3736f0d1cf93SDouglas Gilbert 37379ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 373887c715dcSDouglas Gilbert unmap_region(sip, lba, num); 373944d92694SMartin K. Petersen goto out; 374044d92694SMartin K. Petersen } 374140d07b52SDouglas Gilbert lbaa = lba; 374240d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3743c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 374487c715dcSDouglas Gilbert fsp = sip->storep; 374587c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3746c2248fc9SDouglas Gilbert if (ndob) { 374740d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3748c2248fc9SDouglas Gilbert ret = 0; 3749c2248fc9SDouglas Gilbert } else 375040d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 375144d92694SMartin K. Petersen 375244d92694SMartin K. Petersen if (-1 == ret) { 375367da413fSDouglas Gilbert write_unlock(&sip->macc_lck); 3754773642d9SDouglas Gilbert return DID_ERROR << 16; 375540d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3756c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3757e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 375840d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 375944d92694SMartin K. Petersen 376044d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 376140d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 376240d07b52SDouglas Gilbert lbaa = lba + i; 376340d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 376487c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 376540d07b52SDouglas Gilbert } 37669ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 376787c715dcSDouglas Gilbert map_region(sip, lba, num); 3768f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3769f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3770f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 377144d92694SMartin K. Petersen out: 377267da413fSDouglas Gilbert write_unlock(macc_lckp); 377344d92694SMartin K. Petersen 377444d92694SMartin K. Petersen return 0; 377544d92694SMartin K. Petersen } 377644d92694SMartin K. Petersen 3777fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3778fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3779c2248fc9SDouglas Gilbert { 3780c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3781c2248fc9SDouglas Gilbert u32 lba; 3782c2248fc9SDouglas Gilbert u16 num; 3783c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3784c2248fc9SDouglas Gilbert bool unmap = false; 3785c2248fc9SDouglas Gilbert 3786c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3787773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3788c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3789c2248fc9SDouglas Gilbert return check_condition_result; 3790c2248fc9SDouglas Gilbert } else 3791c2248fc9SDouglas Gilbert unmap = true; 3792c2248fc9SDouglas Gilbert } 3793c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3794c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3795773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3796c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3797c2248fc9SDouglas Gilbert return check_condition_result; 3798c2248fc9SDouglas Gilbert } 3799c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3800c2248fc9SDouglas Gilbert } 3801c2248fc9SDouglas Gilbert 3802fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3803fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3804c2248fc9SDouglas Gilbert { 3805c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3806c2248fc9SDouglas Gilbert u64 lba; 3807c2248fc9SDouglas Gilbert u32 num; 3808c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3809c2248fc9SDouglas Gilbert bool unmap = false; 3810c2248fc9SDouglas Gilbert bool ndob = false; 3811c2248fc9SDouglas Gilbert 3812c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3813773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3814c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3815c2248fc9SDouglas Gilbert return check_condition_result; 3816c2248fc9SDouglas Gilbert } else 3817c2248fc9SDouglas Gilbert unmap = true; 3818c2248fc9SDouglas Gilbert } 3819c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3820c2248fc9SDouglas Gilbert ndob = true; 3821c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3822c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3823773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3824c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3825c2248fc9SDouglas Gilbert return check_condition_result; 3826c2248fc9SDouglas Gilbert } 3827c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3828c2248fc9SDouglas Gilbert } 3829c2248fc9SDouglas Gilbert 3830acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3831acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3832acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3833fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3834fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3835acafd0b9SEwan D. Milne { 3836acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3837acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3838acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3839acafd0b9SEwan D. Milne u8 mode; 3840acafd0b9SEwan D. Milne 3841acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3842acafd0b9SEwan D. Milne switch (mode) { 3843acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3844acafd0b9SEwan D. Milne /* set UAs on this device only */ 3845acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3846acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3847acafd0b9SEwan D. Milne break; 3848acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3849acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3850acafd0b9SEwan D. Milne break; 3851acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3852acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3853acafd0b9SEwan D. Milne list_for_each_entry(dp, 3854acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3855acafd0b9SEwan D. Milne dev_list) 3856acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3857acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3858acafd0b9SEwan D. Milne if (devip != dp) 3859acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3860acafd0b9SEwan D. Milne dp->uas_bm); 3861acafd0b9SEwan D. Milne } 3862acafd0b9SEwan D. Milne break; 3863acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3864acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3865acafd0b9SEwan D. Milne list_for_each_entry(dp, 3866acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3867acafd0b9SEwan D. Milne dev_list) 3868acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3869acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3870acafd0b9SEwan D. Milne dp->uas_bm); 3871acafd0b9SEwan D. Milne break; 3872acafd0b9SEwan D. Milne default: 3873acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3874acafd0b9SEwan D. Milne break; 3875acafd0b9SEwan D. Milne } 3876acafd0b9SEwan D. Milne return 0; 3877acafd0b9SEwan D. Milne } 3878acafd0b9SEwan D. Milne 3879fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3880fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 388138d5c833SDouglas Gilbert { 388238d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 388338d5c833SDouglas Gilbert u8 *arr; 3884b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3885b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 388638d5c833SDouglas Gilbert u64 lba; 388738d5c833SDouglas Gilbert u32 dnum; 3888773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 388938d5c833SDouglas Gilbert u8 num; 389038d5c833SDouglas Gilbert int ret; 3891d467d31fSDouglas Gilbert int retval = 0; 389238d5c833SDouglas Gilbert 3893d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 389438d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 389538d5c833SDouglas Gilbert if (0 == num) 389638d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 38978475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 389838d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 389938d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 390038d5c833SDouglas Gilbert return check_condition_result; 390138d5c833SDouglas Gilbert } 39028475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 39038475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 390438d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 390538d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 390638d5c833SDouglas Gilbert "to DIF device\n"); 39079447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 39089447b6ceSMartin K. Petersen if (ret) 39099447b6ceSMartin K. Petersen return ret; 3910d467d31fSDouglas Gilbert dnum = 2 * num; 39116396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 3912d467d31fSDouglas Gilbert if (NULL == arr) { 3913d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3914d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3915d467d31fSDouglas Gilbert return check_condition_result; 3916d467d31fSDouglas Gilbert } 391738d5c833SDouglas Gilbert 391867da413fSDouglas Gilbert write_lock(macc_lckp); 391938d5c833SDouglas Gilbert 392087c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 392138d5c833SDouglas Gilbert if (ret == -1) { 3922d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3923d467d31fSDouglas Gilbert goto cleanup; 3924773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 392538d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 392638d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 392738d5c833SDouglas Gilbert dnum * lb_size, ret); 3928c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 392938d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3930d467d31fSDouglas Gilbert retval = check_condition_result; 3931d467d31fSDouglas Gilbert goto cleanup; 393238d5c833SDouglas Gilbert } 393338d5c833SDouglas Gilbert if (scsi_debug_lbp()) 393487c715dcSDouglas Gilbert map_region(sip, lba, num); 3935d467d31fSDouglas Gilbert cleanup: 393667da413fSDouglas Gilbert write_unlock(macc_lckp); 3937d467d31fSDouglas Gilbert kfree(arr); 3938d467d31fSDouglas Gilbert return retval; 393938d5c833SDouglas Gilbert } 394038d5c833SDouglas Gilbert 394144d92694SMartin K. Petersen struct unmap_block_desc { 394244d92694SMartin K. Petersen __be64 lba; 394344d92694SMartin K. Petersen __be32 blocks; 394444d92694SMartin K. Petersen __be32 __reserved; 394544d92694SMartin K. Petersen }; 394644d92694SMartin K. Petersen 3947fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 394844d92694SMartin K. Petersen { 394944d92694SMartin K. Petersen unsigned char *buf; 395044d92694SMartin K. Petersen struct unmap_block_desc *desc; 3951b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3952b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 395344d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 395444d92694SMartin K. Petersen int ret; 395544d92694SMartin K. Petersen 3956c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3957c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3958c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3959c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 396044d92694SMartin K. Petersen 396144d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3962773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3963c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 396444d92694SMartin K. Petersen return check_condition_result; 3965c2248fc9SDouglas Gilbert } 396644d92694SMartin K. Petersen 3967b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3968c2248fc9SDouglas Gilbert if (!buf) { 3969c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3970c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3971c2248fc9SDouglas Gilbert return check_condition_result; 3972c2248fc9SDouglas Gilbert } 3973c2248fc9SDouglas Gilbert 3974c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 397544d92694SMartin K. Petersen 397644d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 397744d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 397844d92694SMartin K. Petersen 397944d92694SMartin K. Petersen desc = (void *)&buf[8]; 398044d92694SMartin K. Petersen 398167da413fSDouglas Gilbert write_lock(macc_lckp); 39826c78cc06SAkinobu Mita 398344d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 398444d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 398544d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 398644d92694SMartin K. Petersen 39879447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 398844d92694SMartin K. Petersen if (ret) 398944d92694SMartin K. Petersen goto out; 399044d92694SMartin K. Petersen 399187c715dcSDouglas Gilbert unmap_region(sip, lba, num); 399244d92694SMartin K. Petersen } 399344d92694SMartin K. Petersen 399444d92694SMartin K. Petersen ret = 0; 399544d92694SMartin K. Petersen 399644d92694SMartin K. Petersen out: 399767da413fSDouglas Gilbert write_unlock(macc_lckp); 399844d92694SMartin K. Petersen kfree(buf); 399944d92694SMartin K. Petersen 400044d92694SMartin K. Petersen return ret; 400144d92694SMartin K. Petersen } 400244d92694SMartin K. Petersen 400344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 400444d92694SMartin K. Petersen 4005fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4006fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 400744d92694SMartin K. Petersen { 4008c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4009c2248fc9SDouglas Gilbert u64 lba; 4010c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 401144d92694SMartin K. Petersen int ret; 401287c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 401344d92694SMartin K. Petersen 4014c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4015c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 401644d92694SMartin K. Petersen 401744d92694SMartin K. Petersen if (alloc_len < 24) 401844d92694SMartin K. Petersen return 0; 401944d92694SMartin K. Petersen 40209447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 402144d92694SMartin K. Petersen if (ret) 402244d92694SMartin K. Petersen return ret; 402344d92694SMartin K. Petersen 4024b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4025b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4026b6ff8ca7SDouglas Gilbert 402787c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4028b6ff8ca7SDouglas Gilbert } else { 4029c2248fc9SDouglas Gilbert mapped = 1; 4030c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4031c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4032c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4033c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4034c2248fc9SDouglas Gilbert else 4035c2248fc9SDouglas Gilbert num = 0xffffffff; 4036c2248fc9SDouglas Gilbert } 403744d92694SMartin K. Petersen 403844d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4039c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4040c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4041c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4042c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 404344d92694SMartin K. Petersen 4044c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 404544d92694SMartin K. Petersen } 404644d92694SMartin K. Petersen 404780c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 404880c49563SDouglas Gilbert struct sdebug_dev_info *devip) 404980c49563SDouglas Gilbert { 40504f2c8bf6SDouglas Gilbert int res = 0; 405180c49563SDouglas Gilbert u64 lba; 405280c49563SDouglas Gilbert u32 num_blocks; 405380c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 405480c49563SDouglas Gilbert 405580c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 405680c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 405780c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 405880c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 405980c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 406080c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 406180c49563SDouglas Gilbert } 406280c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 406380c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 406480c49563SDouglas Gilbert return check_condition_result; 406580c49563SDouglas Gilbert } 4066fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 40674f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 40684f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 40694f2c8bf6SDouglas Gilbert write_since_sync = false; 40704f2c8bf6SDouglas Gilbert return res; 407180c49563SDouglas Gilbert } 407280c49563SDouglas Gilbert 4073ed9f3e25SDouglas Gilbert /* 4074ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4075ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4076ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4077ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4078ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4079ed9f3e25SDouglas Gilbert */ 4080ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4081ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4082ed9f3e25SDouglas Gilbert { 4083ed9f3e25SDouglas Gilbert int res = 0; 4084ed9f3e25SDouglas Gilbert u64 lba; 4085ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4086ed9f3e25SDouglas Gilbert u32 nblks; 4087ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4088b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4089b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4090b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4091ed9f3e25SDouglas Gilbert 4092ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4093ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4094ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4095ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4096ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4097ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4098ed9f3e25SDouglas Gilbert } 4099ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4100ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4101ed9f3e25SDouglas Gilbert return check_condition_result; 4102ed9f3e25SDouglas Gilbert } 4103ed9f3e25SDouglas Gilbert if (!fsp) 4104ed9f3e25SDouglas Gilbert goto fini; 4105ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4106ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4107ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4108ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4109ed9f3e25SDouglas Gilbert 4110ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 4111ed9f3e25SDouglas Gilbert read_lock(macc_lckp); 4112ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4113ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4114ed9f3e25SDouglas Gilbert if (rest) 4115ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 4116ed9f3e25SDouglas Gilbert read_unlock(macc_lckp); 4117ed9f3e25SDouglas Gilbert fini: 4118ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4119ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4120ed9f3e25SDouglas Gilbert return res | condition_met_result; 4121ed9f3e25SDouglas Gilbert } 4122ed9f3e25SDouglas Gilbert 4123fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4124fb0cc8d1SDouglas Gilbert 41258d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 41268d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 41278d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 41288d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 41298d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 41308d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 41318d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 41328d039e22SDouglas Gilbert */ 41331da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 41341da177e4SLinus Torvalds struct sdebug_dev_info *devip) 41351da177e4SLinus Torvalds { 413601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 41378d039e22SDouglas Gilbert unsigned int alloc_len; 41388d039e22SDouglas Gilbert unsigned char select_report; 41398d039e22SDouglas Gilbert u64 lun; 41408d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4141fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 41428d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 41438d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 41448d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 41458d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4146fb0cc8d1SDouglas Gilbert int k, j, n, res; 4147fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4148fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 41491da177e4SLinus Torvalds 415019c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 41518d039e22SDouglas Gilbert 41528d039e22SDouglas Gilbert select_report = cmd[2]; 41538d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 41548d039e22SDouglas Gilbert 41558d039e22SDouglas Gilbert if (alloc_len < 4) { 41568d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 41578d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 41581da177e4SLinus Torvalds return check_condition_result; 41591da177e4SLinus Torvalds } 41608d039e22SDouglas Gilbert 41618d039e22SDouglas Gilbert switch (select_report) { 41628d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4163773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 41648d039e22SDouglas Gilbert wlun_cnt = 0; 41658d039e22SDouglas Gilbert break; 41668d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4167c65b1445SDouglas Gilbert lun_cnt = 0; 41688d039e22SDouglas Gilbert wlun_cnt = 1; 41698d039e22SDouglas Gilbert break; 41708d039e22SDouglas Gilbert case 2: /* all LUNs */ 41718d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 41728d039e22SDouglas Gilbert wlun_cnt = 1; 41738d039e22SDouglas Gilbert break; 41748d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 41758d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 41768d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 41778d039e22SDouglas Gilbert default: 41788d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 41798d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 41808d039e22SDouglas Gilbert return check_condition_result; 41818d039e22SDouglas Gilbert } 41828d039e22SDouglas Gilbert 41838d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4184c65b1445SDouglas Gilbert --lun_cnt; 41858d039e22SDouglas Gilbert 41868d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4187fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4188fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 41898d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 41908d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 41918d039e22SDouglas Gilbert 4192fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 41938d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4194fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4195fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4196fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4197fb0cc8d1SDouglas Gilbert if (k == 0) { 4198fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4199fb0cc8d1SDouglas Gilbert ++lun_p; 4200fb0cc8d1SDouglas Gilbert j = 1; 4201fb0cc8d1SDouglas Gilbert } 4202fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4203fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4204fb0cc8d1SDouglas Gilbert break; 4205fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4206ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4207ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4208fb0cc8d1SDouglas Gilbert } 4209fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4210fb0cc8d1SDouglas Gilbert break; 4211fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4212fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4213fb0cc8d1SDouglas Gilbert if (res) 4214fb0cc8d1SDouglas Gilbert return res; 4215fb0cc8d1SDouglas Gilbert off_rsp += n; 4216fb0cc8d1SDouglas Gilbert } 4217fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4218fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4219fb0cc8d1SDouglas Gilbert ++j; 4220fb0cc8d1SDouglas Gilbert } 4221fb0cc8d1SDouglas Gilbert if (j > 0) 4222fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 42238d039e22SDouglas Gilbert return res; 42241da177e4SLinus Torvalds } 42251da177e4SLinus Torvalds 4226c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4227c3e2fe92SDouglas Gilbert { 4228c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4229c3e2fe92SDouglas Gilbert u8 bytchk; 4230c3e2fe92SDouglas Gilbert int ret, j; 4231c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4232c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4233c3e2fe92SDouglas Gilbert u64 lba; 4234c3e2fe92SDouglas Gilbert u8 *arr; 4235c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4236b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4237b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4238c3e2fe92SDouglas Gilbert 4239c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4240c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4241c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4242c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4243c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4244c3e2fe92SDouglas Gilbert return check_condition_result; 4245c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4246c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4247c3e2fe92SDouglas Gilbert } 4248c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4249c3e2fe92SDouglas Gilbert case VERIFY_16: 4250c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4251c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4252c3e2fe92SDouglas Gilbert break; 4253c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4254c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4255c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4256c3e2fe92SDouglas Gilbert break; 4257c3e2fe92SDouglas Gilbert default: 4258c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4259c3e2fe92SDouglas Gilbert return check_condition_result; 4260c3e2fe92SDouglas Gilbert } 4261c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4262c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4263c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4264c3e2fe92SDouglas Gilbert if (ret) 4265c3e2fe92SDouglas Gilbert return ret; 4266c3e2fe92SDouglas Gilbert 4267c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4268c3e2fe92SDouglas Gilbert if (!arr) { 4269c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4270c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4271c3e2fe92SDouglas Gilbert return check_condition_result; 4272c3e2fe92SDouglas Gilbert } 4273c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 427467da413fSDouglas Gilbert read_lock(macc_lckp); 4275c3e2fe92SDouglas Gilbert 4276c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4277c3e2fe92SDouglas Gilbert if (ret == -1) { 4278c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4279c3e2fe92SDouglas Gilbert goto cleanup; 4280c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4281c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4282c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4283c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4284c3e2fe92SDouglas Gilbert } 4285c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4286c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4287c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4288c3e2fe92SDouglas Gilbert } 4289c3e2fe92SDouglas Gilbert ret = 0; 4290c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4291c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4292c3e2fe92SDouglas Gilbert ret = check_condition_result; 4293c3e2fe92SDouglas Gilbert goto cleanup; 4294c3e2fe92SDouglas Gilbert } 4295c3e2fe92SDouglas Gilbert cleanup: 429667da413fSDouglas Gilbert read_unlock(macc_lckp); 4297c3e2fe92SDouglas Gilbert kfree(arr); 4298c3e2fe92SDouglas Gilbert return ret; 4299c3e2fe92SDouglas Gilbert } 4300c3e2fe92SDouglas Gilbert 4301f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4302f0d1cf93SDouglas Gilbert 4303f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */ 4304f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4305f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4306f0d1cf93SDouglas Gilbert { 4307f0d1cf93SDouglas Gilbert unsigned int i, max_zones, rep_max_zones, nrz = 0; 4308f0d1cf93SDouglas Gilbert int ret = 0; 4309f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4310f0d1cf93SDouglas Gilbert bool partial; 4311f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4312f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4313f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4314f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4315b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4316f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4317f0d1cf93SDouglas Gilbert 4318f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4319f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4320f0d1cf93SDouglas Gilbert return check_condition_result; 4321f0d1cf93SDouglas Gilbert } 4322f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4323f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 4324f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4325f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4326f0d1cf93SDouglas Gilbert 4327f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4328f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4329f0d1cf93SDouglas Gilbert return check_condition_result; 4330f0d1cf93SDouglas Gilbert } 4331f0d1cf93SDouglas Gilbert 4332108e36f0SDamien Le Moal max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift); 4333f0d1cf93SDouglas Gilbert rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), 4334f0d1cf93SDouglas Gilbert max_zones); 4335f0d1cf93SDouglas Gilbert 4336f0d1cf93SDouglas Gilbert arr = kcalloc(RZONES_DESC_HD, alloc_len, GFP_ATOMIC); 4337f0d1cf93SDouglas Gilbert if (!arr) { 4338f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4339f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4340f0d1cf93SDouglas Gilbert return check_condition_result; 4341f0d1cf93SDouglas Gilbert } 4342f0d1cf93SDouglas Gilbert 4343f0d1cf93SDouglas Gilbert read_lock(macc_lckp); 4344f0d1cf93SDouglas Gilbert 4345f0d1cf93SDouglas Gilbert desc = arr + 64; 4346f0d1cf93SDouglas Gilbert for (i = 0; i < max_zones; i++) { 4347f0d1cf93SDouglas Gilbert lba = zs_lba + devip->zsize * i; 4348f0d1cf93SDouglas Gilbert if (lba > sdebug_capacity) 4349f0d1cf93SDouglas Gilbert break; 4350f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4351f0d1cf93SDouglas Gilbert switch (rep_opts) { 4352f0d1cf93SDouglas Gilbert case 0x00: 4353f0d1cf93SDouglas Gilbert /* All zones */ 4354f0d1cf93SDouglas Gilbert break; 4355f0d1cf93SDouglas Gilbert case 0x01: 4356f0d1cf93SDouglas Gilbert /* Empty zones */ 4357f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4358f0d1cf93SDouglas Gilbert continue; 4359f0d1cf93SDouglas Gilbert break; 4360f0d1cf93SDouglas Gilbert case 0x02: 4361f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4362f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4363f0d1cf93SDouglas Gilbert continue; 4364f0d1cf93SDouglas Gilbert break; 4365f0d1cf93SDouglas Gilbert case 0x03: 4366f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4367f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4368f0d1cf93SDouglas Gilbert continue; 4369f0d1cf93SDouglas Gilbert break; 4370f0d1cf93SDouglas Gilbert case 0x04: 4371f0d1cf93SDouglas Gilbert /* Closed zones */ 4372f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4373f0d1cf93SDouglas Gilbert continue; 4374f0d1cf93SDouglas Gilbert break; 4375f0d1cf93SDouglas Gilbert case 0x05: 4376f0d1cf93SDouglas Gilbert /* Full zones */ 4377f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4378f0d1cf93SDouglas Gilbert continue; 4379f0d1cf93SDouglas Gilbert break; 4380f0d1cf93SDouglas Gilbert case 0x06: 4381f0d1cf93SDouglas Gilbert case 0x07: 4382f0d1cf93SDouglas Gilbert case 0x10: 4383f0d1cf93SDouglas Gilbert /* 438464e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 438564e14eceSDamien Le Moal * not emulated: no zones to report; 4386f0d1cf93SDouglas Gilbert */ 4387f0d1cf93SDouglas Gilbert continue; 438864e14eceSDamien Le Moal case 0x11: 438964e14eceSDamien Le Moal /* non-seq-resource set */ 439064e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 439164e14eceSDamien Le Moal continue; 439264e14eceSDamien Le Moal break; 4393f0d1cf93SDouglas Gilbert case 0x3f: 4394f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 4395f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp)) 4396f0d1cf93SDouglas Gilbert continue; 4397f0d1cf93SDouglas Gilbert break; 4398f0d1cf93SDouglas Gilbert default: 4399f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4400f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4401f0d1cf93SDouglas Gilbert ret = check_condition_result; 4402f0d1cf93SDouglas Gilbert goto fini; 4403f0d1cf93SDouglas Gilbert } 4404f0d1cf93SDouglas Gilbert 4405f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4406f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 440764e14eceSDamien Le Moal desc[0] = zsp->z_type; 4408f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 440964e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 441064e14eceSDamien Le Moal desc[1] |= 1 << 1; 4411f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4412f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4413f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4414f0d1cf93SDouglas Gilbert desc += 64; 4415f0d1cf93SDouglas Gilbert } 4416f0d1cf93SDouglas Gilbert 4417f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4418f0d1cf93SDouglas Gilbert break; 4419f0d1cf93SDouglas Gilbert 4420f0d1cf93SDouglas Gilbert nrz++; 4421f0d1cf93SDouglas Gilbert } 4422f0d1cf93SDouglas Gilbert 4423f0d1cf93SDouglas Gilbert /* Report header */ 4424f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 4425f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 4426f0d1cf93SDouglas Gilbert 4427f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 4428f0d1cf93SDouglas Gilbert ret = fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, rep_len)); 4429f0d1cf93SDouglas Gilbert 4430f0d1cf93SDouglas Gilbert fini: 4431f0d1cf93SDouglas Gilbert read_unlock(macc_lckp); 4432f0d1cf93SDouglas Gilbert kfree(arr); 4433f0d1cf93SDouglas Gilbert return ret; 4434f0d1cf93SDouglas Gilbert } 4435f0d1cf93SDouglas Gilbert 4436f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4437f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4438f0d1cf93SDouglas Gilbert { 4439f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4440f0d1cf93SDouglas Gilbert unsigned int i; 4441f0d1cf93SDouglas Gilbert 4442f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4443f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4444f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4445f0d1cf93SDouglas Gilbert } 4446f0d1cf93SDouglas Gilbert } 4447f0d1cf93SDouglas Gilbert 4448f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4449f0d1cf93SDouglas Gilbert { 4450f0d1cf93SDouglas Gilbert int res = 0; 4451f0d1cf93SDouglas Gilbert u64 z_id; 4452f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4453f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4454f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4455f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4456b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4457f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4458f0d1cf93SDouglas Gilbert 4459f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4460f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4461f0d1cf93SDouglas Gilbert return check_condition_result; 4462f0d1cf93SDouglas Gilbert } 4463f0d1cf93SDouglas Gilbert 4464f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4465f0d1cf93SDouglas Gilbert 4466f0d1cf93SDouglas Gilbert if (all) { 4467f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4468f0d1cf93SDouglas Gilbert if (devip->max_open && 4469f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4470f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4471f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4472f0d1cf93SDouglas Gilbert res = check_condition_result; 4473f0d1cf93SDouglas Gilbert goto fini; 4474f0d1cf93SDouglas Gilbert } 4475f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4476f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4477f0d1cf93SDouglas Gilbert goto fini; 4478f0d1cf93SDouglas Gilbert } 4479f0d1cf93SDouglas Gilbert 4480f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4481f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4482f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4483f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4484f0d1cf93SDouglas Gilbert res = check_condition_result; 4485f0d1cf93SDouglas Gilbert goto fini; 4486f0d1cf93SDouglas Gilbert } 4487f0d1cf93SDouglas Gilbert 4488f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4489f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4490f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4491f0d1cf93SDouglas Gilbert res = check_condition_result; 4492f0d1cf93SDouglas Gilbert goto fini; 4493f0d1cf93SDouglas Gilbert } 4494f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4495f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4496f0d1cf93SDouglas Gilbert res = check_condition_result; 4497f0d1cf93SDouglas Gilbert goto fini; 4498f0d1cf93SDouglas Gilbert } 4499f0d1cf93SDouglas Gilbert 4500f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4501f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4502f0d1cf93SDouglas Gilbert goto fini; 4503f0d1cf93SDouglas Gilbert 4504f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4505f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4506f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4507f0d1cf93SDouglas Gilbert res = check_condition_result; 4508f0d1cf93SDouglas Gilbert goto fini; 4509f0d1cf93SDouglas Gilbert } 4510f0d1cf93SDouglas Gilbert 4511f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4512f0d1cf93SDouglas Gilbert fini: 4513f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4514f0d1cf93SDouglas Gilbert return res; 4515f0d1cf93SDouglas Gilbert } 4516f0d1cf93SDouglas Gilbert 4517f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4518f0d1cf93SDouglas Gilbert { 4519f0d1cf93SDouglas Gilbert unsigned int i; 4520f0d1cf93SDouglas Gilbert 4521f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4522f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4523f0d1cf93SDouglas Gilbert } 4524f0d1cf93SDouglas Gilbert 4525f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4526f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4527f0d1cf93SDouglas Gilbert { 4528f0d1cf93SDouglas Gilbert int res = 0; 4529f0d1cf93SDouglas Gilbert u64 z_id; 4530f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4531f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4532f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4533b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4534f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4535f0d1cf93SDouglas Gilbert 4536f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4537f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4538f0d1cf93SDouglas Gilbert return check_condition_result; 4539f0d1cf93SDouglas Gilbert } 4540f0d1cf93SDouglas Gilbert 4541f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4542f0d1cf93SDouglas Gilbert 4543f0d1cf93SDouglas Gilbert if (all) { 4544f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4545f0d1cf93SDouglas Gilbert goto fini; 4546f0d1cf93SDouglas Gilbert } 4547f0d1cf93SDouglas Gilbert 4548f0d1cf93SDouglas Gilbert /* Close specified zone */ 4549f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4550f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4551f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4552f0d1cf93SDouglas Gilbert res = check_condition_result; 4553f0d1cf93SDouglas Gilbert goto fini; 4554f0d1cf93SDouglas Gilbert } 4555f0d1cf93SDouglas Gilbert 4556f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4557f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4558f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4559f0d1cf93SDouglas Gilbert res = check_condition_result; 4560f0d1cf93SDouglas Gilbert goto fini; 4561f0d1cf93SDouglas Gilbert } 4562f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4563f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4564f0d1cf93SDouglas Gilbert res = check_condition_result; 4565f0d1cf93SDouglas Gilbert goto fini; 4566f0d1cf93SDouglas Gilbert } 4567f0d1cf93SDouglas Gilbert 4568f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4569f0d1cf93SDouglas Gilbert fini: 4570f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4571f0d1cf93SDouglas Gilbert return res; 4572f0d1cf93SDouglas Gilbert } 4573f0d1cf93SDouglas Gilbert 4574f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4575f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4576f0d1cf93SDouglas Gilbert { 4577f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4578f0d1cf93SDouglas Gilbert 4579f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4580f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4581f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4582f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4583f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4584f0d1cf93SDouglas Gilbert devip->nr_closed--; 4585f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4586f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4587f0d1cf93SDouglas Gilbert } 4588f0d1cf93SDouglas Gilbert } 4589f0d1cf93SDouglas Gilbert 4590f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4591f0d1cf93SDouglas Gilbert { 4592f0d1cf93SDouglas Gilbert unsigned int i; 4593f0d1cf93SDouglas Gilbert 4594f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4595f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4596f0d1cf93SDouglas Gilbert } 4597f0d1cf93SDouglas Gilbert 4598f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4599f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4600f0d1cf93SDouglas Gilbert { 4601f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4602f0d1cf93SDouglas Gilbert int res = 0; 4603f0d1cf93SDouglas Gilbert u64 z_id; 4604f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4605f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4606b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4607f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4608f0d1cf93SDouglas Gilbert 4609f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4610f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4611f0d1cf93SDouglas Gilbert return check_condition_result; 4612f0d1cf93SDouglas Gilbert } 4613f0d1cf93SDouglas Gilbert 4614f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4615f0d1cf93SDouglas Gilbert 4616f0d1cf93SDouglas Gilbert if (all) { 4617f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4618f0d1cf93SDouglas Gilbert goto fini; 4619f0d1cf93SDouglas Gilbert } 4620f0d1cf93SDouglas Gilbert 4621f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4622f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4623f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4624f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4625f0d1cf93SDouglas Gilbert res = check_condition_result; 4626f0d1cf93SDouglas Gilbert goto fini; 4627f0d1cf93SDouglas Gilbert } 4628f0d1cf93SDouglas Gilbert 4629f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4630f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4631f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4632f0d1cf93SDouglas Gilbert res = check_condition_result; 4633f0d1cf93SDouglas Gilbert goto fini; 4634f0d1cf93SDouglas Gilbert } 4635f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4636f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4637f0d1cf93SDouglas Gilbert res = check_condition_result; 4638f0d1cf93SDouglas Gilbert goto fini; 4639f0d1cf93SDouglas Gilbert } 4640f0d1cf93SDouglas Gilbert 4641f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4642f0d1cf93SDouglas Gilbert fini: 4643f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4644f0d1cf93SDouglas Gilbert return res; 4645f0d1cf93SDouglas Gilbert } 4646f0d1cf93SDouglas Gilbert 4647f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4648f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4649f0d1cf93SDouglas Gilbert { 4650f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4651f0d1cf93SDouglas Gilbert 4652f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4653f0d1cf93SDouglas Gilbert return; 4654f0d1cf93SDouglas Gilbert 4655f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4656f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4657f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4658f0d1cf93SDouglas Gilbert 4659f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4660f0d1cf93SDouglas Gilbert devip->nr_closed--; 4661f0d1cf93SDouglas Gilbert 466264e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4663f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4664f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4665f0d1cf93SDouglas Gilbert } 4666f0d1cf93SDouglas Gilbert 4667f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4668f0d1cf93SDouglas Gilbert { 4669f0d1cf93SDouglas Gilbert unsigned int i; 4670f0d1cf93SDouglas Gilbert 4671f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4672f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4673f0d1cf93SDouglas Gilbert } 4674f0d1cf93SDouglas Gilbert 4675f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4676f0d1cf93SDouglas Gilbert { 4677f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4678f0d1cf93SDouglas Gilbert int res = 0; 4679f0d1cf93SDouglas Gilbert u64 z_id; 4680f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4681f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4682b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4683f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4684f0d1cf93SDouglas Gilbert 4685f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4686f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4687f0d1cf93SDouglas Gilbert return check_condition_result; 4688f0d1cf93SDouglas Gilbert } 4689f0d1cf93SDouglas Gilbert 4690f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4691f0d1cf93SDouglas Gilbert 4692f0d1cf93SDouglas Gilbert if (all) { 4693f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4694f0d1cf93SDouglas Gilbert goto fini; 4695f0d1cf93SDouglas Gilbert } 4696f0d1cf93SDouglas Gilbert 4697f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4698f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4699f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4700f0d1cf93SDouglas Gilbert res = check_condition_result; 4701f0d1cf93SDouglas Gilbert goto fini; 4702f0d1cf93SDouglas Gilbert } 4703f0d1cf93SDouglas Gilbert 4704f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4705f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4706f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4707f0d1cf93SDouglas Gilbert res = check_condition_result; 4708f0d1cf93SDouglas Gilbert goto fini; 4709f0d1cf93SDouglas Gilbert } 4710f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4711f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4712f0d1cf93SDouglas Gilbert res = check_condition_result; 4713f0d1cf93SDouglas Gilbert goto fini; 4714f0d1cf93SDouglas Gilbert } 4715f0d1cf93SDouglas Gilbert 4716f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4717f0d1cf93SDouglas Gilbert fini: 4718f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4719f0d1cf93SDouglas Gilbert return res; 4720f0d1cf93SDouglas Gilbert } 4721f0d1cf93SDouglas Gilbert 4722c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4723c4837394SDouglas Gilbert { 4724c10fa55fSJohn Garry u16 hwq; 4725*a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4726c10fa55fSJohn Garry 4727c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4728c4837394SDouglas Gilbert 4729458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4730458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4731458df78bSBart Van Assche hwq = 0; 4732f7c4cdc7SJohn Garry 4733458df78bSBart Van Assche return sdebug_q_arr + hwq; 4734c4837394SDouglas Gilbert } 4735c4837394SDouglas Gilbert 4736c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4737c10fa55fSJohn Garry { 4738*a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4739c10fa55fSJohn Garry } 4740c10fa55fSJohn Garry 4741c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4742fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 47431da177e4SLinus Torvalds { 47447382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4745c4837394SDouglas Gilbert int qc_idx; 4746cbf67842SDouglas Gilbert int retiring = 0; 47471da177e4SLinus Torvalds unsigned long iflags; 4748c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4749cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4750cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4751cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 47521da177e4SLinus Torvalds 47537382f9d8SDouglas Gilbert if (unlikely(aborted)) 47547382f9d8SDouglas Gilbert sd_dp->aborted = false; 4755c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4756c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4757c4837394SDouglas Gilbert if (sdebug_statistics) { 4758cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4759c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4760c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4761c4837394SDouglas Gilbert } 4762c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4763c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 47641da177e4SLinus Torvalds return; 47651da177e4SLinus Torvalds } 4766c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 47674a0c6f43SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 4768c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4769cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4770b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4771c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4772c10fa55fSJohn Garry pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n", 4773c10fa55fSJohn Garry sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx); 47741da177e4SLinus Torvalds return; 47751da177e4SLinus Torvalds } 4776cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4777f46eb0e9SDouglas Gilbert if (likely(devip)) 4778cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4779cbf67842SDouglas Gilbert else 4780c1287970STomas Winkler pr_err("devip=NULL\n"); 4781f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4782cbf67842SDouglas Gilbert retiring = 1; 4783cbf67842SDouglas Gilbert 4784cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4785c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4786c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4787c1287970STomas Winkler pr_err("Unexpected completion\n"); 4788cbf67842SDouglas Gilbert return; 47891da177e4SLinus Torvalds } 47901da177e4SLinus Torvalds 4791cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4792cbf67842SDouglas Gilbert int k, retval; 4793cbf67842SDouglas Gilbert 4794cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4795c4837394SDouglas Gilbert if (qc_idx >= retval) { 4796c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4797c1287970STomas Winkler pr_err("index %d too large\n", retval); 4798cbf67842SDouglas Gilbert return; 4799cbf67842SDouglas Gilbert } 4800c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4801773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4802cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4803cbf67842SDouglas Gilbert else 4804cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4805cbf67842SDouglas Gilbert } 4806c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 48077382f9d8SDouglas Gilbert if (unlikely(aborted)) { 48087382f9d8SDouglas Gilbert if (sdebug_verbose) 48097382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 48107382f9d8SDouglas Gilbert return; 48117382f9d8SDouglas Gilbert } 4812cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 4813cbf67842SDouglas Gilbert } 4814cbf67842SDouglas Gilbert 4815cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4816fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4817cbf67842SDouglas Gilbert { 4818a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4819a10bc12aSDouglas Gilbert hrt); 4820a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4821cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4822cbf67842SDouglas Gilbert } 48231da177e4SLinus Torvalds 4824a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4825fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4826a10bc12aSDouglas Gilbert { 4827a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4828a10bc12aSDouglas Gilbert ew.work); 4829a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4830a10bc12aSDouglas Gilbert } 4831a10bc12aSDouglas Gilbert 483209ba24c1SDouglas Gilbert static bool got_shared_uuid; 4833bf476433SChristoph Hellwig static uuid_t shared_uuid; 483409ba24c1SDouglas Gilbert 4835f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 4836f0d1cf93SDouglas Gilbert { 4837f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4838f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 4839f0d1cf93SDouglas Gilbert sector_t zstart = 0; 4840f0d1cf93SDouglas Gilbert unsigned int i; 4841f0d1cf93SDouglas Gilbert 4842f0d1cf93SDouglas Gilbert /* 484398e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 484498e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 4845f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 4846f0d1cf93SDouglas Gilbert * created for the device. 4847f0d1cf93SDouglas Gilbert */ 484898e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 4849f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 4850f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4851f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 4852f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 4853f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 4854f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 4855f0d1cf93SDouglas Gilbert return -EINVAL; 4856f0d1cf93SDouglas Gilbert } 4857f0d1cf93SDouglas Gilbert } else { 4858108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 4859108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 4860108e36f0SDamien Le Moal return -EINVAL; 4861108e36f0SDamien Le Moal } 486298e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 4863f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4864f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 4865f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 4866f0d1cf93SDouglas Gilbert return -EINVAL; 4867f0d1cf93SDouglas Gilbert } 4868f0d1cf93SDouglas Gilbert } 4869f0d1cf93SDouglas Gilbert 4870f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 4871f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 4872f0d1cf93SDouglas Gilbert 4873aa8fecf9SDamien Le Moal if (sdeb_zbc_nr_conv >= devip->nr_zones) { 4874aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 4875aa8fecf9SDamien Le Moal return -EINVAL; 4876aa8fecf9SDamien Le Moal } 4877aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 4878aa8fecf9SDamien Le Moal 487964e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 488064e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 4881380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 4882f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 4883f0d1cf93SDouglas Gilbert else 4884380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 488564e14eceSDamien Le Moal } 4886f0d1cf93SDouglas Gilbert 4887f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 4888f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 4889f0d1cf93SDouglas Gilbert if (!devip->zstate) 4890f0d1cf93SDouglas Gilbert return -ENOMEM; 4891f0d1cf93SDouglas Gilbert 4892f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 4893f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 4894f0d1cf93SDouglas Gilbert 4895f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 4896f0d1cf93SDouglas Gilbert 4897aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 489864e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_CNV; 4899f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 4900f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 4901f0d1cf93SDouglas Gilbert } else { 490264e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 490364e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWR; 490464e14eceSDamien Le Moal else 490564e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWP; 4906f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4907f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4908f0d1cf93SDouglas Gilbert } 4909f0d1cf93SDouglas Gilbert 4910f0d1cf93SDouglas Gilbert if (zsp->z_start + devip->zsize < capacity) 4911f0d1cf93SDouglas Gilbert zsp->z_size = devip->zsize; 4912f0d1cf93SDouglas Gilbert else 4913f0d1cf93SDouglas Gilbert zsp->z_size = capacity - zsp->z_start; 4914f0d1cf93SDouglas Gilbert 4915f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 4916f0d1cf93SDouglas Gilbert } 4917f0d1cf93SDouglas Gilbert 4918f0d1cf93SDouglas Gilbert return 0; 4919f0d1cf93SDouglas Gilbert } 4920f0d1cf93SDouglas Gilbert 4921fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 4922fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 49235cb2fc06SFUJITA Tomonori { 49245cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 49255cb2fc06SFUJITA Tomonori 49265cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 49275cb2fc06SFUJITA Tomonori if (devip) { 492809ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 4929bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 493009ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 493109ba24c1SDouglas Gilbert if (got_shared_uuid) 493209ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 493309ba24c1SDouglas Gilbert else { 4934bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 493509ba24c1SDouglas Gilbert got_shared_uuid = true; 493609ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 493709ba24c1SDouglas Gilbert } 493809ba24c1SDouglas Gilbert } 49395cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 4940f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 494164e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 4942f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 4943f0d1cf93SDouglas Gilbert kfree(devip); 4944f0d1cf93SDouglas Gilbert return NULL; 4945f0d1cf93SDouglas Gilbert } 494664e14eceSDamien Le Moal } else { 494764e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 4948f0d1cf93SDouglas Gilbert } 4949f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 4950fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 4951fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 49525cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 49535cb2fc06SFUJITA Tomonori } 49545cb2fc06SFUJITA Tomonori return devip; 49555cb2fc06SFUJITA Tomonori } 49565cb2fc06SFUJITA Tomonori 4957f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 49581da177e4SLinus Torvalds { 49591da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 49601da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 4961f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 49621da177e4SLinus Torvalds 4963d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 49641da177e4SLinus Torvalds if (!sdbg_host) { 4965c1287970STomas Winkler pr_err("Host info NULL\n"); 49661da177e4SLinus Torvalds return NULL; 49671da177e4SLinus Torvalds } 4968ad0c7775SDouglas Gilbert 49691da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 49701da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 49711da177e4SLinus Torvalds (devip->target == sdev->id) && 49721da177e4SLinus Torvalds (devip->lun == sdev->lun)) 49731da177e4SLinus Torvalds return devip; 49741da177e4SLinus Torvalds else { 49751da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 49761da177e4SLinus Torvalds open_devip = devip; 49771da177e4SLinus Torvalds } 49781da177e4SLinus Torvalds } 49795cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 49805cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 49815cb2fc06SFUJITA Tomonori if (!open_devip) { 4982c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 49831da177e4SLinus Torvalds return NULL; 49841da177e4SLinus Torvalds } 49851da177e4SLinus Torvalds } 4986a75869d1SFUJITA Tomonori 49871da177e4SLinus Torvalds open_devip->channel = sdev->channel; 49881da177e4SLinus Torvalds open_devip->target = sdev->id; 49891da177e4SLinus Torvalds open_devip->lun = sdev->lun; 49901da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 4991cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 4992cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 4993c2248fc9SDouglas Gilbert open_devip->used = true; 49941da177e4SLinus Torvalds return open_devip; 49951da177e4SLinus Torvalds } 49961da177e4SLinus Torvalds 49978dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 49981da177e4SLinus Torvalds { 4999773642d9SDouglas Gilbert if (sdebug_verbose) 5000c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 50018dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 50028dea0d02SFUJITA Tomonori return 0; 50038dea0d02SFUJITA Tomonori } 50041da177e4SLinus Torvalds 50058dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 50068dea0d02SFUJITA Tomonori { 5007f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5008f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5009a34c4e98SFUJITA Tomonori 5010773642d9SDouglas Gilbert if (sdebug_verbose) 5011c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 50128dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5013b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5014b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 5015b01f6f83SDouglas Gilbert if (devip == NULL) { 5016f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5017b01f6f83SDouglas Gilbert if (devip == NULL) 50188dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5019f46eb0e9SDouglas Gilbert } 5020c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5021773642d9SDouglas Gilbert if (sdebug_no_uld) 502278d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 50239b760fd8SDouglas Gilbert config_cdb_len(sdp); 50248dea0d02SFUJITA Tomonori return 0; 50258dea0d02SFUJITA Tomonori } 50268dea0d02SFUJITA Tomonori 50278dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 50288dea0d02SFUJITA Tomonori { 50298dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 50308dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 50318dea0d02SFUJITA Tomonori 5032773642d9SDouglas Gilbert if (sdebug_verbose) 5033c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 50348dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 50358dea0d02SFUJITA Tomonori if (devip) { 503625985edcSLucas De Marchi /* make this slot available for re-use */ 5037c2248fc9SDouglas Gilbert devip->used = false; 50388dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 50398dea0d02SFUJITA Tomonori } 50408dea0d02SFUJITA Tomonori } 50418dea0d02SFUJITA Tomonori 504210bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 504310bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5044c4837394SDouglas Gilbert { 5045c4837394SDouglas Gilbert if (!sd_dp) 5046c4837394SDouglas Gilbert return; 504710bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5048c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 504910bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5050c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5051c4837394SDouglas Gilbert } 5052c4837394SDouglas Gilbert 5053a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5054a10bc12aSDouglas Gilbert returns false */ 5055a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 50568dea0d02SFUJITA Tomonori { 50578dea0d02SFUJITA Tomonori unsigned long iflags; 5058c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 505910bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5060c4837394SDouglas Gilbert struct sdebug_queue *sqp; 50618dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5062cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5063a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 50648dea0d02SFUJITA Tomonori 5065c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5066c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5067773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5068cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5069cbf67842SDouglas Gilbert if (r_qmax > qmax) 5070cbf67842SDouglas Gilbert qmax = r_qmax; 5071cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5072c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5073c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5074a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5075a10bc12aSDouglas Gilbert continue; 5076c4837394SDouglas Gilbert /* found */ 5077db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5078db525fceSDouglas Gilbert cmnd->device->hostdata; 5079db525fceSDouglas Gilbert if (devip) 5080db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5081db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5082a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 508310bde980SDouglas Gilbert if (sd_dp) { 508410bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 508510bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 508610bde980SDouglas Gilbert } else 508710bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5088c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 508910bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5090c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5091a10bc12aSDouglas Gilbert return true; 50928dea0d02SFUJITA Tomonori } 5093cbf67842SDouglas Gilbert } 5094c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5095c4837394SDouglas Gilbert } 5096a10bc12aSDouglas Gilbert return false; 50978dea0d02SFUJITA Tomonori } 50988dea0d02SFUJITA Tomonori 5099a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 51008dea0d02SFUJITA Tomonori static void stop_all_queued(void) 51018dea0d02SFUJITA Tomonori { 51028dea0d02SFUJITA Tomonori unsigned long iflags; 5103c4837394SDouglas Gilbert int j, k; 510410bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5105c4837394SDouglas Gilbert struct sdebug_queue *sqp; 51068dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5107cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5108a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 51098dea0d02SFUJITA Tomonori 5110c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5111c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5112c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5113c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5114c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5115c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 5116a10bc12aSDouglas Gilbert continue; 5117db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5118db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5119db525fceSDouglas Gilbert if (devip) 5120db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5121db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5122a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 512310bde980SDouglas Gilbert if (sd_dp) { 512410bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 512510bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 512610bde980SDouglas Gilbert } else 512710bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5128c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 512910bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5130c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5131c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 51328dea0d02SFUJITA Tomonori } 51338dea0d02SFUJITA Tomonori } 5134c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5135c4837394SDouglas Gilbert } 5136cbf67842SDouglas Gilbert } 5137cbf67842SDouglas Gilbert 5138cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5139cbf67842SDouglas Gilbert static void free_all_queued(void) 5140cbf67842SDouglas Gilbert { 5141c4837394SDouglas Gilbert int j, k; 5142c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5143cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5144cbf67842SDouglas Gilbert 5145c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5146c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5147c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5148a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5149a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5150cbf67842SDouglas Gilbert } 51511da177e4SLinus Torvalds } 5152c4837394SDouglas Gilbert } 51531da177e4SLinus Torvalds 51541da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 51551da177e4SLinus Torvalds { 5156a10bc12aSDouglas Gilbert bool ok; 5157a10bc12aSDouglas Gilbert 51581da177e4SLinus Torvalds ++num_aborts; 5159cbf67842SDouglas Gilbert if (SCpnt) { 5160a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5161a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5162a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5163a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5164a10bc12aSDouglas Gilbert ok ? "" : " not"); 5165cbf67842SDouglas Gilbert } 51661da177e4SLinus Torvalds return SUCCESS; 51671da177e4SLinus Torvalds } 51681da177e4SLinus Torvalds 51691da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 51701da177e4SLinus Torvalds { 51711da177e4SLinus Torvalds ++num_dev_resets; 5172cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5173cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5174f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5175f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5176cbf67842SDouglas Gilbert 5177773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5178cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 51791da177e4SLinus Torvalds if (devip) 5180cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 51811da177e4SLinus Torvalds } 51821da177e4SLinus Torvalds return SUCCESS; 51831da177e4SLinus Torvalds } 51841da177e4SLinus Torvalds 5185cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5186cbf67842SDouglas Gilbert { 5187cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5188cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5189cbf67842SDouglas Gilbert struct scsi_device *sdp; 5190cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5191cbf67842SDouglas Gilbert int k = 0; 5192cbf67842SDouglas Gilbert 5193cbf67842SDouglas Gilbert ++num_target_resets; 5194cbf67842SDouglas Gilbert if (!SCpnt) 5195cbf67842SDouglas Gilbert goto lie; 5196cbf67842SDouglas Gilbert sdp = SCpnt->device; 5197cbf67842SDouglas Gilbert if (!sdp) 5198cbf67842SDouglas Gilbert goto lie; 5199773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5200cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5201cbf67842SDouglas Gilbert hp = sdp->host; 5202cbf67842SDouglas Gilbert if (!hp) 5203cbf67842SDouglas Gilbert goto lie; 5204cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5205cbf67842SDouglas Gilbert if (sdbg_host) { 5206cbf67842SDouglas Gilbert list_for_each_entry(devip, 5207cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5208cbf67842SDouglas Gilbert dev_list) 5209cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5210cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5211cbf67842SDouglas Gilbert ++k; 5212cbf67842SDouglas Gilbert } 5213cbf67842SDouglas Gilbert } 5214773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5215cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5216cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5217cbf67842SDouglas Gilbert lie: 5218cbf67842SDouglas Gilbert return SUCCESS; 5219cbf67842SDouglas Gilbert } 5220cbf67842SDouglas Gilbert 52211da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 52221da177e4SLinus Torvalds { 52231da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5224cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 52251da177e4SLinus Torvalds struct scsi_device *sdp; 52261da177e4SLinus Torvalds struct Scsi_Host *hp; 5227cbf67842SDouglas Gilbert int k = 0; 52281da177e4SLinus Torvalds 52291da177e4SLinus Torvalds ++num_bus_resets; 5230cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5231cbf67842SDouglas Gilbert goto lie; 5232cbf67842SDouglas Gilbert sdp = SCpnt->device; 5233773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5234cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5235cbf67842SDouglas Gilbert hp = sdp->host; 5236cbf67842SDouglas Gilbert if (hp) { 5237d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 52381da177e4SLinus Torvalds if (sdbg_host) { 5239cbf67842SDouglas Gilbert list_for_each_entry(devip, 52401da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5241cbf67842SDouglas Gilbert dev_list) { 5242cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5243cbf67842SDouglas Gilbert ++k; 52441da177e4SLinus Torvalds } 52451da177e4SLinus Torvalds } 5246cbf67842SDouglas Gilbert } 5247773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5248cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5249cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5250cbf67842SDouglas Gilbert lie: 52511da177e4SLinus Torvalds return SUCCESS; 52521da177e4SLinus Torvalds } 52531da177e4SLinus Torvalds 52541da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 52551da177e4SLinus Torvalds { 52561da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5257cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5258cbf67842SDouglas Gilbert int k = 0; 52591da177e4SLinus Torvalds 52601da177e4SLinus Torvalds ++num_host_resets; 5261773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5262cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 52631da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 52641da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5265cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5266cbf67842SDouglas Gilbert dev_list) { 5267cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5268cbf67842SDouglas Gilbert ++k; 5269cbf67842SDouglas Gilbert } 52701da177e4SLinus Torvalds } 52711da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 52721da177e4SLinus Torvalds stop_all_queued(); 5273773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5274cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5275cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 52761da177e4SLinus Torvalds return SUCCESS; 52771da177e4SLinus Torvalds } 52781da177e4SLinus Torvalds 527987c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 52801da177e4SLinus Torvalds { 52811442f76dSChristoph Hellwig struct msdos_partition *pp; 5282979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 52831da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 52841da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 52851da177e4SLinus Torvalds 52861da177e4SLinus Torvalds /* assume partition table already zeroed */ 5287773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 52881da177e4SLinus Torvalds return; 5289773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5290773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5291c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 52921da177e4SLinus Torvalds } 52938c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 52941da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5295773642d9SDouglas Gilbert / sdebug_num_parts; 52961da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 52971da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5298979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5299979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 53001da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 53011da177e4SLinus Torvalds * heads_by_sects; 5302979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5303979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5304979e0dc3SJohn Pittman } 5305773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5306773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 53071da177e4SLinus Torvalds 53081da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 53091da177e4SLinus Torvalds ramp[511] = 0xAA; 53101442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 53111da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 53121da177e4SLinus Torvalds start_sec = starts[k]; 5313979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 53141da177e4SLinus Torvalds pp->boot_ind = 0; 53151da177e4SLinus Torvalds 53161da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 53171da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 53181da177e4SLinus Torvalds / sdebug_sectors_per; 53191da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 53201da177e4SLinus Torvalds 53211da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 53221da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 53231da177e4SLinus Torvalds / sdebug_sectors_per; 53241da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 53251da177e4SLinus Torvalds 5326150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5327150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 53281da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 53291da177e4SLinus Torvalds } 53301da177e4SLinus Torvalds } 53311da177e4SLinus Torvalds 5332c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 5333c4837394SDouglas Gilbert { 5334c4837394SDouglas Gilbert int j; 5335c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5336c4837394SDouglas Gilbert 5337c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 5338c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 5339c4837394SDouglas Gilbert } 5340c4837394SDouglas Gilbert 5341c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5342c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5343c4837394SDouglas Gilbert */ 5344c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5345c4837394SDouglas Gilbert { 5346c4837394SDouglas Gilbert int count, modulo; 5347c4837394SDouglas Gilbert 5348c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5349c4837394SDouglas Gilbert if (modulo < 2) 5350c4837394SDouglas Gilbert return; 5351c4837394SDouglas Gilbert block_unblock_all_queues(true); 5352c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5353c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5354c4837394SDouglas Gilbert block_unblock_all_queues(false); 5355c4837394SDouglas Gilbert } 5356c4837394SDouglas Gilbert 5357c4837394SDouglas Gilbert static void clear_queue_stats(void) 5358c4837394SDouglas Gilbert { 5359c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5360c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5361c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5362c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5363c4837394SDouglas Gilbert } 5364c4837394SDouglas Gilbert 53653a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5366c4837394SDouglas Gilbert { 53673a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 53683a90a63dSDouglas Gilbert return false; 53693a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5370c4837394SDouglas Gilbert } 5371c4837394SDouglas Gilbert 5372a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5373a2aede97SDouglas Gilbert 5374c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5375c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5376c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5377c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5378c4837394SDouglas Gilbert */ 5379fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5380f66b8517SMartin Wilck int scsi_result, 5381f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, 5382f66b8517SMartin Wilck struct sdebug_dev_info *), 5383f66b8517SMartin Wilck int delta_jiff, int ndelay) 53841da177e4SLinus Torvalds { 5385a2aede97SDouglas Gilbert bool new_sd_dp; 53863a90a63dSDouglas Gilbert bool inject = false; 5387*a6e76e6fSBart Van Assche bool hipri = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_HIPRI; 53883a90a63dSDouglas Gilbert int k, num_in_q, qdepth; 5389a2aede97SDouglas Gilbert unsigned long iflags; 5390a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5391c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5392c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5393299b6c07STomas Winkler struct scsi_device *sdp; 5394a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 53951da177e4SLinus Torvalds 5396b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5397b01f6f83SDouglas Gilbert if (scsi_result == 0) 5398f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5399f46eb0e9SDouglas Gilbert goto respond_in_thread; 54001da177e4SLinus Torvalds } 5401299b6c07STomas Winkler sdp = cmnd->device; 5402299b6c07STomas Winkler 5403cd62b7daSDouglas Gilbert if (delta_jiff == 0) 5404cd62b7daSDouglas Gilbert goto respond_in_thread; 54051da177e4SLinus Torvalds 5406c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5407c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5408c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5409c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5410c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5411c4837394SDouglas Gilbert } 5412cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5413cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5414f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5415cd62b7daSDouglas Gilbert if (scsi_result) { 5416c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5417cd62b7daSDouglas Gilbert goto respond_in_thread; 5418cd62b7daSDouglas Gilbert } else 5419cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5420c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5421773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5422f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5423cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5424cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5425773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5426cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 54273a90a63dSDouglas Gilbert inject = true; 5428cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 54291da177e4SLinus Torvalds } 5430cbf67842SDouglas Gilbert } 5431cbf67842SDouglas Gilbert 5432c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5433f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5434c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5435cd62b7daSDouglas Gilbert if (scsi_result) 5436cd62b7daSDouglas Gilbert goto respond_in_thread; 5437773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 5438cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5439773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 5440cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5441cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 5442773642d9SDouglas Gilbert __func__, sdebug_max_queue, 5443cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 5444cbf67842SDouglas Gilbert "report: host busy")); 5445cd62b7daSDouglas Gilbert if (scsi_result) 5446cd62b7daSDouglas Gilbert goto respond_in_thread; 5447cd62b7daSDouglas Gilbert else 5448cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 54491da177e4SLinus Torvalds } 545074595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5451cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5452c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 54531da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5454c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5455a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5456c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5457c4b57d89SKashyap Desai 545874595c04SDouglas Gilbert if (!sd_dp) { 545910bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 546074595c04SDouglas Gilbert if (!sd_dp) { 546174595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 546274595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 546310bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 546474595c04SDouglas Gilbert } 5465a2aede97SDouglas Gilbert new_sd_dp = true; 5466a2aede97SDouglas Gilbert } else { 5467a2aede97SDouglas Gilbert new_sd_dp = false; 546810bde980SDouglas Gilbert } 5469f66b8517SMartin Wilck 5470c10fa55fSJohn Garry /* Set the hostwide tag */ 5471c10fa55fSJohn Garry if (sdebug_host_max_queue) 5472c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5473c10fa55fSJohn Garry 5474771f712bSDouglas Gilbert if (hipri) 5475a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5476a2aede97SDouglas Gilbert 5477a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 54783a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5479f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5480f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5481f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5482f66b8517SMartin Wilck } 5483f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5484f66b8517SMartin Wilck cmnd->result = scsi_result; 54853a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 54863a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 54873a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 54883a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 54893a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 54903a90a63dSDouglas Gilbert } 54913a90a63dSDouglas Gilbert } 5492f66b8517SMartin Wilck 5493f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5494f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5495f66b8517SMartin Wilck __func__, cmnd->result); 5496f66b8517SMartin Wilck 549710bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5498b333a819SDouglas Gilbert ktime_t kt; 5499cbf67842SDouglas Gilbert 5500b333a819SDouglas Gilbert if (delta_jiff > 0) { 55010c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 55020c4bc91dSDouglas Gilbert 55030c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 55040c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 55050c4bc91dSDouglas Gilbert } else if (sdebug_random) { 55060c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 55070c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 55080c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 55090c4bc91dSDouglas Gilbert ns <<= 12; 55100c4bc91dSDouglas Gilbert } 55110c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 55120c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 55130c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 55140c4bc91dSDouglas Gilbert (u32)ndelay; 5515a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5516a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5517a2aede97SDouglas Gilbert 5518a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5519223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5520a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5521a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5522a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5523223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5524a2aede97SDouglas Gilbert if (new_sd_dp) 5525a2aede97SDouglas Gilbert kfree(sd_dp); 5526a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 5527a2aede97SDouglas Gilbert cmnd->scsi_done(cmnd); 5528a2aede97SDouglas Gilbert return 0; 5529a2aede97SDouglas Gilbert } 5530a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5531a2aede97SDouglas Gilbert kt -= d; 5532a2aede97SDouglas Gilbert } 55330c4bc91dSDouglas Gilbert } 5534771f712bSDouglas Gilbert if (hipri) { 55354a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 55364a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 55374a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 55384a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 55394a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 55404a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 55414a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 55424a0c6f43SDouglas Gilbert } 55434a0c6f43SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_POLL; 55444a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 55454a0c6f43SDouglas Gilbert } else { 554610bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 554710bde980SDouglas Gilbert sd_dp->init_hrt = true; 5548a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5549a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5550c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5551a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5552c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5553c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5554cbf67842SDouglas Gilbert } 555510bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_HRT; 5556a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5557c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 55584a0c6f43SDouglas Gilbert } 55594a0c6f43SDouglas Gilbert if (sdebug_statistics) 55604a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 5561c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 55624a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 55634a0c6f43SDouglas Gilbert atomic_read(&sdeb_inject_pending))) 55644a0c6f43SDouglas Gilbert sd_dp->aborted = true; 5565771f712bSDouglas Gilbert if (hipri) { 55664a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 55674a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 55684a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 55694a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 55704a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 55714a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 55724a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 55734a0c6f43SDouglas Gilbert } 55744a0c6f43SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_POLL; 55754a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 55764a0c6f43SDouglas Gilbert } else { 557710bde980SDouglas Gilbert if (!sd_dp->init_wq) { 557810bde980SDouglas Gilbert sd_dp->init_wq = true; 5579a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5580c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5581c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5582a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5583cbf67842SDouglas Gilbert } 55844a0c6f43SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_WQ; 55854a0c6f43SDouglas Gilbert schedule_work(&sd_dp->ew.work); 55864a0c6f43SDouglas Gilbert } 5587c4837394SDouglas Gilbert if (sdebug_statistics) 5588c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 55894a0c6f43SDouglas Gilbert if (unlikely(sd_dp->aborted)) { 5590*a6e76e6fSBart Van Assche sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 5591*a6e76e6fSBart Van Assche scsi_cmd_to_rq(cmnd)->tag); 5592*a6e76e6fSBart Van Assche blk_abort_request(scsi_cmd_to_rq(cmnd)); 55933a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 55944a0c6f43SDouglas Gilbert sd_dp->aborted = false; 55957382f9d8SDouglas Gilbert } 5596cbf67842SDouglas Gilbert } 55973a90a63dSDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result)) 55983a90a63dSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__, 55993a90a63dSDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL"); 56001da177e4SLinus Torvalds return 0; 5601cd62b7daSDouglas Gilbert 5602cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5603f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5604f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5605f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5606cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 5607cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 5608cd62b7daSDouglas Gilbert return 0; 56091da177e4SLinus Torvalds } 5610cbf67842SDouglas Gilbert 561123183910SDouglas Gilbert /* Note: The following macros create attribute files in the 561223183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 561323183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 561423183910SDouglas Gilbert as it can when the corresponding attribute in the 561523183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 561623183910SDouglas Gilbert */ 5617773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5618773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 56199b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5620773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5621c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5622773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5623773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5624773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5625773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5626773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5627773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5628773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5629773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5630c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5631e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5632e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5633e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5634e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 56355d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 56365d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 56375d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5638773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5639773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5640773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5641773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5642ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5643773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5644773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 56455d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 56465d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 56475d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 56485d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5649773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5650773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 5651773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5652773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5653773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5654773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 56555d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5656773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 565787c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 565887c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5659773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5660773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 56610c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5662773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5663773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5664773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5665c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5666773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5667c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5668c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5669fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5670773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5671773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5672773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5673773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 567409ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 56755d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5676773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 567723183910SDouglas Gilbert S_IRUGO | S_IWUSR); 56789447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5679773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 56805b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 56819267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 5682380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5683aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 568498e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 56851da177e4SLinus Torvalds 56861da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 56871da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 56881da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5689b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 56901da177e4SLinus Torvalds 56915d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 56925b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 56939b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 56940759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5695cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5696c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 56975b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 56985b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5699c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5700beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 570123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 57025b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5703185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5704c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5705c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5706e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 57079b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 57089b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 57095d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 57105d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 57115d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 57125b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 57135b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 57145b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 57155b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5716ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5717fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5718cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5719d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 57205d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5721cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5722c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 572378d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 57241da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5725c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 572632c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 572786e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 57285d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 57295d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 57305d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5731fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 57321da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 57330c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5734d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5735760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5736ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5737c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5738c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5739c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5740fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 57415b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 57425b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 57436014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 57446014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 574509ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 574609ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5747c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 57485b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 57499447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 57505b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 57519267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 5752380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5753aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 575498e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 57551da177e4SLinus Torvalds 5756760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5757760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 57581da177e4SLinus Torvalds 57591da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 57601da177e4SLinus Torvalds { 5761c4837394SDouglas Gilbert int k; 5762c4837394SDouglas Gilbert 5763760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5764760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5765760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5766c4837394SDouglas Gilbert return sdebug_info; 5767760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5768760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5769760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5770760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 57711da177e4SLinus Torvalds return sdebug_info; 57721da177e4SLinus Torvalds } 57731da177e4SLinus Torvalds 5774cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5775fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5776fd32119bSDouglas Gilbert int length) 57771da177e4SLinus Torvalds { 57781da177e4SLinus Torvalds char arr[16]; 5779c8ed555aSAl Viro int opts; 57801da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 57811da177e4SLinus Torvalds 57821da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 57831da177e4SLinus Torvalds return -EACCES; 57841da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 57851da177e4SLinus Torvalds arr[minLen] = '\0'; 5786c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 57871da177e4SLinus Torvalds return -EINVAL; 5788773642d9SDouglas Gilbert sdebug_opts = opts; 5789773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5790773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5791773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5792c4837394SDouglas Gilbert tweak_cmnd_count(); 57931da177e4SLinus Torvalds return length; 57941da177e4SLinus Torvalds } 5795c8ed555aSAl Viro 5796cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5797cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5798cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5799c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5800c8ed555aSAl Viro { 5801c4837394SDouglas Gilbert int f, j, l; 5802c4837394SDouglas Gilbert struct sdebug_queue *sqp; 580387c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5804cbf67842SDouglas Gilbert 5805c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5806c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5807c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5808c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5809c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 5810c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 5811c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 5812c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 5813c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 5814c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 5815c4837394SDouglas Gilbert num_aborts); 5816c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 5817c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 5818c4837394SDouglas Gilbert num_host_resets); 5819c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 5820c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 5821458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 5822458df78bSBart Van Assche sdebug_statistics); 58234a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 5824c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 5825c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 5826c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 58274a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 58284a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 5829cbf67842SDouglas Gilbert 5830c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 5831c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5832c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 5833c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 5834773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 5835c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 5836c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 5837c4837394SDouglas Gilbert "first,last bits", f, l); 5838c4837394SDouglas Gilbert } 5839cbf67842SDouglas Gilbert } 584087c715dcSDouglas Gilbert 584187c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 584287c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 584387c715dcSDouglas Gilbert bool niu; 584487c715dcSDouglas Gilbert int idx; 584587c715dcSDouglas Gilbert unsigned long l_idx; 584687c715dcSDouglas Gilbert struct sdeb_store_info *sip; 584787c715dcSDouglas Gilbert 584887c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 584987c715dcSDouglas Gilbert j = 0; 585087c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 585187c715dcSDouglas Gilbert idx = sdhp->si_idx; 585287c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 585387c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 585487c715dcSDouglas Gilbert ++j; 585587c715dcSDouglas Gilbert } 585687c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 585787c715dcSDouglas Gilbert sdeb_most_recent_idx); 585887c715dcSDouglas Gilbert j = 0; 585987c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 586087c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 586187c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 586287c715dcSDouglas Gilbert idx = (int)l_idx; 586387c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 586487c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 586587c715dcSDouglas Gilbert ++j; 586687c715dcSDouglas Gilbert } 586787c715dcSDouglas Gilbert } 5868c8ed555aSAl Viro return 0; 58691da177e4SLinus Torvalds } 58701da177e4SLinus Torvalds 587182069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 58721da177e4SLinus Torvalds { 5873c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 58741da177e4SLinus Torvalds } 5875c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 5876c4837394SDouglas Gilbert * of delay is jiffies. 5877c4837394SDouglas Gilbert */ 587882069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 587982069379SAkinobu Mita size_t count) 58801da177e4SLinus Torvalds { 5881c2206098SDouglas Gilbert int jdelay, res; 58821da177e4SLinus Torvalds 5883b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 5884cbf67842SDouglas Gilbert res = count; 5885c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 5886c4837394SDouglas Gilbert int j, k; 5887c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5888cbf67842SDouglas Gilbert 5889c4837394SDouglas Gilbert block_unblock_all_queues(true); 5890c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5891c4837394SDouglas Gilbert ++j, ++sqp) { 5892c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5893c4837394SDouglas Gilbert sdebug_max_queue); 5894c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5895c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5896c4837394SDouglas Gilbert break; 5897c4837394SDouglas Gilbert } 5898c4837394SDouglas Gilbert } 5899c4837394SDouglas Gilbert if (res > 0) { 5900c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 5901773642d9SDouglas Gilbert sdebug_ndelay = 0; 59021da177e4SLinus Torvalds } 5903c4837394SDouglas Gilbert block_unblock_all_queues(false); 5904cbf67842SDouglas Gilbert } 5905cbf67842SDouglas Gilbert return res; 59061da177e4SLinus Torvalds } 59071da177e4SLinus Torvalds return -EINVAL; 59081da177e4SLinus Torvalds } 590982069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 59101da177e4SLinus Torvalds 5911cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 5912cbf67842SDouglas Gilbert { 5913773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 5914cbf67842SDouglas Gilbert } 5915cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 5916c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 5917cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 5918cbf67842SDouglas Gilbert size_t count) 5919cbf67842SDouglas Gilbert { 5920c4837394SDouglas Gilbert int ndelay, res; 5921cbf67842SDouglas Gilbert 5922cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 5923c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 5924cbf67842SDouglas Gilbert res = count; 5925773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 5926c4837394SDouglas Gilbert int j, k; 5927c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5928c4837394SDouglas Gilbert 5929c4837394SDouglas Gilbert block_unblock_all_queues(true); 5930c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5931c4837394SDouglas Gilbert ++j, ++sqp) { 5932c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5933c4837394SDouglas Gilbert sdebug_max_queue); 5934c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5935c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5936c4837394SDouglas Gilbert break; 5937c4837394SDouglas Gilbert } 5938c4837394SDouglas Gilbert } 5939c4837394SDouglas Gilbert if (res > 0) { 5940773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 5941c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 5942c2206098SDouglas Gilbert : DEF_JDELAY; 5943cbf67842SDouglas Gilbert } 5944c4837394SDouglas Gilbert block_unblock_all_queues(false); 5945cbf67842SDouglas Gilbert } 5946cbf67842SDouglas Gilbert return res; 5947cbf67842SDouglas Gilbert } 5948cbf67842SDouglas Gilbert return -EINVAL; 5949cbf67842SDouglas Gilbert } 5950cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 5951cbf67842SDouglas Gilbert 595282069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 59531da177e4SLinus Torvalds { 5954773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 59551da177e4SLinus Torvalds } 59561da177e4SLinus Torvalds 595782069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 595882069379SAkinobu Mita size_t count) 59591da177e4SLinus Torvalds { 59601da177e4SLinus Torvalds int opts; 59611da177e4SLinus Torvalds char work[20]; 59621da177e4SLinus Torvalds 59639a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 59649a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 59659a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 59661da177e4SLinus Torvalds goto opts_done; 59671da177e4SLinus Torvalds } else { 59689a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 59691da177e4SLinus Torvalds goto opts_done; 59701da177e4SLinus Torvalds } 59711da177e4SLinus Torvalds } 59721da177e4SLinus Torvalds return -EINVAL; 59731da177e4SLinus Torvalds opts_done: 5974773642d9SDouglas Gilbert sdebug_opts = opts; 5975773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5976773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5977c4837394SDouglas Gilbert tweak_cmnd_count(); 59781da177e4SLinus Torvalds return count; 59791da177e4SLinus Torvalds } 598082069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 59811da177e4SLinus Torvalds 598282069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 59831da177e4SLinus Torvalds { 5984773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 59851da177e4SLinus Torvalds } 598682069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 598782069379SAkinobu Mita size_t count) 59881da177e4SLinus Torvalds { 59891da177e4SLinus Torvalds int n; 59901da177e4SLinus Torvalds 5991f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 5992f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 5993f0d1cf93SDouglas Gilbert return -EINVAL; 5994f0d1cf93SDouglas Gilbert 59951da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5996f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 5997f0d1cf93SDouglas Gilbert return -EINVAL; 5998773642d9SDouglas Gilbert sdebug_ptype = n; 59991da177e4SLinus Torvalds return count; 60001da177e4SLinus Torvalds } 60011da177e4SLinus Torvalds return -EINVAL; 60021da177e4SLinus Torvalds } 600382069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 60041da177e4SLinus Torvalds 600582069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 60061da177e4SLinus Torvalds { 6007773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 60081da177e4SLinus Torvalds } 600982069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 601082069379SAkinobu Mita size_t count) 60111da177e4SLinus Torvalds { 60121da177e4SLinus Torvalds int n; 60131da177e4SLinus Torvalds 60141da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6015773642d9SDouglas Gilbert sdebug_dsense = n; 60161da177e4SLinus Torvalds return count; 60171da177e4SLinus Torvalds } 60181da177e4SLinus Torvalds return -EINVAL; 60191da177e4SLinus Torvalds } 602082069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 60211da177e4SLinus Torvalds 602282069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 602323183910SDouglas Gilbert { 6024773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 602523183910SDouglas Gilbert } 602682069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 602782069379SAkinobu Mita size_t count) 602823183910SDouglas Gilbert { 602987c715dcSDouglas Gilbert int n, idx; 603023183910SDouglas Gilbert 603123183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 603287c715dcSDouglas Gilbert bool want_store = (n == 0); 603387c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 603487c715dcSDouglas Gilbert 6035cbf67842SDouglas Gilbert n = (n > 0); 6036773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 603787c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 603887c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6039cbf67842SDouglas Gilbert 604087c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 604187c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 604287c715dcSDouglas Gilbert idx = sdebug_add_store(); 604387c715dcSDouglas Gilbert if (idx < 0) 604487c715dcSDouglas Gilbert return idx; 604587c715dcSDouglas Gilbert } else { 604687c715dcSDouglas Gilbert idx = sdeb_first_idx; 604787c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 604887c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6049cbf67842SDouglas Gilbert } 605087c715dcSDouglas Gilbert /* make all hosts use same store */ 605187c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 605287c715dcSDouglas Gilbert host_list) { 605387c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 605487c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 605587c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 605687c715dcSDouglas Gilbert sdhp->si_idx = idx; 605787c715dcSDouglas Gilbert } 605887c715dcSDouglas Gilbert } 605987c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 606087c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 606187c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6062cbf67842SDouglas Gilbert } 6063773642d9SDouglas Gilbert sdebug_fake_rw = n; 606423183910SDouglas Gilbert return count; 606523183910SDouglas Gilbert } 606623183910SDouglas Gilbert return -EINVAL; 606723183910SDouglas Gilbert } 606882069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 606923183910SDouglas Gilbert 607082069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6071c65b1445SDouglas Gilbert { 6072773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6073c65b1445SDouglas Gilbert } 607482069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 607582069379SAkinobu Mita size_t count) 6076c65b1445SDouglas Gilbert { 6077c65b1445SDouglas Gilbert int n; 6078c65b1445SDouglas Gilbert 6079c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6080773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6081c65b1445SDouglas Gilbert return count; 6082c65b1445SDouglas Gilbert } 6083c65b1445SDouglas Gilbert return -EINVAL; 6084c65b1445SDouglas Gilbert } 608582069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6086c65b1445SDouglas Gilbert 608782069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 60881da177e4SLinus Torvalds { 6089773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 60901da177e4SLinus Torvalds } 609182069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 609282069379SAkinobu Mita size_t count) 60931da177e4SLinus Torvalds { 60941da177e4SLinus Torvalds int n; 60951da177e4SLinus Torvalds 60961da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6097773642d9SDouglas Gilbert sdebug_num_tgts = n; 60981da177e4SLinus Torvalds sdebug_max_tgts_luns(); 60991da177e4SLinus Torvalds return count; 61001da177e4SLinus Torvalds } 61011da177e4SLinus Torvalds return -EINVAL; 61021da177e4SLinus Torvalds } 610382069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 61041da177e4SLinus Torvalds 610582069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 61061da177e4SLinus Torvalds { 6107773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 61081da177e4SLinus Torvalds } 610982069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 61101da177e4SLinus Torvalds 611187c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 611287c715dcSDouglas Gilbert { 611387c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 611487c715dcSDouglas Gilbert } 611587c715dcSDouglas Gilbert 611687c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 611787c715dcSDouglas Gilbert size_t count) 611887c715dcSDouglas Gilbert { 611987c715dcSDouglas Gilbert bool v; 612087c715dcSDouglas Gilbert 612187c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 612287c715dcSDouglas Gilbert return -EINVAL; 612387c715dcSDouglas Gilbert 612487c715dcSDouglas Gilbert sdebug_per_host_store = v; 612587c715dcSDouglas Gilbert return count; 612687c715dcSDouglas Gilbert } 612787c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 612887c715dcSDouglas Gilbert 612982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 61301da177e4SLinus Torvalds { 6131773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 61321da177e4SLinus Torvalds } 613382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 61341da177e4SLinus Torvalds 613582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 61361da177e4SLinus Torvalds { 6137773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 61381da177e4SLinus Torvalds } 613982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 614082069379SAkinobu Mita size_t count) 61411da177e4SLinus Torvalds { 61421da177e4SLinus Torvalds int nth; 61433a90a63dSDouglas Gilbert char work[20]; 61441da177e4SLinus Torvalds 61453a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 61463a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 61473a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 61483a90a63dSDouglas Gilbert goto every_nth_done; 61493a90a63dSDouglas Gilbert } else { 61503a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 61513a90a63dSDouglas Gilbert goto every_nth_done; 61523a90a63dSDouglas Gilbert } 61533a90a63dSDouglas Gilbert } 61543a90a63dSDouglas Gilbert return -EINVAL; 61553a90a63dSDouglas Gilbert 61563a90a63dSDouglas Gilbert every_nth_done: 6157773642d9SDouglas Gilbert sdebug_every_nth = nth; 6158c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6159c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6160c4837394SDouglas Gilbert sdebug_statistics = true; 6161c4837394SDouglas Gilbert } 6162c4837394SDouglas Gilbert tweak_cmnd_count(); 61631da177e4SLinus Torvalds return count; 61641da177e4SLinus Torvalds } 616582069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 61661da177e4SLinus Torvalds 6167ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6168ad0c7775SDouglas Gilbert { 6169ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6170ad0c7775SDouglas Gilbert } 6171ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6172ad0c7775SDouglas Gilbert size_t count) 6173ad0c7775SDouglas Gilbert { 6174ad0c7775SDouglas Gilbert int n; 6175ad0c7775SDouglas Gilbert bool changed; 6176ad0c7775SDouglas Gilbert 6177ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6178ad0c7775SDouglas Gilbert return -EINVAL; 6179ad0c7775SDouglas Gilbert if (n >= 0) { 6180ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6181ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6182ad0c7775SDouglas Gilbert return -EINVAL; 6183ad0c7775SDouglas Gilbert } 6184ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6185ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6186ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6187ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6188ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6189ad0c7775SDouglas Gilbert 6190ad0c7775SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 6191ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6192ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6193ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6194ad0c7775SDouglas Gilbert } 6195ad0c7775SDouglas Gilbert } 6196ad0c7775SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 6197ad0c7775SDouglas Gilbert } 6198ad0c7775SDouglas Gilbert return count; 6199ad0c7775SDouglas Gilbert } 6200ad0c7775SDouglas Gilbert return -EINVAL; 6201ad0c7775SDouglas Gilbert } 6202ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6203ad0c7775SDouglas Gilbert 620482069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 62051da177e4SLinus Torvalds { 6206773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 62071da177e4SLinus Torvalds } 620882069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 620982069379SAkinobu Mita size_t count) 62101da177e4SLinus Torvalds { 62111da177e4SLinus Torvalds int n; 621219c8ead7SEwan D. Milne bool changed; 62131da177e4SLinus Torvalds 62141da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 62158d039e22SDouglas Gilbert if (n > 256) { 62168d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 62178d039e22SDouglas Gilbert return -EINVAL; 62188d039e22SDouglas Gilbert } 6219773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6220773642d9SDouglas Gilbert sdebug_max_luns = n; 62211da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6222773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 622319c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 622419c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 622519c8ead7SEwan D. Milne 622619c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 622719c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 622819c8ead7SEwan D. Milne host_list) { 622919c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 623019c8ead7SEwan D. Milne dev_list) { 623119c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 623219c8ead7SEwan D. Milne dp->uas_bm); 623319c8ead7SEwan D. Milne } 623419c8ead7SEwan D. Milne } 623519c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 623619c8ead7SEwan D. Milne } 62371da177e4SLinus Torvalds return count; 62381da177e4SLinus Torvalds } 62391da177e4SLinus Torvalds return -EINVAL; 62401da177e4SLinus Torvalds } 624182069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 62421da177e4SLinus Torvalds 624382069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 624478d4e5a0SDouglas Gilbert { 6245773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 624678d4e5a0SDouglas Gilbert } 6247cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6248cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 624982069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 625082069379SAkinobu Mita size_t count) 625178d4e5a0SDouglas Gilbert { 6252c4837394SDouglas Gilbert int j, n, k, a; 6253c4837394SDouglas Gilbert struct sdebug_queue *sqp; 625478d4e5a0SDouglas Gilbert 625578d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6256c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6257c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 6258c4837394SDouglas Gilbert block_unblock_all_queues(true); 6259c4837394SDouglas Gilbert k = 0; 6260c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6261c4837394SDouglas Gilbert ++j, ++sqp) { 6262c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6263c4837394SDouglas Gilbert if (a > k) 6264c4837394SDouglas Gilbert k = a; 6265c4837394SDouglas Gilbert } 6266773642d9SDouglas Gilbert sdebug_max_queue = n; 6267c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6268cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6269cbf67842SDouglas Gilbert else if (k >= n) 6270cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6271cbf67842SDouglas Gilbert else 6272cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6273c4837394SDouglas Gilbert block_unblock_all_queues(false); 627478d4e5a0SDouglas Gilbert return count; 627578d4e5a0SDouglas Gilbert } 627678d4e5a0SDouglas Gilbert return -EINVAL; 627778d4e5a0SDouglas Gilbert } 627882069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 627978d4e5a0SDouglas Gilbert 6280c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6281c10fa55fSJohn Garry { 6282c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6283c10fa55fSJohn Garry } 6284c10fa55fSJohn Garry 6285c10fa55fSJohn Garry /* 6286c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6287c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6288c10fa55fSJohn Garry */ 6289c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6290c10fa55fSJohn Garry 629182069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 629278d4e5a0SDouglas Gilbert { 6293773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 629478d4e5a0SDouglas Gilbert } 629582069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 629678d4e5a0SDouglas Gilbert 629782069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 62981da177e4SLinus Torvalds { 6299773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 63001da177e4SLinus Torvalds } 630182069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 63021da177e4SLinus Torvalds 630382069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6304c65b1445SDouglas Gilbert { 6305773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6306c65b1445SDouglas Gilbert } 630782069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 630882069379SAkinobu Mita size_t count) 6309c65b1445SDouglas Gilbert { 6310c65b1445SDouglas Gilbert int n; 63110d01c5dfSDouglas Gilbert bool changed; 6312c65b1445SDouglas Gilbert 6313f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6314f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6315f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6316f0d1cf93SDouglas Gilbert 6317c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6318773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6319773642d9SDouglas Gilbert sdebug_virtual_gb = n; 632028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 63210d01c5dfSDouglas Gilbert if (changed) { 63220d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 63230d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 632428898873SFUJITA Tomonori 63254bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 63260d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 63270d01c5dfSDouglas Gilbert host_list) { 63280d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 63290d01c5dfSDouglas Gilbert dev_list) { 63300d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 63310d01c5dfSDouglas Gilbert dp->uas_bm); 63320d01c5dfSDouglas Gilbert } 63330d01c5dfSDouglas Gilbert } 63344bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 63350d01c5dfSDouglas Gilbert } 6336c65b1445SDouglas Gilbert return count; 6337c65b1445SDouglas Gilbert } 6338c65b1445SDouglas Gilbert return -EINVAL; 6339c65b1445SDouglas Gilbert } 634082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6341c65b1445SDouglas Gilbert 634282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 63431da177e4SLinus Torvalds { 634487c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 634587c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 63461da177e4SLinus Torvalds } 63471da177e4SLinus Torvalds 634882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 634982069379SAkinobu Mita size_t count) 63501da177e4SLinus Torvalds { 635187c715dcSDouglas Gilbert bool found; 635287c715dcSDouglas Gilbert unsigned long idx; 635387c715dcSDouglas Gilbert struct sdeb_store_info *sip; 635487c715dcSDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 63551da177e4SLinus Torvalds int delta_hosts; 63561da177e4SLinus Torvalds 6357f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 63581da177e4SLinus Torvalds return -EINVAL; 63591da177e4SLinus Torvalds if (delta_hosts > 0) { 63601da177e4SLinus Torvalds do { 636187c715dcSDouglas Gilbert found = false; 636287c715dcSDouglas Gilbert if (want_phs) { 636387c715dcSDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, 636487c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE) { 636587c715dcSDouglas Gilbert sdeb_most_recent_idx = (int)idx; 636687c715dcSDouglas Gilbert found = true; 636787c715dcSDouglas Gilbert break; 636887c715dcSDouglas Gilbert } 636987c715dcSDouglas Gilbert if (found) /* re-use case */ 637087c715dcSDouglas Gilbert sdebug_add_host_helper((int)idx); 637187c715dcSDouglas Gilbert else 637287c715dcSDouglas Gilbert sdebug_do_add_host(true); 637387c715dcSDouglas Gilbert } else { 637487c715dcSDouglas Gilbert sdebug_do_add_host(false); 637587c715dcSDouglas Gilbert } 63761da177e4SLinus Torvalds } while (--delta_hosts); 63771da177e4SLinus Torvalds } else if (delta_hosts < 0) { 63781da177e4SLinus Torvalds do { 637987c715dcSDouglas Gilbert sdebug_do_remove_host(false); 63801da177e4SLinus Torvalds } while (++delta_hosts); 63811da177e4SLinus Torvalds } 63821da177e4SLinus Torvalds return count; 63831da177e4SLinus Torvalds } 638482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 63851da177e4SLinus Torvalds 638682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 638723183910SDouglas Gilbert { 6388773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 638923183910SDouglas Gilbert } 639082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 639182069379SAkinobu Mita size_t count) 639223183910SDouglas Gilbert { 639323183910SDouglas Gilbert int n; 639423183910SDouglas Gilbert 639523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6396773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 639723183910SDouglas Gilbert return count; 639823183910SDouglas Gilbert } 639923183910SDouglas Gilbert return -EINVAL; 640023183910SDouglas Gilbert } 640182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 640223183910SDouglas Gilbert 6403c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6404c4837394SDouglas Gilbert { 6405c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6406c4837394SDouglas Gilbert } 6407c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6408c4837394SDouglas Gilbert size_t count) 6409c4837394SDouglas Gilbert { 6410c4837394SDouglas Gilbert int n; 6411c4837394SDouglas Gilbert 6412c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6413c4837394SDouglas Gilbert if (n > 0) 6414c4837394SDouglas Gilbert sdebug_statistics = true; 6415c4837394SDouglas Gilbert else { 6416c4837394SDouglas Gilbert clear_queue_stats(); 6417c4837394SDouglas Gilbert sdebug_statistics = false; 6418c4837394SDouglas Gilbert } 6419c4837394SDouglas Gilbert return count; 6420c4837394SDouglas Gilbert } 6421c4837394SDouglas Gilbert return -EINVAL; 6422c4837394SDouglas Gilbert } 6423c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6424c4837394SDouglas Gilbert 642582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6426597136abSMartin K. Petersen { 6427773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6428597136abSMartin K. Petersen } 642982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6430597136abSMartin K. Petersen 6431c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6432c4837394SDouglas Gilbert { 6433c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6434c4837394SDouglas Gilbert } 6435c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6436c4837394SDouglas Gilbert 643782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6438c6a44287SMartin K. Petersen { 6439773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6440c6a44287SMartin K. Petersen } 644182069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6442c6a44287SMartin K. Petersen 644382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6444c6a44287SMartin K. Petersen { 6445773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6446c6a44287SMartin K. Petersen } 644782069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6448c6a44287SMartin K. Petersen 644982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6450c6a44287SMartin K. Petersen { 6451773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6452c6a44287SMartin K. Petersen } 645382069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6454c6a44287SMartin K. Petersen 645582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6456c6a44287SMartin K. Petersen { 6457773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6458c6a44287SMartin K. Petersen } 645982069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6460c6a44287SMartin K. Petersen 646182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 646244d92694SMartin K. Petersen { 646387c715dcSDouglas Gilbert ssize_t count = 0; 646444d92694SMartin K. Petersen 64655b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 646644d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 646744d92694SMartin K. Petersen sdebug_store_sectors); 646844d92694SMartin K. Petersen 646987c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 647087c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 647187c715dcSDouglas Gilbert 647287c715dcSDouglas Gilbert if (sip) 6473c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 647487c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 647587c715dcSDouglas Gilbert } 647644d92694SMartin K. Petersen buf[count++] = '\n'; 6477c7badc90STejun Heo buf[count] = '\0'; 647844d92694SMartin K. Petersen 647944d92694SMartin K. Petersen return count; 648044d92694SMartin K. Petersen } 648182069379SAkinobu Mita static DRIVER_ATTR_RO(map); 648244d92694SMartin K. Petersen 64830c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 64840c4bc91dSDouglas Gilbert { 64850c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 64860c4bc91dSDouglas Gilbert } 64870c4bc91dSDouglas Gilbert 64880c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 64890c4bc91dSDouglas Gilbert size_t count) 64900c4bc91dSDouglas Gilbert { 64910c4bc91dSDouglas Gilbert bool v; 64920c4bc91dSDouglas Gilbert 64930c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 64940c4bc91dSDouglas Gilbert return -EINVAL; 64950c4bc91dSDouglas Gilbert 64960c4bc91dSDouglas Gilbert sdebug_random = v; 64970c4bc91dSDouglas Gilbert return count; 64980c4bc91dSDouglas Gilbert } 64990c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 65000c4bc91dSDouglas Gilbert 650182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6502d986788bSMartin Pitt { 6503773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6504d986788bSMartin Pitt } 650582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 650682069379SAkinobu Mita size_t count) 6507d986788bSMartin Pitt { 6508d986788bSMartin Pitt int n; 6509d986788bSMartin Pitt 6510d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6511773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6512d986788bSMartin Pitt return count; 6513d986788bSMartin Pitt } 6514d986788bSMartin Pitt return -EINVAL; 6515d986788bSMartin Pitt } 651682069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6517d986788bSMartin Pitt 6518cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6519cbf67842SDouglas Gilbert { 6520773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6521cbf67842SDouglas Gilbert } 6522185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6523cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6524cbf67842SDouglas Gilbert size_t count) 6525cbf67842SDouglas Gilbert { 6526185dd232SDouglas Gilbert int n; 6527cbf67842SDouglas Gilbert 6528cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6529185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6530185dd232SDouglas Gilbert return count; 6531cbf67842SDouglas Gilbert } 6532cbf67842SDouglas Gilbert return -EINVAL; 6533cbf67842SDouglas Gilbert } 6534cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6535cbf67842SDouglas Gilbert 6536c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6537c2248fc9SDouglas Gilbert { 6538773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6539c2248fc9SDouglas Gilbert } 6540c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6541c2248fc9SDouglas Gilbert size_t count) 6542c2248fc9SDouglas Gilbert { 6543c2248fc9SDouglas Gilbert int n; 6544c2248fc9SDouglas Gilbert 6545c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6546773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6547c2248fc9SDouglas Gilbert return count; 6548c2248fc9SDouglas Gilbert } 6549c2248fc9SDouglas Gilbert return -EINVAL; 6550c2248fc9SDouglas Gilbert } 6551c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6552c2248fc9SDouglas Gilbert 655309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 655409ba24c1SDouglas Gilbert { 655509ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 655609ba24c1SDouglas Gilbert } 655709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 655809ba24c1SDouglas Gilbert 65599b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 65609b760fd8SDouglas Gilbert { 65619b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 65629b760fd8SDouglas Gilbert } 65639b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 65649b760fd8SDouglas Gilbert size_t count) 65659b760fd8SDouglas Gilbert { 65669b760fd8SDouglas Gilbert int ret, n; 65679b760fd8SDouglas Gilbert 65689b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 65699b760fd8SDouglas Gilbert if (ret) 65709b760fd8SDouglas Gilbert return ret; 65719b760fd8SDouglas Gilbert sdebug_cdb_len = n; 65729b760fd8SDouglas Gilbert all_config_cdb_len(); 65739b760fd8SDouglas Gilbert return count; 65749b760fd8SDouglas Gilbert } 65759b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 65769b760fd8SDouglas Gilbert 65779267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 65789267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 65799267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 65809267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 65819267e0ebSDouglas Gilbert }; 65829267e0ebSDouglas Gilbert 65839267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 65849267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 65859267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 65869267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 65879267e0ebSDouglas Gilbert }; 65889267e0ebSDouglas Gilbert 65899267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 65909267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 65919267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 65929267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 65939267e0ebSDouglas Gilbert }; 65949267e0ebSDouglas Gilbert 65959267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 65969267e0ebSDouglas Gilbert { 65979267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 65989267e0ebSDouglas Gilbert 65999267e0ebSDouglas Gilbert if (res < 0) { 66009267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 66019267e0ebSDouglas Gilbert if (res < 0) { 66029267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 660347742bdeSDan Carpenter if (res < 0) 66049267e0ebSDouglas Gilbert return -EINVAL; 66059267e0ebSDouglas Gilbert } 66069267e0ebSDouglas Gilbert } 66079267e0ebSDouglas Gilbert return res; 66089267e0ebSDouglas Gilbert } 66099267e0ebSDouglas Gilbert 66109267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 66119267e0ebSDouglas Gilbert { 66129267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 66139267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 66149267e0ebSDouglas Gilbert } 66159267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6616cbf67842SDouglas Gilbert 6617fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6618fc13638aSDouglas Gilbert { 6619fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6620fc13638aSDouglas Gilbert } 6621fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6622fc13638aSDouglas Gilbert 662382069379SAkinobu Mita /* Note: The following array creates attribute files in the 662423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 662523183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 662623183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 662787c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 662823183910SDouglas Gilbert */ 66296ecaff7fSRandy Dunlap 663082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 663182069379SAkinobu Mita &driver_attr_delay.attr, 663282069379SAkinobu Mita &driver_attr_opts.attr, 663382069379SAkinobu Mita &driver_attr_ptype.attr, 663482069379SAkinobu Mita &driver_attr_dsense.attr, 663582069379SAkinobu Mita &driver_attr_fake_rw.attr, 6636c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 663782069379SAkinobu Mita &driver_attr_no_lun_0.attr, 663882069379SAkinobu Mita &driver_attr_num_tgts.attr, 663982069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 664082069379SAkinobu Mita &driver_attr_num_parts.attr, 664182069379SAkinobu Mita &driver_attr_every_nth.attr, 6642ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 664382069379SAkinobu Mita &driver_attr_max_luns.attr, 664482069379SAkinobu Mita &driver_attr_max_queue.attr, 664582069379SAkinobu Mita &driver_attr_no_uld.attr, 664682069379SAkinobu Mita &driver_attr_scsi_level.attr, 664782069379SAkinobu Mita &driver_attr_virtual_gb.attr, 664882069379SAkinobu Mita &driver_attr_add_host.attr, 664987c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 665082069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 665182069379SAkinobu Mita &driver_attr_sector_size.attr, 6652c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6653c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 665482069379SAkinobu Mita &driver_attr_dix.attr, 665582069379SAkinobu Mita &driver_attr_dif.attr, 665682069379SAkinobu Mita &driver_attr_guard.attr, 665782069379SAkinobu Mita &driver_attr_ato.attr, 665882069379SAkinobu Mita &driver_attr_map.attr, 66590c4bc91dSDouglas Gilbert &driver_attr_random.attr, 666082069379SAkinobu Mita &driver_attr_removable.attr, 6661cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6662cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6663c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 666409ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 66659b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6666fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 66679267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 666882069379SAkinobu Mita NULL, 666982069379SAkinobu Mita }; 667082069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 66711da177e4SLinus Torvalds 667211ddcecaSAkinobu Mita static struct device *pseudo_primary; 66738dea0d02SFUJITA Tomonori 66741da177e4SLinus Torvalds static int __init scsi_debug_init(void) 66751da177e4SLinus Torvalds { 667687c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 66775f2578e5SFUJITA Tomonori unsigned long sz; 667887c715dcSDouglas Gilbert int k, ret, hosts_to_add; 667987c715dcSDouglas Gilbert int idx = -1; 66801da177e4SLinus Torvalds 668187c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 668287c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6683cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6684cbf67842SDouglas Gilbert 6685773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6686c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6687773642d9SDouglas Gilbert sdebug_ndelay = 0; 6688773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6689c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6690cbf67842SDouglas Gilbert 6691773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6692597136abSMartin K. Petersen case 512: 6693597136abSMartin K. Petersen case 1024: 6694597136abSMartin K. Petersen case 2048: 6695597136abSMartin K. Petersen case 4096: 6696597136abSMartin K. Petersen break; 6697597136abSMartin K. Petersen default: 6698773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6699597136abSMartin K. Petersen return -EINVAL; 6700597136abSMartin K. Petersen } 6701597136abSMartin K. Petersen 6702773642d9SDouglas Gilbert switch (sdebug_dif) { 67038475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6704f46eb0e9SDouglas Gilbert break; 67058475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 67068475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 67078475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6708f46eb0e9SDouglas Gilbert have_dif_prot = true; 6709c6a44287SMartin K. Petersen break; 6710c6a44287SMartin K. Petersen 6711c6a44287SMartin K. Petersen default: 6712c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6713c6a44287SMartin K. Petersen return -EINVAL; 6714c6a44287SMartin K. Petersen } 6715c6a44287SMartin K. Petersen 6716aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6717aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6718aa5334c4SMaurizio Lombardi return -EINVAL; 6719aa5334c4SMaurizio Lombardi } 6720aa5334c4SMaurizio Lombardi 6721773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6722c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6723c6a44287SMartin K. Petersen return -EINVAL; 6724c6a44287SMartin K. Petersen } 6725c6a44287SMartin K. Petersen 6726773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6727c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6728c6a44287SMartin K. Petersen return -EINVAL; 6729c6a44287SMartin K. Petersen } 6730c6a44287SMartin K. Petersen 6731773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6732773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6733ea61fca5SMartin K. Petersen return -EINVAL; 6734ea61fca5SMartin K. Petersen } 6735ad0c7775SDouglas Gilbert 6736ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6737ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6738ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6739ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6740ad0c7775SDouglas Gilbert } 6741ad0c7775SDouglas Gilbert 67428d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6743ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6744ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 67458d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 67468d039e22SDouglas Gilbert } 6747ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6748ad0c7775SDouglas Gilbert } 6749ea61fca5SMartin K. Petersen 6750773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6751773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6752ea61fca5SMartin K. Petersen return -EINVAL; 6753ea61fca5SMartin K. Petersen } 6754ea61fca5SMartin K. Petersen 6755c4837394SDouglas Gilbert if (submit_queues < 1) { 6756c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6757c4837394SDouglas Gilbert return -EINVAL; 6758c4837394SDouglas Gilbert } 6759c87bf24cSJohn Garry 6760c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6761c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6762c87bf24cSJohn Garry return -EINVAL; 6763c87bf24cSJohn Garry } 6764c87bf24cSJohn Garry 6765c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6766c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6767c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6768c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6769c10fa55fSJohn Garry return -EINVAL; 6770c10fa55fSJohn Garry } 6771c10fa55fSJohn Garry 6772c10fa55fSJohn Garry if (sdebug_host_max_queue && 6773c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6774c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6775c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6776c10fa55fSJohn Garry sdebug_max_queue); 6777c10fa55fSJohn Garry } 6778c10fa55fSJohn Garry 6779c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6780c4837394SDouglas Gilbert GFP_KERNEL); 6781c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6782c4837394SDouglas Gilbert return -ENOMEM; 6783c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6784c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6785c4837394SDouglas Gilbert 6786f0d1cf93SDouglas Gilbert /* 67879267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 67889267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 6789f0d1cf93SDouglas Gilbert */ 67909267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 67919267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 67929267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 67939267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 67949267e0ebSDouglas Gilbert if (k < 0) { 67959267e0ebSDouglas Gilbert ret = k; 67963b01d7eaSDinghao Liu goto free_q_arr; 67979267e0ebSDouglas Gilbert } 67989267e0ebSDouglas Gilbert sdeb_zbc_model = k; 67999267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 68009267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 680164e14eceSDamien Le Moal case BLK_ZONED_HA: 68029267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 68039267e0ebSDouglas Gilbert break; 68049267e0ebSDouglas Gilbert case BLK_ZONED_HM: 68059267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 68069267e0ebSDouglas Gilbert break; 68079267e0ebSDouglas Gilbert default: 68089267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 68093b01d7eaSDinghao Liu ret = -EINVAL; 68103b01d7eaSDinghao Liu goto free_q_arr; 68119267e0ebSDouglas Gilbert } 68129267e0ebSDouglas Gilbert } 68139267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 6814f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 68159267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 68169267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 68179267e0ebSDouglas Gilbert } 6818f0d1cf93SDouglas Gilbert 68199267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 68209267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 6821773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 6822773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 6823773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 6824773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 682528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 68261da177e4SLinus Torvalds 68271da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 68281da177e4SLinus Torvalds sdebug_heads = 8; 68291da177e4SLinus Torvalds sdebug_sectors_per = 32; 6830773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 68311da177e4SLinus Torvalds sdebug_heads = 64; 6832773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 6833fa785f0aSAndy Shevchenko sdebug_heads = 32; 68341da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 68351da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 68361da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 68371da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 68381da177e4SLinus Torvalds sdebug_heads = 255; 68391da177e4SLinus Torvalds sdebug_sectors_per = 63; 68401da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 68411da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 68421da177e4SLinus Torvalds } 68435b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 6844773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 6845773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 68466014759cSMartin K. Petersen 6847773642d9SDouglas Gilbert sdebug_unmap_max_desc = 6848773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 68496014759cSMartin K. Petersen 6850773642d9SDouglas Gilbert sdebug_unmap_granularity = 6851773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 68526014759cSMartin K. Petersen 6853773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 6854773642d9SDouglas Gilbert sdebug_unmap_granularity <= 6855773642d9SDouglas Gilbert sdebug_unmap_alignment) { 6856c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 6857c4837394SDouglas Gilbert ret = -EINVAL; 685887c715dcSDouglas Gilbert goto free_q_arr; 685944d92694SMartin K. Petersen } 686044d92694SMartin K. Petersen } 686187c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 686287c715dcSDouglas Gilbert if (want_store) { 686387c715dcSDouglas Gilbert idx = sdebug_add_store(); 686487c715dcSDouglas Gilbert if (idx < 0) { 686587c715dcSDouglas Gilbert ret = idx; 686687c715dcSDouglas Gilbert goto free_q_arr; 686787c715dcSDouglas Gilbert } 686844d92694SMartin K. Petersen } 686944d92694SMartin K. Petersen 68709b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 68719b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 6872c1287970STomas Winkler pr_warn("root_device_register() error\n"); 68739b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 68746ecaff7fSRandy Dunlap goto free_vm; 68756ecaff7fSRandy Dunlap } 68766ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 68776ecaff7fSRandy Dunlap if (ret < 0) { 6878c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 68796ecaff7fSRandy Dunlap goto dev_unreg; 68806ecaff7fSRandy Dunlap } 68816ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 68826ecaff7fSRandy Dunlap if (ret < 0) { 6883c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 68846ecaff7fSRandy Dunlap goto bus_unreg; 68856ecaff7fSRandy Dunlap } 68861da177e4SLinus Torvalds 688787c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 6888773642d9SDouglas Gilbert sdebug_add_host = 0; 68891da177e4SLinus Torvalds 689087c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 689187c715dcSDouglas Gilbert if (want_store && k == 0) { 689287c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 689387c715dcSDouglas Gilbert if (ret < 0) { 689487c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 689587c715dcSDouglas Gilbert k, -ret); 689687c715dcSDouglas Gilbert break; 689787c715dcSDouglas Gilbert } 689887c715dcSDouglas Gilbert } else { 689987c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 690087c715dcSDouglas Gilbert sdebug_per_host_store); 690187c715dcSDouglas Gilbert if (ret < 0) { 690287c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 69031da177e4SLinus Torvalds break; 69041da177e4SLinus Torvalds } 69051da177e4SLinus Torvalds } 690687c715dcSDouglas Gilbert } 6907773642d9SDouglas Gilbert if (sdebug_verbose) 690887c715dcSDouglas Gilbert pr_info("built %d host(s)\n", sdebug_num_hosts); 6909c1287970STomas Winkler 69101da177e4SLinus Torvalds return 0; 69116ecaff7fSRandy Dunlap 69126ecaff7fSRandy Dunlap bus_unreg: 69136ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 69146ecaff7fSRandy Dunlap dev_unreg: 69159b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 69166ecaff7fSRandy Dunlap free_vm: 691787c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 6918c4837394SDouglas Gilbert free_q_arr: 6919c4837394SDouglas Gilbert kfree(sdebug_q_arr); 69206ecaff7fSRandy Dunlap return ret; 69211da177e4SLinus Torvalds } 69221da177e4SLinus Torvalds 69231da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 69241da177e4SLinus Torvalds { 692587c715dcSDouglas Gilbert int k = sdebug_num_hosts; 69261da177e4SLinus Torvalds 69271da177e4SLinus Torvalds stop_all_queued(); 69281da177e4SLinus Torvalds for (; k; k--) 692987c715dcSDouglas Gilbert sdebug_do_remove_host(true); 693052ab9768SLuis Henriques free_all_queued(); 69311da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 69321da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 69339b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 69341da177e4SLinus Torvalds 693587c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 693687c715dcSDouglas Gilbert xa_destroy(per_store_ap); 6937f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 69381da177e4SLinus Torvalds } 69391da177e4SLinus Torvalds 69401da177e4SLinus Torvalds device_initcall(scsi_debug_init); 69411da177e4SLinus Torvalds module_exit(scsi_debug_exit); 69421da177e4SLinus Torvalds 69431da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 69441da177e4SLinus Torvalds { 69451da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 69461da177e4SLinus Torvalds 69471da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 69481da177e4SLinus Torvalds kfree(sdbg_host); 69491da177e4SLinus Torvalds } 69501da177e4SLinus Torvalds 695187c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 695287c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 69531da177e4SLinus Torvalds { 695487c715dcSDouglas Gilbert if (idx < 0) 695587c715dcSDouglas Gilbert return; 695687c715dcSDouglas Gilbert if (!sip) { 695787c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 695887c715dcSDouglas Gilbert return; 695987c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 696087c715dcSDouglas Gilbert if (!sip) 696187c715dcSDouglas Gilbert return; 696287c715dcSDouglas Gilbert } 696387c715dcSDouglas Gilbert vfree(sip->map_storep); 696487c715dcSDouglas Gilbert vfree(sip->dif_storep); 696587c715dcSDouglas Gilbert vfree(sip->storep); 696687c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 696787c715dcSDouglas Gilbert kfree(sip); 696887c715dcSDouglas Gilbert } 696987c715dcSDouglas Gilbert 697087c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 697187c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 697287c715dcSDouglas Gilbert { 697387c715dcSDouglas Gilbert unsigned long idx; 697487c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 697587c715dcSDouglas Gilbert 697687c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 697787c715dcSDouglas Gilbert if (apart_from_first) 697887c715dcSDouglas Gilbert apart_from_first = false; 697987c715dcSDouglas Gilbert else 698087c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 698187c715dcSDouglas Gilbert } 698287c715dcSDouglas Gilbert if (apart_from_first) 698387c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 698487c715dcSDouglas Gilbert } 698587c715dcSDouglas Gilbert 698687c715dcSDouglas Gilbert /* 698787c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 698887c715dcSDouglas Gilbert * Limit the number of stores to 65536. 698987c715dcSDouglas Gilbert */ 699087c715dcSDouglas Gilbert static int sdebug_add_store(void) 699187c715dcSDouglas Gilbert { 699287c715dcSDouglas Gilbert int res; 699387c715dcSDouglas Gilbert u32 n_idx; 699487c715dcSDouglas Gilbert unsigned long iflags; 699587c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 699687c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 699787c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 699887c715dcSDouglas Gilbert 699987c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 700087c715dcSDouglas Gilbert if (!sip) 700187c715dcSDouglas Gilbert return -ENOMEM; 700287c715dcSDouglas Gilbert 700387c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 700487c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 700587c715dcSDouglas Gilbert if (unlikely(res < 0)) { 700687c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 700787c715dcSDouglas Gilbert kfree(sip); 700887c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 700987c715dcSDouglas Gilbert return res; 701087c715dcSDouglas Gilbert } 701187c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 701287c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 701387c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 701487c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 701587c715dcSDouglas Gilbert 701687c715dcSDouglas Gilbert res = -ENOMEM; 701787c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 701887c715dcSDouglas Gilbert if (!sip->storep) { 701987c715dcSDouglas Gilbert pr_err("user data oom\n"); 702087c715dcSDouglas Gilbert goto err; 702187c715dcSDouglas Gilbert } 702287c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 702387c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 702487c715dcSDouglas Gilbert 702587c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 702687c715dcSDouglas Gilbert if (sdebug_dix) { 702787c715dcSDouglas Gilbert int dif_size; 702887c715dcSDouglas Gilbert 702987c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 703087c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 703187c715dcSDouglas Gilbert 703287c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 703387c715dcSDouglas Gilbert sip->dif_storep); 703487c715dcSDouglas Gilbert 703587c715dcSDouglas Gilbert if (!sip->dif_storep) { 703687c715dcSDouglas Gilbert pr_err("DIX oom\n"); 703787c715dcSDouglas Gilbert goto err; 703887c715dcSDouglas Gilbert } 703987c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 704087c715dcSDouglas Gilbert } 704187c715dcSDouglas Gilbert /* Logical Block Provisioning */ 704287c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 704387c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 704487c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 704587c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 704687c715dcSDouglas Gilbert 704787c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 704887c715dcSDouglas Gilbert 704987c715dcSDouglas Gilbert if (!sip->map_storep) { 705087c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 705187c715dcSDouglas Gilbert goto err; 705287c715dcSDouglas Gilbert } 705387c715dcSDouglas Gilbert 705487c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 705587c715dcSDouglas Gilbert 705687c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 705787c715dcSDouglas Gilbert if (sdebug_num_parts) 705887c715dcSDouglas Gilbert map_region(sip, 0, 2); 705987c715dcSDouglas Gilbert } 706087c715dcSDouglas Gilbert 706187c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 706287c715dcSDouglas Gilbert return (int)n_idx; 706387c715dcSDouglas Gilbert err: 706487c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 706587c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 706687c715dcSDouglas Gilbert return res; 706787c715dcSDouglas Gilbert } 706887c715dcSDouglas Gilbert 706987c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 707087c715dcSDouglas Gilbert { 707187c715dcSDouglas Gilbert int k, devs_per_host, idx; 707287c715dcSDouglas Gilbert int error = -ENOMEM; 70731da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 70748b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 70751da177e4SLinus Torvalds 707624669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 707787c715dcSDouglas Gilbert if (!sdbg_host) 70781da177e4SLinus Torvalds return -ENOMEM; 707987c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 708087c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 708187c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 708287c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 70831da177e4SLinus Torvalds 70841da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 70851da177e4SLinus Torvalds 7086773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 70871da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 70885cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 708987c715dcSDouglas Gilbert if (!sdbg_devinfo) 70901da177e4SLinus Torvalds goto clean; 70911da177e4SLinus Torvalds } 70921da177e4SLinus Torvalds 70931da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 70941da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 70951da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 70961da177e4SLinus Torvalds 70971da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 70989b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 70991da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 710087c715dcSDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 71011da177e4SLinus Torvalds 71021da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 71031da177e4SLinus Torvalds if (error) 71041da177e4SLinus Torvalds goto clean; 71051da177e4SLinus Torvalds 710687c715dcSDouglas Gilbert ++sdebug_num_hosts; 710787c715dcSDouglas Gilbert return 0; 71081da177e4SLinus Torvalds 71091da177e4SLinus Torvalds clean: 71108b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 71118b40228fSFUJITA Tomonori dev_list) { 71121da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7113f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 71141da177e4SLinus Torvalds kfree(sdbg_devinfo); 71151da177e4SLinus Torvalds } 71161da177e4SLinus Torvalds kfree(sdbg_host); 711787c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 71181da177e4SLinus Torvalds return error; 71191da177e4SLinus Torvalds } 71201da177e4SLinus Torvalds 712187c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 71221da177e4SLinus Torvalds { 712387c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 712487c715dcSDouglas Gilbert 712587c715dcSDouglas Gilbert if (mk_new_store) { 712687c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 712787c715dcSDouglas Gilbert if (ph_idx < 0) 712887c715dcSDouglas Gilbert return ph_idx; 712987c715dcSDouglas Gilbert } 713087c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 713187c715dcSDouglas Gilbert } 713287c715dcSDouglas Gilbert 713387c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 713487c715dcSDouglas Gilbert { 713587c715dcSDouglas Gilbert int idx = -1; 71361da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 713787c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 71381da177e4SLinus Torvalds 71391da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 71401da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 71411da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 71421da177e4SLinus Torvalds struct sdebug_host_info, host_list); 714387c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 71441da177e4SLinus Torvalds } 714587c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 714687c715dcSDouglas Gilbert bool unique = true; 714787c715dcSDouglas Gilbert 714887c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 714987c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 715087c715dcSDouglas Gilbert continue; 715187c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 715287c715dcSDouglas Gilbert unique = false; 715387c715dcSDouglas Gilbert break; 715487c715dcSDouglas Gilbert } 715587c715dcSDouglas Gilbert } 715687c715dcSDouglas Gilbert if (unique) { 715787c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 715887c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 715987c715dcSDouglas Gilbert --sdeb_most_recent_idx; 716087c715dcSDouglas Gilbert } 716187c715dcSDouglas Gilbert } 716287c715dcSDouglas Gilbert if (sdbg_host) 716387c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 71641da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 71651da177e4SLinus Torvalds 71661da177e4SLinus Torvalds if (!sdbg_host) 71671da177e4SLinus Torvalds return; 71681da177e4SLinus Torvalds 71691da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 717087c715dcSDouglas Gilbert --sdebug_num_hosts; 71711da177e4SLinus Torvalds } 71721da177e4SLinus Torvalds 7173fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7174cbf67842SDouglas Gilbert { 7175cbf67842SDouglas Gilbert int num_in_q = 0; 7176cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7177cbf67842SDouglas Gilbert 7178c4837394SDouglas Gilbert block_unblock_all_queues(true); 7179cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7180cbf67842SDouglas Gilbert if (NULL == devip) { 7181c4837394SDouglas Gilbert block_unblock_all_queues(false); 7182cbf67842SDouglas Gilbert return -ENODEV; 7183cbf67842SDouglas Gilbert } 7184cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7185c40ecc12SChristoph Hellwig 7186fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7187fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7188fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7189fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7190fc09acb7SDouglas Gilbert } 7191cbf67842SDouglas Gilbert if (qdepth < 1) 7192cbf67842SDouglas Gilbert qdepth = 1; 7193fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7194db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7195cbf67842SDouglas Gilbert 7196773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7197c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7198c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7199cbf67842SDouglas Gilbert } 7200c4837394SDouglas Gilbert block_unblock_all_queues(false); 7201cbf67842SDouglas Gilbert return sdev->queue_depth; 7202cbf67842SDouglas Gilbert } 7203cbf67842SDouglas Gilbert 7204c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7205817fd66bSDouglas Gilbert { 7206c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7207773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7208773642d9SDouglas Gilbert sdebug_every_nth = -1; 7209773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7210c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7211773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7212817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7213c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7214817fd66bSDouglas Gilbert } 7215c4837394SDouglas Gilbert return false; 7216817fd66bSDouglas Gilbert } 7217817fd66bSDouglas Gilbert 7218fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7219fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7220fc13638aSDouglas Gilbert { 7221fc13638aSDouglas Gilbert int stopped_state; 7222fc13638aSDouglas Gilbert u64 diff_ns = 0; 7223fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7224fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7225fc13638aSDouglas Gilbert 7226fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7227fc13638aSDouglas Gilbert if (stopped_state == 2) { 7228fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7229fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7230fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7231fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7232fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7233fc13638aSDouglas Gilbert return 0; 7234fc13638aSDouglas Gilbert } 7235fc13638aSDouglas Gilbert } 7236fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7237fc13638aSDouglas Gilbert if (sdebug_verbose) 7238fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7239fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7240fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7241fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7242fc13638aSDouglas Gilbert 7243fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7244fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7245fc13638aSDouglas Gilbert else 7246fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7247fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7248fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7249fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7250fc13638aSDouglas Gilbert diff_ns); 7251fc13638aSDouglas Gilbert return check_condition_result; 7252fc13638aSDouglas Gilbert } 7253fc13638aSDouglas Gilbert } 7254fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7255fc13638aSDouglas Gilbert if (sdebug_verbose) 7256fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7257fc13638aSDouglas Gilbert my_name); 7258fc13638aSDouglas Gilbert return check_condition_result; 7259fc13638aSDouglas Gilbert } 7260fc13638aSDouglas Gilbert 7261c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost) 7262c4b57d89SKashyap Desai { 7263c4b57d89SKashyap Desai int i, qoff; 7264c4b57d89SKashyap Desai 7265c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7266c4b57d89SKashyap Desai return 0; 7267c4b57d89SKashyap Desai 7268c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7269c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7270c4b57d89SKashyap Desai 7271c4b57d89SKashyap Desai map->nr_queues = 0; 7272c4b57d89SKashyap Desai 7273c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7274c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7275c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7276c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7277c4b57d89SKashyap Desai 7278c4b57d89SKashyap Desai if (!map->nr_queues) { 7279c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7280c4b57d89SKashyap Desai continue; 7281c4b57d89SKashyap Desai } 7282c4b57d89SKashyap Desai 7283c4b57d89SKashyap Desai map->queue_offset = qoff; 7284c4b57d89SKashyap Desai blk_mq_map_queues(map); 7285c4b57d89SKashyap Desai 7286c4b57d89SKashyap Desai qoff += map->nr_queues; 7287c4b57d89SKashyap Desai } 7288c4b57d89SKashyap Desai 7289c4b57d89SKashyap Desai return 0; 7290c4b57d89SKashyap Desai 7291c4b57d89SKashyap Desai } 7292c4b57d89SKashyap Desai 7293c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7294c4b57d89SKashyap Desai { 72954a0c6f43SDouglas Gilbert bool first; 72964a0c6f43SDouglas Gilbert bool retiring = false; 72974a0c6f43SDouglas Gilbert int num_entries = 0; 72984a0c6f43SDouglas Gilbert unsigned int qc_idx = 0; 7299c4b57d89SKashyap Desai unsigned long iflags; 73004a0c6f43SDouglas Gilbert ktime_t kt_from_boot = ktime_get_boottime(); 7301c4b57d89SKashyap Desai struct sdebug_queue *sqp; 7302c4b57d89SKashyap Desai struct sdebug_queued_cmd *sqcp; 7303c4b57d89SKashyap Desai struct scsi_cmnd *scp; 7304c4b57d89SKashyap Desai struct sdebug_dev_info *devip; 73054a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7306c4b57d89SKashyap Desai 7307c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 7308c4b57d89SKashyap Desai spin_lock_irqsave(&sqp->qc_lock, iflags); 73094a0c6f43SDouglas Gilbert 73104a0c6f43SDouglas Gilbert for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { 73114a0c6f43SDouglas Gilbert if (first) { 7312c4b57d89SKashyap Desai qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 73134a0c6f43SDouglas Gilbert first = false; 73144a0c6f43SDouglas Gilbert } else { 73154a0c6f43SDouglas Gilbert qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1); 73164a0c6f43SDouglas Gilbert } 73174a0c6f43SDouglas Gilbert if (unlikely(qc_idx >= sdebug_max_queue)) 73184a0c6f43SDouglas Gilbert break; 7319c4b57d89SKashyap Desai 7320c4b57d89SKashyap Desai sqcp = &sqp->qc_arr[qc_idx]; 73214a0c6f43SDouglas Gilbert sd_dp = sqcp->sd_dp; 73224a0c6f43SDouglas Gilbert if (unlikely(!sd_dp)) 73234a0c6f43SDouglas Gilbert continue; 7324c4b57d89SKashyap Desai scp = sqcp->a_cmnd; 7325c4b57d89SKashyap Desai if (unlikely(scp == NULL)) { 73264a0c6f43SDouglas Gilbert pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n", 7327c4b57d89SKashyap Desai queue_num, qc_idx, __func__); 73284a0c6f43SDouglas Gilbert break; 7329c4b57d89SKashyap Desai } 73304a0c6f43SDouglas Gilbert if (sd_dp->defer_t == SDEB_DEFER_POLL) { 73314a0c6f43SDouglas Gilbert if (kt_from_boot < sd_dp->cmpl_ts) 73324a0c6f43SDouglas Gilbert continue; 73334a0c6f43SDouglas Gilbert 73344a0c6f43SDouglas Gilbert } else /* ignoring non REQ_HIPRI requests */ 73354a0c6f43SDouglas Gilbert continue; 7336c4b57d89SKashyap Desai devip = (struct sdebug_dev_info *)scp->device->hostdata; 7337c4b57d89SKashyap Desai if (likely(devip)) 7338c4b57d89SKashyap Desai atomic_dec(&devip->num_in_q); 7339c4b57d89SKashyap Desai else 7340c4b57d89SKashyap Desai pr_err("devip=NULL from %s\n", __func__); 7341c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 73424a0c6f43SDouglas Gilbert retiring = true; 7343c4b57d89SKashyap Desai 7344c4b57d89SKashyap Desai sqcp->a_cmnd = NULL; 7345c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 73464a0c6f43SDouglas Gilbert pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n", 7347c4b57d89SKashyap Desai sqp, queue_num, qc_idx, __func__); 73484a0c6f43SDouglas Gilbert break; 7349c4b57d89SKashyap Desai } 7350c4b57d89SKashyap Desai if (unlikely(retiring)) { /* user has reduced max_queue */ 7351c4b57d89SKashyap Desai int k, retval; 7352c4b57d89SKashyap Desai 7353c4b57d89SKashyap Desai retval = atomic_read(&retired_max_queue); 7354c4b57d89SKashyap Desai if (qc_idx >= retval) { 7355c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 73564a0c6f43SDouglas Gilbert break; 7357c4b57d89SKashyap Desai } 7358c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7359c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7360c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7361c4b57d89SKashyap Desai else 7362c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7363c4b57d89SKashyap Desai } 73644a0c6f43SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 7365c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 7366c4b57d89SKashyap Desai scp->scsi_done(scp); /* callback to mid level */ 73674a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 7368c4b57d89SKashyap Desai num_entries++; 73694a0c6f43SDouglas Gilbert } 7370c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 73714a0c6f43SDouglas Gilbert if (num_entries > 0) 73724a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7373c4b57d89SKashyap Desai return num_entries; 7374c4b57d89SKashyap Desai } 7375c4b57d89SKashyap Desai 7376fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7377fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7378c2248fc9SDouglas Gilbert { 7379c2248fc9SDouglas Gilbert u8 sdeb_i; 7380c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7381c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7382c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7383c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7384c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7385c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7386f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7387c2248fc9SDouglas Gilbert int k, na; 7388c2248fc9SDouglas Gilbert int errsts = 0; 7389ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7390c2248fc9SDouglas Gilbert u32 flags; 7391c2248fc9SDouglas Gilbert u16 sa; 7392c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7393c2248fc9SDouglas Gilbert bool has_wlun_rl; 73943a90a63dSDouglas Gilbert bool inject_now; 7395c2248fc9SDouglas Gilbert 7396c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 73973a90a63dSDouglas Gilbert if (sdebug_statistics) { 7398c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 73993a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 74003a90a63dSDouglas Gilbert } else { 74013a90a63dSDouglas Gilbert inject_now = false; 74023a90a63dSDouglas Gilbert } 7403f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7404f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7405c2248fc9SDouglas Gilbert char b[120]; 7406c2248fc9SDouglas Gilbert int n, len, sb; 7407c2248fc9SDouglas Gilbert 7408c2248fc9SDouglas Gilbert len = scp->cmd_len; 7409c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7410c2248fc9SDouglas Gilbert if (len > 32) 7411c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7412c2248fc9SDouglas Gilbert else { 7413c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7414c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7415c2248fc9SDouglas Gilbert (u32)cmd[k]); 7416c2248fc9SDouglas Gilbert } 7417458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7418*a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7419c2248fc9SDouglas Gilbert } 74203a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 74217ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 742234d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7423ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7424f46eb0e9SDouglas Gilbert goto err_out; 7425c2248fc9SDouglas Gilbert 7426c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7427c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7428c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7429f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7430f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7431c2248fc9SDouglas Gilbert if (NULL == devip) 7432f46eb0e9SDouglas Gilbert goto err_out; 7433c2248fc9SDouglas Gilbert } 74343a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 74353a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 74363a90a63dSDouglas Gilbert 7437c2248fc9SDouglas Gilbert na = oip->num_attached; 7438c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7439c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7440c2248fc9SDouglas Gilbert r_oip = oip; 7441c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7442c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7443c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7444c2248fc9SDouglas Gilbert else 7445c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7446c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7447c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7448c2248fc9SDouglas Gilbert break; 7449c2248fc9SDouglas Gilbert } 7450c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7451c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7452c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7453c2248fc9SDouglas Gilbert break; 7454c2248fc9SDouglas Gilbert } 7455c2248fc9SDouglas Gilbert } 7456c2248fc9SDouglas Gilbert if (k > na) { 7457c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7458c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7459c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7460c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7461c2248fc9SDouglas Gilbert else 7462c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7463c2248fc9SDouglas Gilbert goto check_cond; 7464c2248fc9SDouglas Gilbert } 7465c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7466c2248fc9SDouglas Gilbert flags = oip->flags; 7467f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7468c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7469c2248fc9SDouglas Gilbert goto check_cond; 7470c2248fc9SDouglas Gilbert } 7471f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7472773642d9SDouglas Gilbert if (sdebug_verbose) 7473773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7474773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7475c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7476c2248fc9SDouglas Gilbert goto check_cond; 7477c2248fc9SDouglas Gilbert } 7478f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7479c2248fc9SDouglas Gilbert u8 rem; 7480c2248fc9SDouglas Gilbert int j; 7481c2248fc9SDouglas Gilbert 7482c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7483c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7484c2248fc9SDouglas Gilbert if (rem) { 7485c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7486c2248fc9SDouglas Gilbert if (0x80 & rem) 7487c2248fc9SDouglas Gilbert break; 7488c2248fc9SDouglas Gilbert } 7489c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7490c2248fc9SDouglas Gilbert goto check_cond; 7491c2248fc9SDouglas Gilbert } 7492c2248fc9SDouglas Gilbert } 7493c2248fc9SDouglas Gilbert } 7494f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7495b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7496b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7497f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7498c2248fc9SDouglas Gilbert if (errsts) 7499c2248fc9SDouglas Gilbert goto check_cond; 7500c2248fc9SDouglas Gilbert } 7501fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7502fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7503fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7504fc13638aSDouglas Gilbert if (errsts) 7505c2248fc9SDouglas Gilbert goto fini; 7506c2248fc9SDouglas Gilbert } 7507773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7508c2248fc9SDouglas Gilbert goto fini; 7509f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7510c4837394SDouglas Gilbert if (fake_timeout(scp)) 7511c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7512c2248fc9SDouglas Gilbert } 7513f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7514f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7515f66b8517SMartin Wilck else 7516f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7517c2248fc9SDouglas Gilbert 7518c2248fc9SDouglas Gilbert fini: 751967da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7520f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 752175aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 752275aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 752380c49563SDouglas Gilbert /* 752475aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 752575aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 752675aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 752775aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 752880c49563SDouglas Gilbert */ 752980c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 75304f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 753180c49563SDouglas Gilbert 75324f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7533f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 753480c49563SDouglas Gilbert } else 7535f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 753610bde980SDouglas Gilbert sdebug_ndelay); 7537c2248fc9SDouglas Gilbert check_cond: 7538f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7539f46eb0e9SDouglas Gilbert err_out: 7540f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7541c2248fc9SDouglas Gilbert } 7542c2248fc9SDouglas Gilbert 75439e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7544c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7545c8ed555aSAl Viro .write_info = scsi_debug_write_info, 75469e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 75479e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 75489e603ca0SFUJITA Tomonori .info = scsi_debug_info, 75499e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 75509e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 75519e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 75529e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7553185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7554cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7555c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7556c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 75579e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 75589e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7559cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7560cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 75619e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7562c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 75639e603ca0SFUJITA Tomonori .this_id = 7, 756465e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7565cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 75666bb5e6e7SAkinobu Mita .max_sectors = -1U, 756750c2e910SChristoph Hellwig .max_segment_size = -1U, 75689e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7569c40ecc12SChristoph Hellwig .track_queue_depth = 1, 75709e603ca0SFUJITA Tomonori }; 75719e603ca0SFUJITA Tomonori 75721da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 75731da177e4SLinus Torvalds { 75741da177e4SLinus Torvalds int error = 0; 75751da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 75761da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7577f46eb0e9SDouglas Gilbert int hprot; 75781da177e4SLinus Torvalds 75791da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 75801da177e4SLinus Torvalds 7581773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7582fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 75832a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 75844af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 75854af14d11SChristoph Hellwig 75861da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 75871da177e4SLinus Torvalds if (NULL == hpnt) { 7588c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 75891da177e4SLinus Torvalds error = -ENODEV; 75901da177e4SLinus Torvalds return error; 75911da177e4SLinus Torvalds } 7592c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 75939b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7594c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7595c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7596c4837394SDouglas Gilbert } 7597c10fa55fSJohn Garry /* 7598c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7599f7c4cdc7SJohn Garry * following should give the same answer for each host. 7600c10fa55fSJohn Garry */ 7601c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7602f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7603f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 76041da177e4SLinus Torvalds 7605c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7606c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7607c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7608c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7609c4b57d89SKashyap Desai poll_queues = 0; 7610c4b57d89SKashyap Desai } 7611c4b57d89SKashyap Desai 7612c4b57d89SKashyap Desai /* 7613c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7614c4b57d89SKashyap Desai * left over for non-polled I/O. 7615c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7616c4b57d89SKashyap Desai */ 7617c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7618fc09acb7SDouglas Gilbert if (submit_queues < 3) 7619c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7620fc09acb7SDouglas Gilbert else 7621fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7622fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7623c4b57d89SKashyap Desai poll_queues = 1; 7624c4b57d89SKashyap Desai } 7625c4b57d89SKashyap Desai if (poll_queues) 7626c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7627c4b57d89SKashyap Desai 76281da177e4SLinus Torvalds sdbg_host->shost = hpnt; 76291da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7630773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7631773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 76321da177e4SLinus Torvalds else 7633773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7634773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7635f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 76361da177e4SLinus Torvalds 7637f46eb0e9SDouglas Gilbert hprot = 0; 7638c6a44287SMartin K. Petersen 7639773642d9SDouglas Gilbert switch (sdebug_dif) { 7640c6a44287SMartin K. Petersen 76418475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7642f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7643773642d9SDouglas Gilbert if (sdebug_dix) 7644f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7645c6a44287SMartin K. Petersen break; 7646c6a44287SMartin K. Petersen 76478475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7648f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7649773642d9SDouglas Gilbert if (sdebug_dix) 7650f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7651c6a44287SMartin K. Petersen break; 7652c6a44287SMartin K. Petersen 76538475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7654f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7655773642d9SDouglas Gilbert if (sdebug_dix) 7656f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7657c6a44287SMartin K. Petersen break; 7658c6a44287SMartin K. Petersen 7659c6a44287SMartin K. Petersen default: 7660773642d9SDouglas Gilbert if (sdebug_dix) 7661f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7662c6a44287SMartin K. Petersen break; 7663c6a44287SMartin K. Petersen } 7664c6a44287SMartin K. Petersen 7665f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7666c6a44287SMartin K. Petersen 7667f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7668c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7669f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7670f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7671f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7672f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7673f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7674f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7675f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7676c6a44287SMartin K. Petersen 7677773642d9SDouglas Gilbert if (sdebug_guard == 1) 7678c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7679c6a44287SMartin K. Petersen else 7680c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7681c6a44287SMartin K. Petersen 7682773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7683773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7684c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7685c4837394SDouglas Gilbert sdebug_statistics = true; 76861da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 76871da177e4SLinus Torvalds if (error) { 7688c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 76891da177e4SLinus Torvalds error = -ENODEV; 76901da177e4SLinus Torvalds scsi_host_put(hpnt); 769187c715dcSDouglas Gilbert } else { 76921da177e4SLinus Torvalds scsi_scan_host(hpnt); 769387c715dcSDouglas Gilbert } 76941da177e4SLinus Torvalds 76951da177e4SLinus Torvalds return error; 76961da177e4SLinus Torvalds } 76971da177e4SLinus Torvalds 76981da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev) 76991da177e4SLinus Torvalds { 77001da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 77018b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 77021da177e4SLinus Torvalds 77031da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 77041da177e4SLinus Torvalds 77051da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 77061da177e4SLinus Torvalds 77078b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 77088b40228fSFUJITA Tomonori dev_list) { 77091da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7710f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 77111da177e4SLinus Torvalds kfree(sdbg_devinfo); 77121da177e4SLinus Torvalds } 77131da177e4SLinus Torvalds 77141da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 77151da177e4SLinus Torvalds return 0; 77161da177e4SLinus Torvalds } 77171da177e4SLinus Torvalds 77188dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 77198dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 77201da177e4SLinus Torvalds { 77218dea0d02SFUJITA Tomonori return 1; 77228dea0d02SFUJITA Tomonori } 77231da177e4SLinus Torvalds 77248dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 77258dea0d02SFUJITA Tomonori .name = "pseudo", 77268dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 77278dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 77288dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 772982069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 77308dea0d02SFUJITA Tomonori }; 7731