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 * 10500d0d24SDouglas Gilbert * Copyright (C) 2001 - 2021 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/fs.h> 271da177e4SLinus Torvalds #include <linux/init.h> 281da177e4SLinus Torvalds #include <linux/proc_fs.h> 291da177e4SLinus Torvalds #include <linux/vmalloc.h> 301da177e4SLinus Torvalds #include <linux/moduleparam.h> 31852e034dSJens Axboe #include <linux/scatterlist.h> 321da177e4SLinus Torvalds #include <linux/blkdev.h> 33c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 34cbf67842SDouglas Gilbert #include <linux/spinlock.h> 352aad3cd8SDouglas Gilbert #include <linux/mutex.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 */ 63500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191" /* format to fit INQUIRY revision field */ 64500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520"; 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 86500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1 87cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 88cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8922017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 901da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 916f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 92c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 93c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9422017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 96acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 97481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc 98f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4 99f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5 100f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6 101f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7 102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe 1031da177e4SLinus Torvalds 1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 1066f3cbf55SDouglas Gilbert 1071da177e4SLinus Torvalds /* Default values for driver parameters */ 1081da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1091da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1101da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1121da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1131da177e4SLinus Torvalds */ 1145b94e232SMartin K. Petersen #define DEF_ATO 1 1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10 116c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT 0 1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB 128 1205b94e232SMartin K. Petersen #define DEF_DIF 0 1215b94e232SMartin K. Petersen #define DEF_DIX 0 12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false 1235b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1241da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1255b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1265b94e232SMartin K. Petersen #define DEF_GUARD 0 127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1285b94e232SMartin K. Petersen #define DEF_LBPU 0 1295b94e232SMartin K. Petersen #define DEF_LBPWS 0 1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0 131be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 133cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1351da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1361da177e4SLinus Torvalds #define DEF_OPTS 0 13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 140b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false 142d986788bSMartin Pitt #define DEF_REMOVABLE false 143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 152c2248fc9SDouglas Gilbert #define DEF_STRICT 0 153c4837394SDouglas Gilbert #define DEF_STATISTICS false 154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0 15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1581da177e4SLinus Torvalds 159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */ 160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB 128 161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES 8 162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES 1 163f0d1cf93SDouglas Gilbert 164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 165b01f6f83SDouglas Gilbert 166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 1777d5a129bSDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 /* ignore */ 178773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 179773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 180773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 181773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1827ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 1837382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT 0x10000 184773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 185773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 186773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 187773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 188773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1897ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1907382f9d8SDouglas Gilbert SDEBUG_OPT_HOST_BUSY | \ 1917382f9d8SDouglas Gilbert SDEBUG_OPT_CMD_ABORT) 1923a90a63dSDouglas Gilbert #define SDEBUG_OPT_RECOV_DIF_DIX (SDEBUG_OPT_RECOVERED_ERR | \ 1933a90a63dSDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR) 1941da177e4SLinus Torvalds 195cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 196cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 197cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 198cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 199cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 200500d0d24SDouglas Gilbert #define SDEBUG_UA_POOCCUR 1 /* Power on occurred */ 201500d0d24SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 2 202500d0d24SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 3 203500d0d24SDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 4 204500d0d24SDouglas Gilbert #define SDEBUG_UA_LUNS_CHANGED 5 205500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED 6 /* simulate firmware change */ 206500d0d24SDouglas Gilbert #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 7 207500d0d24SDouglas Gilbert #define SDEBUG_NUM_UAS 8 208cbf67842SDouglas Gilbert 209773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2101da177e4SLinus Torvalds * sector on read commands: */ 2111da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 21232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2131da177e4SLinus Torvalds 214c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 215c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 216c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 217c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 218c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 219c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 220c4837394SDouglas Gilbert */ 221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 222c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 223fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN SDEBUG_CANQUEUE 224cbf67842SDouglas Gilbert 225b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */ 226b6ff8ca7SDouglas Gilbert #define F_D_IN 1 /* Data-in command (e.g. READ) */ 227b6ff8ca7SDouglas Gilbert #define F_D_OUT 2 /* Data-out command (e.g. WRITE) */ 228fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 229fd32119bSDouglas Gilbert #define F_D_UNKN 8 230b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK 0x10 /* allowed with REPORT LUNS W-LUN */ 231b6ff8ca7SDouglas Gilbert #define F_SKIP_UA 0x20 /* bypass UAs (e.g. INQUIRY command) */ 232b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR 0x40 /* for commands like INQUIRY */ 233b6ff8ca7SDouglas Gilbert #define F_SA_LOW 0x80 /* SA is in cdb byte 1, bits 4 to 0 */ 234b6ff8ca7SDouglas Gilbert #define F_SA_HIGH 0x100 /* SA is in cdb bytes 8 and 9 */ 235b6ff8ca7SDouglas Gilbert #define F_INV_OP 0x200 /* invalid opcode (not supported) */ 236b6ff8ca7SDouglas Gilbert #define F_FAKE_RW 0x400 /* bypass resp_*() when fake_rw set */ 237b6ff8ca7SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access, reacts to SSU state */ 238b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY 0x1000 /* SSU command delay (long-ish) */ 239b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY 0x2000 /* SYNCHRONIZE CACHE delay */ 240fd32119bSDouglas Gilbert 241b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */ 242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 246fd32119bSDouglas Gilbert 247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 248fd32119bSDouglas Gilbert 249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 250fd32119bSDouglas Gilbert 25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 25287c715dcSDouglas Gilbert 25364e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */ 25464e14eceSDamien Le Moal enum sdebug_z_type { 25564e14eceSDamien Le Moal ZBC_ZONE_TYPE_CNV = 0x1, 25664e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWR = 0x2, 25764e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWP = 0x3, 25864e14eceSDamien Le Moal }; 25964e14eceSDamien Le Moal 260f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 261f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 262f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 263f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 264f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 265f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 266f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 267f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 268f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 269f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 270f0d1cf93SDouglas Gilbert }; 271f0d1cf93SDouglas Gilbert 272f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 27364e14eceSDamien Le Moal enum sdebug_z_type z_type; 274f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 27564e14eceSDamien Le Moal bool z_non_seq_resource; 276f0d1cf93SDouglas Gilbert unsigned int z_size; 277f0d1cf93SDouglas Gilbert sector_t z_start; 278f0d1cf93SDouglas Gilbert sector_t z_wp; 279f0d1cf93SDouglas Gilbert }; 280fd32119bSDouglas Gilbert 281fd32119bSDouglas Gilbert struct sdebug_dev_info { 282fd32119bSDouglas Gilbert struct list_head dev_list; 283fd32119bSDouglas Gilbert unsigned int channel; 284fd32119bSDouglas Gilbert unsigned int target; 285fd32119bSDouglas Gilbert u64 lun; 286bf476433SChristoph Hellwig uuid_t lu_name; 287fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 288fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 289fd32119bSDouglas Gilbert atomic_t num_in_q; 290fc13638aSDouglas Gilbert atomic_t stopped; /* 1: by SSU, 2: device start */ 291fd32119bSDouglas Gilbert bool used; 292f0d1cf93SDouglas Gilbert 293f0d1cf93SDouglas Gilbert /* For ZBC devices */ 29464e14eceSDamien Le Moal enum blk_zoned_model zmodel; 295f0d1cf93SDouglas Gilbert unsigned int zsize; 296f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 297f0d1cf93SDouglas Gilbert unsigned int nr_zones; 298aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 299f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 300f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 301f0d1cf93SDouglas Gilbert unsigned int nr_closed; 302f0d1cf93SDouglas Gilbert unsigned int max_open; 303fc13638aSDouglas Gilbert ktime_t create_ts; /* time since bootup that this device was created */ 304f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 305fd32119bSDouglas Gilbert }; 306fd32119bSDouglas Gilbert 307fd32119bSDouglas Gilbert struct sdebug_host_info { 308fd32119bSDouglas Gilbert struct list_head host_list; 30987c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 310fd32119bSDouglas Gilbert struct Scsi_Host *shost; 311fd32119bSDouglas Gilbert struct device dev; 312fd32119bSDouglas Gilbert struct list_head dev_info_list; 313fd32119bSDouglas Gilbert }; 314fd32119bSDouglas Gilbert 31587c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 31687c715dcSDouglas Gilbert struct sdeb_store_info { 31787c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 31887c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 31987c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 32087c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 32187c715dcSDouglas Gilbert }; 32287c715dcSDouglas Gilbert 323fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 324fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 325fd32119bSDouglas Gilbert 32610bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 3274a0c6f43SDouglas Gilbert SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3}; 32810bde980SDouglas Gilbert 329fd32119bSDouglas Gilbert struct sdebug_defer { 330fd32119bSDouglas Gilbert struct hrtimer hrt; 331fd32119bSDouglas Gilbert struct execute_work ew; 3324a0c6f43SDouglas Gilbert ktime_t cmpl_ts;/* time since boot to complete this cmd */ 333c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 334c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 335c10fa55fSJohn Garry int hc_idx; /* hostwide tag index */ 336c4837394SDouglas Gilbert int issuing_cpu; 33710bde980SDouglas Gilbert bool init_hrt; 33810bde980SDouglas Gilbert bool init_wq; 3394a0c6f43SDouglas Gilbert bool init_poll; 3407382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 34110bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 342fd32119bSDouglas Gilbert }; 343fd32119bSDouglas Gilbert 344fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 345c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 346c4837394SDouglas Gilbert * instance indicates this slot is in use. 347c4837394SDouglas Gilbert */ 348fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 349fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 350fd32119bSDouglas Gilbert }; 351fd32119bSDouglas Gilbert 352c4837394SDouglas Gilbert struct sdebug_queue { 353c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 354c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 355c4837394SDouglas Gilbert spinlock_t qc_lock; 356c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 357fd32119bSDouglas Gilbert }; 358fd32119bSDouglas Gilbert 359c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 360c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 361c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 362c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 3633a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending; 3644a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */ 365c4837394SDouglas Gilbert 366fd32119bSDouglas Gilbert struct opcode_info_t { 367b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 368b01f6f83SDouglas Gilbert /* for terminating element */ 369fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 370fd32119bSDouglas Gilbert u16 sa; /* service action */ 371fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 372fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 373fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3749a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3759a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 376fd32119bSDouglas Gilbert }; 377fd32119bSDouglas Gilbert 378fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 379c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 380c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 381c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 382c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 383c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 384c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 385c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 386c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 387c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 388c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 389c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 390c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 391c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 39246f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 39346f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 394c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 395c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 396c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 397481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 398c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 399c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 400c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 401c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 402c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 403c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 404c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 405c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 406c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 407c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 408c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 409ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 410f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 411f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 412f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 413c2248fc9SDouglas Gilbert }; 414c2248fc9SDouglas Gilbert 415c4837394SDouglas Gilbert 416c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 417c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 418c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 419c2248fc9SDouglas Gilbert 0, 0, 0, 0, 420c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 421c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 422c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 423c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 424c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 425c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 426c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 427c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 428ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 429c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 430c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 431c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 432c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 433c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 434c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 435c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 436fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 437c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 438c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 439c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 440c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 441c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 442c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 443c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 444f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 445f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 44646f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 447c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 448c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 449c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 45046f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 45146f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 452c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 453c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 454c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 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 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 458c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 459c2248fc9SDouglas Gilbert }; 460c2248fc9SDouglas Gilbert 46180c49563SDouglas Gilbert /* 46280c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 46380c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 46480c49563SDouglas Gilbert * command completion, they can mask their return value with 46580c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 46680c49563SDouglas Gilbert */ 46780c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 46880c49563SDouglas Gilbert 469c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 470c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 471c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 472c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 473c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 474c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 475c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 476c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 477c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 478481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 479c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 482c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 483c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 48438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 48538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 486c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 487c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 488c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 48938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 490acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 49180c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 492ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 493f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 494f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 495f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 496f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 497f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 498c2248fc9SDouglas Gilbert 49987c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 50087c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 50187c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 50287c715dcSDouglas Gilbert static int sdebug_add_store(void); 50387c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 50487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 50587c715dcSDouglas Gilbert 50646f64e70SDouglas Gilbert /* 50746f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 50846f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 50946f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 51046f64e70SDouglas Gilbert */ 51146f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 512c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 513c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 514c2248fc9SDouglas Gilbert }; 515c2248fc9SDouglas Gilbert 51646f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 517c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 518c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 519c2248fc9SDouglas Gilbert }; 520c2248fc9SDouglas Gilbert 52146f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 52246f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 523b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 524c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 52546f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 526c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 52746f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 528b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 529c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 530c2248fc9SDouglas Gilbert }; 531c2248fc9SDouglas Gilbert 53246f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 53346f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 53446f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 53546f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 53646f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 53746f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 53846f64e70SDouglas Gilbert 0, 0, 0} }, 53946f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 54046f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54146f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 542c2248fc9SDouglas Gilbert }; 543c2248fc9SDouglas Gilbert 544c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 545c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 546c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 547c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 548c3e2fe92SDouglas Gilbert }; 549c3e2fe92SDouglas Gilbert 55046f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 551c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 552c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55346f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 554c2248fc9SDouglas Gilbert }; 555c2248fc9SDouglas Gilbert 55646f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 55746f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 558b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 559c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 560481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 561481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 562481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 563c2248fc9SDouglas Gilbert }; 564c2248fc9SDouglas Gilbert 56546f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 56638d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 567c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 56846f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 56938d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 570c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 57146f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 572c2248fc9SDouglas Gilbert }; 573c2248fc9SDouglas Gilbert 57446f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 57546f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 576c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57746f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 578c2248fc9SDouglas Gilbert }; 579c2248fc9SDouglas Gilbert 58046f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 581c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 582c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 583c2248fc9SDouglas Gilbert }; 584c2248fc9SDouglas Gilbert 58546f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 586c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 587c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 588c2248fc9SDouglas Gilbert }; 589c2248fc9SDouglas Gilbert 59080c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5914f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 59280c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59380c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 59480c49563SDouglas Gilbert }; 59580c49563SDouglas Gilbert 596ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 597b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 598ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 599ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 600ed9f3e25SDouglas Gilbert }; 601ed9f3e25SDouglas Gilbert 602f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 603b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 604f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 605f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 606b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 607f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 608f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 609b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 610f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 611f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 612f0d1cf93SDouglas Gilbert }; 613f0d1cf93SDouglas Gilbert 614f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 615b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 616f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 617f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 618f0d1cf93SDouglas Gilbert }; 619f0d1cf93SDouglas Gilbert 620c2248fc9SDouglas Gilbert 621c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 622c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 623c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 624ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 625c2248fc9SDouglas Gilbert /* 0 */ 62646f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 627c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 62846f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 629c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 630c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 631c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 63246f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 633c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 634c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 635c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 636c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63746f64e70SDouglas Gilbert /* 5 */ 63846f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 63946f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 64046f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64146f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 64246f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 64346f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64446f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 645c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 646c2248fc9SDouglas Gilbert 0, 0, 0} }, 64746f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 648c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 649c2248fc9SDouglas Gilbert 0, 0} }, 65046f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 65146f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 65246f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 653c2248fc9SDouglas Gilbert /* 10 */ 65446f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 65546f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 65646f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65780c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6584f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 659c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 66046f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 66146f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 66246f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66346f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 664481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 665481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 666481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 66746f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 66846f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 66946f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 67046f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 67146f64e70SDouglas Gilbert /* 15 */ 672c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 673c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 674c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 675c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 676c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 677c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 67846f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 67946f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 68046f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 68146f64e70SDouglas Gilbert 0xff, 0xff} }, 68246f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 68346f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 684c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 685c2248fc9SDouglas Gilbert 0} }, 68646f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 68746f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 688c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 689c2248fc9SDouglas Gilbert 0} }, 690c2248fc9SDouglas Gilbert /* 20 */ 691f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 692f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 693c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 694c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 695c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 696c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 697c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 698c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 69946f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 700b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 70146f64e70SDouglas Gilbert /* 25 */ 702acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 703acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 704acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 70546f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 70646f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 70746f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 70846f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7094f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 71080c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 711b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 71280c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 71346f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 714c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 715b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 716b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 717ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 718ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 719ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 720c2248fc9SDouglas Gilbert 721ed9f3e25SDouglas Gilbert /* 30 */ 722b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 723f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 724f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 725f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 726b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 727f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 728f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 729f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 730f0d1cf93SDouglas Gilbert /* sentinel */ 731c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 732c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 733c2248fc9SDouglas Gilbert }; 734c2248fc9SDouglas Gilbert 7352aad3cd8SDouglas Gilbert static atomic_t sdebug_num_hosts; 7362aad3cd8SDouglas Gilbert static DEFINE_MUTEX(add_host_mutex); 7372aad3cd8SDouglas Gilbert 73887c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 739773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7409b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 741c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7429267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 743773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 744773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 745773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 746773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 747773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 748773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 749c10fa55fSJohn Garry static int sdebug_host_max_queue; /* per host */ 750773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 751773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 752c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 753d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 754d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 755cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 756c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 757773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 758773642d9SDouglas Gilbert static int sdebug_no_uld; 759773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 760773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 761773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 762773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 763773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 76486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 765b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 766773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 767773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 768fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY; 769773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 770773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 771773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 772773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 773773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 774773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 776773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 778773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 779773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 78009ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7810c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 78287c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 783773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 7842aad3cd8SDouglas Gilbert static bool sdebug_deflect_incoming; 785773642d9SDouglas Gilbert static bool sdebug_clustering; 786773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 787773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 788817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 7897109f370SDouglas Gilbert static bool sdebug_no_rwlock; 790773642d9SDouglas Gilbert static bool sdebug_verbose; 791f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7924f2c8bf6SDouglas Gilbert static bool write_since_sync; 793c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7949447b6ceSMartin K. Petersen static bool sdebug_wp; 7959267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 7969267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 7979267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 7981da177e4SLinus Torvalds 799ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0, 800ad0c7775SDouglas Gilbert SAM_LUN_AM_FLAT = 0x1, 801ad0c7775SDouglas Gilbert SAM_LUN_AM_LOGICAL_UNIT = 0x2, 802ad0c7775SDouglas Gilbert SAM_LUN_AM_EXTENDED = 0x3}; 803ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 804ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL; 805ad0c7775SDouglas Gilbert 806c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8071da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8081da177e4SLinus Torvalds 8091da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8101da177e4SLinus Torvalds may still need them */ 8111da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8121da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8131da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8161da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8171da177e4SLinus Torvalds 81887c715dcSDouglas Gilbert static struct xarray per_store_arr; 81987c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 82087c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 82187c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 82287c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8231da177e4SLinus Torvalds 82444d92694SMartin K. Petersen static unsigned long map_size; 825cbf67842SDouglas Gilbert static int num_aborts; 826cbf67842SDouglas Gilbert static int num_dev_resets; 827cbf67842SDouglas Gilbert static int num_target_resets; 828cbf67842SDouglas Gilbert static int num_bus_resets; 829cbf67842SDouglas Gilbert static int num_host_resets; 830c6a44287SMartin K. Petersen static int dix_writes; 831c6a44287SMartin K. Petersen static int dix_reads; 832c6a44287SMartin K. Petersen static int dif_errors; 8331da177e4SLinus Torvalds 834f0d1cf93SDouglas Gilbert /* ZBC global data */ 83564e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 83698e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 837380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 838aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 839f0d1cf93SDouglas Gilbert 840c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 841c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/ 842c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 843fd32119bSDouglas Gilbert 8441da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 84587c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 84687c715dcSDouglas Gilbert 84787c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8481da177e4SLinus Torvalds 849cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 850cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8551da177e4SLinus Torvalds .name = sdebug_proc_name, 8561da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8571da177e4SLinus Torvalds }; 8581da177e4SLinus Torvalds 8591da177e4SLinus Torvalds static const int check_condition_result = 860464a00c9SHannes Reinecke SAM_STAT_CHECK_CONDITION; 8611da177e4SLinus Torvalds 862c6a44287SMartin K. Petersen static const int illegal_condition_result = 863464a00c9SHannes Reinecke (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 864c6a44287SMartin K. Petersen 865cbf67842SDouglas Gilbert static const int device_qfull_result = 8667d5a129bSDouglas Gilbert (DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL; 867cbf67842SDouglas Gilbert 868ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 869ed9f3e25SDouglas Gilbert 870fd32119bSDouglas Gilbert 871760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 872760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 873760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 874760f3b03SDouglas Gilbert */ 875760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 876fd32119bSDouglas Gilbert { 877fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 878fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 879fd32119bSDouglas Gilbert } 880c65b1445SDouglas Gilbert 88187c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 88287c715dcSDouglas Gilbert unsigned long long lba) 88314faa944SAkinobu Mita { 88487c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 88514faa944SAkinobu Mita 88687c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 88787c715dcSDouglas Gilbert if (!sip || !sip->storep) { 88887c715dcSDouglas Gilbert WARN_ON_ONCE(true); 88987c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 89087c715dcSDouglas Gilbert } 89187c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 89214faa944SAkinobu Mita } 89314faa944SAkinobu Mita 89487c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 89587c715dcSDouglas Gilbert sector_t sector) 89614faa944SAkinobu Mita { 89749413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 89814faa944SAkinobu Mita 89987c715dcSDouglas Gilbert return sip->dif_storep + sector; 90014faa944SAkinobu Mita } 90114faa944SAkinobu Mita 9028dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 9038dea0d02SFUJITA Tomonori { 9048dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 9058dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9068dea0d02SFUJITA Tomonori 9078dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 9088dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9098dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9108dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 911773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 912773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9138dea0d02SFUJITA Tomonori else 914773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 915773642d9SDouglas Gilbert /* sdebug_max_luns; */ 916f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9178dea0d02SFUJITA Tomonori } 9188dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9198dea0d02SFUJITA Tomonori } 9208dea0d02SFUJITA Tomonori 92122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 92222017ed2SDouglas Gilbert 92322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 924fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 925fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 92622017ed2SDouglas Gilbert int in_byte, int in_bit) 92722017ed2SDouglas Gilbert { 92822017ed2SDouglas Gilbert unsigned char *sbuff; 92922017ed2SDouglas Gilbert u8 sks[4]; 93022017ed2SDouglas Gilbert int sl, asc; 93122017ed2SDouglas Gilbert 93222017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 93322017ed2SDouglas Gilbert if (!sbuff) { 93422017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 93522017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 93622017ed2SDouglas Gilbert return; 93722017ed2SDouglas Gilbert } 93822017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 93922017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 940f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0); 94122017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 94222017ed2SDouglas Gilbert sks[0] = 0x80; 94322017ed2SDouglas Gilbert if (c_d) 94422017ed2SDouglas Gilbert sks[0] |= 0x40; 94522017ed2SDouglas Gilbert if (in_bit >= 0) { 94622017ed2SDouglas Gilbert sks[0] |= 0x8; 94722017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 94822017ed2SDouglas Gilbert } 94922017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 950773642d9SDouglas Gilbert if (sdebug_dsense) { 95122017ed2SDouglas Gilbert sl = sbuff[7] + 8; 95222017ed2SDouglas Gilbert sbuff[7] = sl; 95322017ed2SDouglas Gilbert sbuff[sl] = 0x2; 95422017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 95522017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 95622017ed2SDouglas Gilbert } else 95722017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 958773642d9SDouglas Gilbert if (sdebug_verbose) 95922017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 96022017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 96122017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 96222017ed2SDouglas Gilbert } 96322017ed2SDouglas Gilbert 964cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9658dea0d02SFUJITA Tomonori { 966f2b1e9c6SHannes Reinecke if (!scp->sense_buffer) { 967cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 968cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 969cbf67842SDouglas Gilbert return; 970cbf67842SDouglas Gilbert } 971f2b1e9c6SHannes Reinecke memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 9728dea0d02SFUJITA Tomonori 973f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, key, asc, asq); 9748dea0d02SFUJITA Tomonori 975773642d9SDouglas Gilbert if (sdebug_verbose) 976cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 977cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 978cbf67842SDouglas Gilbert my_name, key, asc, asq); 9798dea0d02SFUJITA Tomonori } 9801da177e4SLinus Torvalds 981fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 98222017ed2SDouglas Gilbert { 98322017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 98422017ed2SDouglas Gilbert } 98522017ed2SDouglas Gilbert 9866f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9876f4e626fSNathan Chancellor void __user *arg) 9881da177e4SLinus Torvalds { 989773642d9SDouglas Gilbert if (sdebug_verbose) { 990cbf67842SDouglas Gilbert if (0x1261 == cmd) 991cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 992cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 993cbf67842SDouglas Gilbert else if (0x5331 == cmd) 994cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 995cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 996cbf67842SDouglas Gilbert __func__); 997cbf67842SDouglas Gilbert else 998cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 999cbf67842SDouglas Gilbert __func__, cmd); 10001da177e4SLinus Torvalds } 10011da177e4SLinus Torvalds return -EINVAL; 10021da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 10031da177e4SLinus Torvalds } 10041da177e4SLinus Torvalds 10059b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10069b760fd8SDouglas Gilbert { 10079b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10089b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10099b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10109b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10119b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10129b760fd8SDouglas Gilbert break; 10139b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10149b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10159b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10169b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10179b760fd8SDouglas Gilbert break; 10189b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10199b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10209b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10219b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10229b760fd8SDouglas Gilbert break; 10239b760fd8SDouglas Gilbert case 16: 10249b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10259b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10269b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10279b760fd8SDouglas Gilbert break; 10289b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10299b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10309b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10319b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10329b760fd8SDouglas Gilbert break; 10339b760fd8SDouglas Gilbert default: 10349b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10359b760fd8SDouglas Gilbert sdebug_cdb_len); 10369b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10379b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10389b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10399b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10409b760fd8SDouglas Gilbert break; 10419b760fd8SDouglas Gilbert } 10429b760fd8SDouglas Gilbert } 10439b760fd8SDouglas Gilbert 10449b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10459b760fd8SDouglas Gilbert { 10469b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10479b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10489b760fd8SDouglas Gilbert struct scsi_device *sdev; 10499b760fd8SDouglas Gilbert 10509b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10519b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10529b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10539b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10549b760fd8SDouglas Gilbert config_cdb_len(sdev); 10559b760fd8SDouglas Gilbert } 10569b760fd8SDouglas Gilbert } 10579b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10589b760fd8SDouglas Gilbert } 10599b760fd8SDouglas Gilbert 106019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 106119c8ead7SEwan D. Milne { 106219c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 106319c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 106419c8ead7SEwan D. Milne 106519c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 106619c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 106719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 106819c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 106919c8ead7SEwan D. Milne (devip->target == dp->target)) 107019c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 107119c8ead7SEwan D. Milne } 107219c8ead7SEwan D. Milne } 107319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 107419c8ead7SEwan D. Milne } 107519c8ead7SEwan D. Milne 1076f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10771da177e4SLinus Torvalds { 1078cbf67842SDouglas Gilbert int k; 1079cbf67842SDouglas Gilbert 1080cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1081cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1082cbf67842SDouglas Gilbert const char *cp = NULL; 1083cbf67842SDouglas Gilbert 1084cbf67842SDouglas Gilbert switch (k) { 1085cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1086f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1087f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1088773642d9SDouglas Gilbert if (sdebug_verbose) 1089cbf67842SDouglas Gilbert cp = "power on reset"; 1090cbf67842SDouglas Gilbert break; 1091500d0d24SDouglas Gilbert case SDEBUG_UA_POOCCUR: 1092500d0d24SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1093500d0d24SDouglas Gilbert POWER_ON_OCCURRED_ASCQ); 1094500d0d24SDouglas Gilbert if (sdebug_verbose) 1095500d0d24SDouglas Gilbert cp = "power on occurred"; 1096500d0d24SDouglas Gilbert break; 1097cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1098f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1099f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1100773642d9SDouglas Gilbert if (sdebug_verbose) 1101cbf67842SDouglas Gilbert cp = "bus reset"; 1102cbf67842SDouglas Gilbert break; 1103cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1104f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1105f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1106773642d9SDouglas Gilbert if (sdebug_verbose) 1107cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1108cbf67842SDouglas Gilbert break; 11090d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1110f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1111f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1112773642d9SDouglas Gilbert if (sdebug_verbose) 11130d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1114f49accf1SEwan D. Milne break; 1115acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1116f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1117b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1118b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1119773642d9SDouglas Gilbert if (sdebug_verbose) 1120acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1121acafd0b9SEwan D. Milne break; 1122acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1123f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1124acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1125acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1126773642d9SDouglas Gilbert if (sdebug_verbose) 1127acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1128acafd0b9SEwan D. Milne break; 112919c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 113019c8ead7SEwan D. Milne /* 113119c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 113219c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 113319c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 113419c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1135773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 113619c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 113719c8ead7SEwan D. Milne */ 1138773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 113919c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1140f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 114119c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 114219c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1143773642d9SDouglas Gilbert if (sdebug_verbose) 114419c8ead7SEwan D. Milne cp = "reported luns data has changed"; 114519c8ead7SEwan D. Milne break; 1146cbf67842SDouglas Gilbert default: 1147773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1148773642d9SDouglas Gilbert if (sdebug_verbose) 1149cbf67842SDouglas Gilbert cp = "unknown"; 1150cbf67842SDouglas Gilbert break; 1151cbf67842SDouglas Gilbert } 1152cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1153773642d9SDouglas Gilbert if (sdebug_verbose) 1154f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1155cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1156cbf67842SDouglas Gilbert my_name, cp); 11571da177e4SLinus Torvalds return check_condition_result; 11581da177e4SLinus Torvalds } 11591da177e4SLinus Torvalds return 0; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds 1162fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11631da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11641da177e4SLinus Torvalds int arr_len) 11651da177e4SLinus Torvalds { 116621a61829SFUJITA Tomonori int act_len; 1167ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11681da177e4SLinus Torvalds 1169072d0bb3SFUJITA Tomonori if (!sdb->length) 11701da177e4SLinus Torvalds return 0; 1171ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1172773642d9SDouglas Gilbert return DID_ERROR << 16; 117321a61829SFUJITA Tomonori 117421a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 117521a61829SFUJITA Tomonori arr, arr_len); 117642d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 117721a61829SFUJITA Tomonori 11781da177e4SLinus Torvalds return 0; 11791da177e4SLinus Torvalds } 11801da177e4SLinus Torvalds 1181fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1182fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1183fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1184fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1185fb0cc8d1SDouglas Gilbert */ 1186fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1187fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1188fb0cc8d1SDouglas Gilbert { 11899237f04eSDamien Le Moal unsigned int act_len, n; 1190ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1191fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1192fb0cc8d1SDouglas Gilbert 1193fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1194fb0cc8d1SDouglas Gilbert return 0; 1195ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1196fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1197fb0cc8d1SDouglas Gilbert 1198fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1199fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1200fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 120142d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 120242d387beSBart Van Assche scsi_get_resid(scp)); 12039237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 120436e07d7eSGeorge Kennedy scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); 1205fb0cc8d1SDouglas Gilbert return 0; 1206fb0cc8d1SDouglas Gilbert } 1207fb0cc8d1SDouglas Gilbert 1208fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1209fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1210fb0cc8d1SDouglas Gilbert */ 12111da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 121221a61829SFUJITA Tomonori int arr_len) 12131da177e4SLinus Torvalds { 121421a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12151da177e4SLinus Torvalds return 0; 1216ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12171da177e4SLinus Torvalds return -1; 121821a61829SFUJITA Tomonori 121921a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12221da177e4SLinus Torvalds 1223e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1224e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12259b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12261b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12271b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12281b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12291b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12301da177e4SLinus Torvalds 1231cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1232760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12335a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 123409ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1235bf476433SChristoph Hellwig const uuid_t *lu_name) 12361da177e4SLinus Torvalds { 1237c65b1445SDouglas Gilbert int num, port_a; 1238c65b1445SDouglas Gilbert char b[32]; 12391da177e4SLinus Torvalds 1240c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12411da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12421da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12431da177e4SLinus Torvalds arr[1] = 0x1; 12441da177e4SLinus Torvalds arr[2] = 0x0; 1245e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1246e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12471da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12481da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12491da177e4SLinus Torvalds arr[3] = num; 12501da177e4SLinus Torvalds num += 4; 1251c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 125209ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 125309ba24c1SDouglas Gilbert /* Locally assigned UUID */ 125409ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 125509ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 125609ba24c1SDouglas Gilbert arr[num++] = 0x0; 125709ba24c1SDouglas Gilbert arr[num++] = 0x12; 125809ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 125909ba24c1SDouglas Gilbert arr[num++] = 0x0; 126009ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 126109ba24c1SDouglas Gilbert num += 16; 126209ba24c1SDouglas Gilbert } else { 12631b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1264c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1265c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1266c65b1445SDouglas Gilbert arr[num++] = 0x0; 1267c65b1445SDouglas Gilbert arr[num++] = 0x8; 12681b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1269773642d9SDouglas Gilbert num += 8; 127009ba24c1SDouglas Gilbert } 1271c65b1445SDouglas Gilbert /* Target relative port number */ 1272c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1273c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1274c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1275c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1276c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1277c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1278c65b1445SDouglas Gilbert arr[num++] = 0x0; 1279c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1280c65b1445SDouglas Gilbert } 12811b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1282c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1283c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1284c65b1445SDouglas Gilbert arr[num++] = 0x0; 1285c65b1445SDouglas Gilbert arr[num++] = 0x8; 12861b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1287773642d9SDouglas Gilbert num += 8; 12881b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12895a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12905a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12915a09e398SHannes Reinecke arr[num++] = 0x0; 12925a09e398SHannes Reinecke arr[num++] = 0x4; 12935a09e398SHannes Reinecke arr[num++] = 0; 12945a09e398SHannes Reinecke arr[num++] = 0; 1295773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1296773642d9SDouglas Gilbert num += 2; 12971b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1298c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1299c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1300c65b1445SDouglas Gilbert arr[num++] = 0x0; 1301c65b1445SDouglas Gilbert arr[num++] = 0x8; 13021b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1303773642d9SDouglas Gilbert num += 8; 1304c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1305c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1306c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1307c65b1445SDouglas Gilbert arr[num++] = 0x0; 1308c65b1445SDouglas Gilbert arr[num++] = 24; 13091b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1310c65b1445SDouglas Gilbert num += 12; 1311c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1312c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1313c65b1445SDouglas Gilbert num += 8; 1314c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1315c65b1445SDouglas Gilbert num += 4; 1316c65b1445SDouglas Gilbert return num; 1317c65b1445SDouglas Gilbert } 1318c65b1445SDouglas Gilbert 1319c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1320c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1321c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1322c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1323c65b1445SDouglas Gilbert }; 1324c65b1445SDouglas Gilbert 1325cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1326760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1327c65b1445SDouglas Gilbert { 1328c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1329c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1330c65b1445SDouglas Gilbert } 1331c65b1445SDouglas Gilbert 1332cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1333760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1334c65b1445SDouglas Gilbert { 1335c65b1445SDouglas Gilbert int num = 0; 1336c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1337c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1338c65b1445SDouglas Gilbert int plen, olen; 1339c65b1445SDouglas Gilbert 1340c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1341c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1342c65b1445SDouglas Gilbert arr[num++] = 0x0; 1343c65b1445SDouglas Gilbert olen = strlen(na1); 1344c65b1445SDouglas Gilbert plen = olen + 1; 1345c65b1445SDouglas Gilbert if (plen % 4) 1346c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1347c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1348c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1349c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1350c65b1445SDouglas Gilbert num += plen; 1351c65b1445SDouglas Gilbert 1352c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1353c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1354c65b1445SDouglas Gilbert arr[num++] = 0x0; 1355c65b1445SDouglas Gilbert olen = strlen(na2); 1356c65b1445SDouglas Gilbert plen = olen + 1; 1357c65b1445SDouglas Gilbert if (plen % 4) 1358c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1359c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1360c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1361c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1362c65b1445SDouglas Gilbert num += plen; 1363c65b1445SDouglas Gilbert 1364c65b1445SDouglas Gilbert return num; 1365c65b1445SDouglas Gilbert } 1366c65b1445SDouglas Gilbert 1367c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1368760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1369c65b1445SDouglas Gilbert { 1370c65b1445SDouglas Gilbert int num = 0; 1371c65b1445SDouglas Gilbert int port_a, port_b; 1372c65b1445SDouglas Gilbert 1373c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1374c65b1445SDouglas Gilbert port_b = port_a + 1; 1375c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1376c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1377c65b1445SDouglas Gilbert arr[num++] = 0x0; 1378c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1379c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1380c65b1445SDouglas Gilbert num += 6; 1381c65b1445SDouglas Gilbert arr[num++] = 0x0; 1382c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1383c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1384c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1385c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1386c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1387c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13881b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1389773642d9SDouglas Gilbert num += 8; 1390c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1391c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1392c65b1445SDouglas Gilbert arr[num++] = 0x0; 1393c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1394c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1395c65b1445SDouglas Gilbert num += 6; 1396c65b1445SDouglas Gilbert arr[num++] = 0x0; 1397c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1398c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1399c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1400c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1401c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1402c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 14031b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1404773642d9SDouglas Gilbert num += 8; 1405c65b1445SDouglas Gilbert 1406c65b1445SDouglas Gilbert return num; 1407c65b1445SDouglas Gilbert } 1408c65b1445SDouglas Gilbert 1409c65b1445SDouglas Gilbert 1410c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1411c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1412c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1413c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1414c65b1445SDouglas Gilbert '1','2','3','4', 1415c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1416c65b1445SDouglas Gilbert 0xec,0,0,0, 1417c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1418c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1419c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1420c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1421c65b1445SDouglas Gilbert 0x53,0x41, 1422c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1423c65b1445SDouglas Gilbert 0x20,0x20, 1424c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1425c65b1445SDouglas Gilbert 0x10,0x80, 1426c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1427c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1428c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1429c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1430c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1431c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1437c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1438c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1439c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1443c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1444c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1445c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1446c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1447c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1448c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1449c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1450c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1451c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1452c65b1445SDouglas Gilbert }; 1453c65b1445SDouglas Gilbert 1454cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1455760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1456c65b1445SDouglas Gilbert { 1457c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1458c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1459c65b1445SDouglas Gilbert } 1460c65b1445SDouglas Gilbert 1461c65b1445SDouglas Gilbert 1462c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14631e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14641e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14651e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14661e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1467c65b1445SDouglas Gilbert }; 1468c65b1445SDouglas Gilbert 1469cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1470760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1471c65b1445SDouglas Gilbert { 1472ea61fca5SMartin K. Petersen unsigned int gran; 1473ea61fca5SMartin K. Petersen 1474c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1475e308b3d1SMartin K. Petersen 1476e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 147786e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 147886e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 147986e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 148086e6828aSLukas Herbolt else 1481773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1482773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1483e308b3d1SMartin K. Petersen 1484e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1485773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1486773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 148744d92694SMartin K. Petersen 1488e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1489773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1490e308b3d1SMartin K. Petersen 1491773642d9SDouglas Gilbert if (sdebug_lbpu) { 1492e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1493773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1494e308b3d1SMartin K. Petersen 1495e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1496773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 149744d92694SMartin K. Petersen } 149844d92694SMartin K. Petersen 1499e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1500773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1501773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 150244d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 150344d92694SMartin K. Petersen } 150444d92694SMartin K. Petersen 1505e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1506773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 15076014759cSMartin K. Petersen 15085b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1509773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 15105b94e232SMartin K. Petersen 15115b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 151244d92694SMartin K. Petersen 1513c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 15141da177e4SLinus Torvalds } 15151da177e4SLinus Torvalds 15161e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 151764e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1518eac6e8e4SMatthew Wilcox { 1519eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1520eac6e8e4SMatthew Wilcox arr[0] = 0; 15211e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15221e49f785SDouglas Gilbert arr[2] = 0; 15231e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 152464e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 152564e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1526eac6e8e4SMatthew Wilcox 1527eac6e8e4SMatthew Wilcox return 0x3c; 1528eac6e8e4SMatthew Wilcox } 15291da177e4SLinus Torvalds 1530760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1531760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15326014759cSMartin K. Petersen { 15333f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15346014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1535773642d9SDouglas Gilbert if (sdebug_lbpu) 15366014759cSMartin K. Petersen arr[1] = 1 << 7; 1537773642d9SDouglas Gilbert if (sdebug_lbpws) 15386014759cSMartin K. Petersen arr[1] |= 1 << 6; 1539773642d9SDouglas Gilbert if (sdebug_lbpws10) 15405b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1541760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1542760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1543760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1544760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1545760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15463f0bc3b3SMartin K. Petersen return 0x4; 15476014759cSMartin K. Petersen } 15486014759cSMartin K. Petersen 1549d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1550f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1551d36da305SDouglas Gilbert { 1552d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1553d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1554d36da305SDouglas Gilbert /* 1555d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1556d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1557f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1558f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1559d36da305SDouglas Gilbert */ 1560d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1561d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 156264e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1563f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1564f0d1cf93SDouglas Gilbert else 1565d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 1566d36da305SDouglas Gilbert return 0x3c; 1567d36da305SDouglas Gilbert } 1568d36da305SDouglas Gilbert 15691da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1570c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15711da177e4SLinus Torvalds 1572c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15731da177e4SLinus Torvalds { 15741da177e4SLinus Torvalds unsigned char pq_pdt; 15755a09e398SHannes Reinecke unsigned char *arr; 157601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 157736e07d7eSGeorge Kennedy u32 alloc_len, n; 157836e07d7eSGeorge Kennedy int ret; 1579d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15801da177e4SLinus Torvalds 1581773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15826f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15836f3cbf55SDouglas Gilbert if (! arr) 15846f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1585760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 158664e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1587d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1588b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1589c2248fc9SDouglas Gilbert if (have_wlun) 1590b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1591b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1592b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1593c65b1445SDouglas Gilbert else 1594773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 15951da177e4SLinus Torvalds arr[0] = pq_pdt; 15961da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 159722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 15985a09e398SHannes Reinecke kfree(arr); 15991da177e4SLinus Torvalds return check_condition_result; 16001da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 160136e07d7eSGeorge Kennedy int lu_id_num, port_group_id, target_dev_id; 160236e07d7eSGeorge Kennedy u32 len; 1603c65b1445SDouglas Gilbert char lu_id_str[6]; 1604c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 16051da177e4SLinus Torvalds 16065a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 16075a09e398SHannes Reinecke (devip->channel & 0x7f); 1608b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 160923183910SDouglas Gilbert host_no = 0; 1610c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1611c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1612c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1613c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1614c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16151da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1616c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1617c65b1445SDouglas Gilbert n = 4; 1618c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1619c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1620c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1621c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1622c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1623c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1624c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1625c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1626d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1627c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1628760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1629760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1630d36da305SDouglas Gilbert if (is_disk) 1631d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 163264e14eceSDamien Le Moal if (is_zbc) 1633d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1634760f3b03SDouglas Gilbert } 1635c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16361da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1637c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16381da177e4SLinus Torvalds arr[3] = len; 1639c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16401da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1641c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1642760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16435a09e398SHannes Reinecke target_dev_id, lu_id_num, 164409ba24c1SDouglas Gilbert lu_id_str, len, 164509ba24c1SDouglas Gilbert &devip->lu_name); 1646c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1647c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1648760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1649c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1650c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1651760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1652c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1653c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1654c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16558475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1656c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1657760f3b03SDouglas Gilbert else if (have_dif_prot) 1658c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1659c6a44287SMartin K. Petersen else 1660c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1661c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1662c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1663c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1664c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1665c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1666c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1667c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1668c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1669c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1670c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1671760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1672d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1673c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1674760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1675773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1676d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1677c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1678760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1679d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1680eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 168164e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1682760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16836014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1684760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1685d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1686d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1687f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16881da177e4SLinus Torvalds } else { 168922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16905a09e398SHannes Reinecke kfree(arr); 16911da177e4SLinus Torvalds return check_condition_result; 16921da177e4SLinus Torvalds } 169336e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 16945a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 169536e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 16965a09e398SHannes Reinecke kfree(arr); 16975a09e398SHannes Reinecke return ret; 16981da177e4SLinus Torvalds } 16991da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1700773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1701773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 17021da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 17031da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1704f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1705b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 170670bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1707c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 17081da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1709c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1710e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1711e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1712e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 17139b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17149b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17151da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1716760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1717760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1718c65b1445SDouglas Gilbert n = 62; 1719760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1720760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1721760f3b03SDouglas Gilbert n += 2; 1722760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1723760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1724760f3b03SDouglas Gilbert n += 2; 1725d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1726d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1727d36da305SDouglas Gilbert n += 2; 17281da177e4SLinus Torvalds } 1729760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17305a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 173136e07d7eSGeorge Kennedy min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ)); 17325a09e398SHannes Reinecke kfree(arr); 17335a09e398SHannes Reinecke return ret; 17341da177e4SLinus Torvalds } 17351da177e4SLinus Torvalds 173684905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */ 1737fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1738fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1739fd32119bSDouglas Gilbert 17401da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17411da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17421da177e4SLinus Torvalds { 174301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 174484905d34SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ 174584905d34SDouglas Gilbert bool dsense = !!(cmd[1] & 1); 174636e07d7eSGeorge Kennedy u32 alloc_len = cmd[4]; 174736e07d7eSGeorge Kennedy u32 len = 18; 174884905d34SDouglas Gilbert int stopped_state = atomic_read(&devip->stopped); 17491da177e4SLinus Torvalds 1750c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 175184905d34SDouglas Gilbert if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ 175284905d34SDouglas Gilbert if (dsense) { 175384905d34SDouglas Gilbert arr[0] = 0x72; 175484905d34SDouglas Gilbert arr[1] = NOT_READY; 175584905d34SDouglas Gilbert arr[2] = LOGICAL_UNIT_NOT_READY; 175684905d34SDouglas Gilbert arr[3] = (stopped_state == 2) ? 0x1 : 0x2; 175784905d34SDouglas Gilbert len = 8; 175884905d34SDouglas Gilbert } else { 175984905d34SDouglas Gilbert arr[0] = 0x70; 176084905d34SDouglas Gilbert arr[2] = NOT_READY; /* NO_SENSE in sense_key */ 176184905d34SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 176284905d34SDouglas Gilbert arr[12] = LOGICAL_UNIT_NOT_READY; 176384905d34SDouglas Gilbert arr[13] = (stopped_state == 2) ? 0x1 : 0x2; 176484905d34SDouglas Gilbert } 176584905d34SDouglas Gilbert } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 176684905d34SDouglas Gilbert /* Information exceptions control mode page: TEST=1, MRIE=6 */ 1767c2248fc9SDouglas Gilbert if (dsense) { 1768c65b1445SDouglas Gilbert arr[0] = 0x72; 1769c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1770c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 177184905d34SDouglas Gilbert arr[3] = 0xff; /* Failure prediction(false) */ 1772c2248fc9SDouglas Gilbert len = 8; 1773c65b1445SDouglas Gilbert } else { 1774c65b1445SDouglas Gilbert arr[0] = 0x70; 1775c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1776c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1777c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 177884905d34SDouglas Gilbert arr[13] = 0xff; /* Failure prediction(false) */ 1779c65b1445SDouglas Gilbert } 178084905d34SDouglas Gilbert } else { /* nothing to report */ 1781c2248fc9SDouglas Gilbert if (dsense) { 1782c2248fc9SDouglas Gilbert len = 8; 178384905d34SDouglas Gilbert memset(arr, 0, len); 178484905d34SDouglas Gilbert arr[0] = 0x72; 1785c2248fc9SDouglas Gilbert } else { 178684905d34SDouglas Gilbert memset(arr, 0, len); 1787c2248fc9SDouglas Gilbert arr[0] = 0x70; 1788c2248fc9SDouglas Gilbert arr[7] = 0xa; 1789c2248fc9SDouglas Gilbert } 1790c65b1445SDouglas Gilbert } 179136e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len)); 17921da177e4SLinus Torvalds } 17931da177e4SLinus Torvalds 1794fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 1795c65b1445SDouglas Gilbert { 179601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1797fc13638aSDouglas Gilbert int power_cond, want_stop, stopped_state; 17984f2c8bf6SDouglas Gilbert bool changing; 1799c65b1445SDouglas Gilbert 1800c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1801c65b1445SDouglas Gilbert if (power_cond) { 180222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1803c65b1445SDouglas Gilbert return check_condition_result; 1804c65b1445SDouglas Gilbert } 1805fc13638aSDouglas Gilbert want_stop = !(cmd[4] & 1); 1806fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 1807fc13638aSDouglas Gilbert if (stopped_state == 2) { 1808fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 1809fc13638aSDouglas Gilbert 1810fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 1811fc13638aSDouglas Gilbert u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 1812fc13638aSDouglas Gilbert 1813fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 1814fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 1815fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 1816fc13638aSDouglas Gilbert stopped_state = 0; 1817fc13638aSDouglas Gilbert } 1818fc13638aSDouglas Gilbert } 1819fc13638aSDouglas Gilbert if (stopped_state == 2) { 1820fc13638aSDouglas Gilbert if (want_stop) { 1821fc13638aSDouglas Gilbert stopped_state = 1; /* dummy up success */ 1822fc13638aSDouglas Gilbert } else { /* Disallow tur_ms_to_ready delay to be overridden */ 1823fc13638aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */); 1824fc13638aSDouglas Gilbert return check_condition_result; 1825fc13638aSDouglas Gilbert } 1826fc13638aSDouglas Gilbert } 1827fc13638aSDouglas Gilbert } 1828fc13638aSDouglas Gilbert changing = (stopped_state != want_stop); 1829fc13638aSDouglas Gilbert if (changing) 1830fc13638aSDouglas Gilbert atomic_xchg(&devip->stopped, want_stop); 1831fc13638aSDouglas Gilbert if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ 18324f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18334f2c8bf6SDouglas Gilbert else 18344f2c8bf6SDouglas Gilbert return 0; 1835c65b1445SDouglas Gilbert } 1836c65b1445SDouglas Gilbert 183728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 183828898873SFUJITA Tomonori { 1839773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1840773642d9SDouglas Gilbert 1841773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1842773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1843773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 184428898873SFUJITA Tomonori else 184528898873SFUJITA Tomonori return sdebug_store_sectors; 184628898873SFUJITA Tomonori } 184728898873SFUJITA Tomonori 18481da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18491da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18501da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18511da177e4SLinus Torvalds { 18521da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1853c65b1445SDouglas Gilbert unsigned int capac; 18541da177e4SLinus Torvalds 1855c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 185628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18571da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1858c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1859c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1860773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1861773642d9SDouglas Gilbert } else 1862773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1863773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18641da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18651da177e4SLinus Torvalds } 18661da177e4SLinus Torvalds 1867c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1868c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1869c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1870c65b1445SDouglas Gilbert { 187101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1872c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 18734e3ace00SYe Bin u32 alloc_len; 1874c65b1445SDouglas Gilbert 1875773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1876c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 187728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1878c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1879773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1880773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1881773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1882773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 188344d92694SMartin K. Petersen 1884be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18855b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1886760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1887760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1888760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1889760f3b03SDouglas Gilbert */ 1890760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1891760f3b03SDouglas Gilbert arr[14] |= 0x40; 1892be1dd78dSEric Sandeen } 189344d92694SMartin K. Petersen 1894773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1895c6a44287SMartin K. Petersen 1896760f3b03SDouglas Gilbert if (have_dif_prot) { 1897773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1898c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1899c6a44287SMartin K. Petersen } 1900c6a44287SMartin K. Petersen 1901c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 19024e3ace00SYe Bin min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1903c65b1445SDouglas Gilbert } 1904c65b1445SDouglas Gilbert 19055a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 19065a09e398SHannes Reinecke 19075a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 19085a09e398SHannes Reinecke struct sdebug_dev_info *devip) 19095a09e398SHannes Reinecke { 191001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19115a09e398SHannes Reinecke unsigned char *arr; 19125a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 19135a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 1914f347c268SYe Bin u32 alen, n, rlen; 1915f347c268SYe Bin int ret; 19165a09e398SHannes Reinecke 1917773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19186f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19196f3cbf55SDouglas Gilbert if (! arr) 19206f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19215a09e398SHannes Reinecke /* 19225a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19235a09e398SHannes Reinecke * real and a fake port with no device connected. 19245a09e398SHannes Reinecke * So we create two port groups with one port each 19255a09e398SHannes Reinecke * and set the group with port B to unavailable. 19265a09e398SHannes Reinecke */ 19275a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19285a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19295a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19305a09e398SHannes Reinecke (devip->channel & 0x7f); 19315a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19325a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19335a09e398SHannes Reinecke 19345a09e398SHannes Reinecke /* 19355a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19365a09e398SHannes Reinecke */ 19375a09e398SHannes Reinecke n = 4; 1938b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19395a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19405a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19415a09e398SHannes Reinecke } else { 19425a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1943773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19445a09e398SHannes Reinecke } 1945773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1946773642d9SDouglas Gilbert n += 2; 19475a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19485a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19495a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19505a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19515a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19525a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1953773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1954773642d9SDouglas Gilbert n += 2; 19555a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19565a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1957773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1958773642d9SDouglas Gilbert n += 2; 19595a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19605a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19615a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19625a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19635a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19645a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1965773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1966773642d9SDouglas Gilbert n += 2; 19675a09e398SHannes Reinecke 19685a09e398SHannes Reinecke rlen = n - 4; 1969773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19705a09e398SHannes Reinecke 19715a09e398SHannes Reinecke /* 19725a09e398SHannes Reinecke * Return the smallest value of either 19735a09e398SHannes Reinecke * - The allocated length 19745a09e398SHannes Reinecke * - The constructed command length 19755a09e398SHannes Reinecke * - The maximum array size 19765a09e398SHannes Reinecke */ 1977f347c268SYe Bin rlen = min(alen, n); 19785a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1979f347c268SYe Bin min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19805a09e398SHannes Reinecke kfree(arr); 19815a09e398SHannes Reinecke return ret; 19825a09e398SHannes Reinecke } 19835a09e398SHannes Reinecke 1984fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1985fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 198638d5c833SDouglas Gilbert { 198738d5c833SDouglas Gilbert bool rctd; 198838d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 198938d5c833SDouglas Gilbert u16 req_sa, u; 199038d5c833SDouglas Gilbert u32 alloc_len, a_len; 199138d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 199238d5c833SDouglas Gilbert const struct opcode_info_t *oip; 199338d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 199438d5c833SDouglas Gilbert u8 *arr; 199538d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 199638d5c833SDouglas Gilbert 199738d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 199838d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 199938d5c833SDouglas Gilbert req_opcode = cmd[3]; 200038d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 200138d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 20026d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 200338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 200438d5c833SDouglas Gilbert return check_condition_result; 200538d5c833SDouglas Gilbert } 200638d5c833SDouglas Gilbert if (alloc_len > 8192) 200738d5c833SDouglas Gilbert a_len = 8192; 200838d5c833SDouglas Gilbert else 200938d5c833SDouglas Gilbert a_len = alloc_len; 201099531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 201138d5c833SDouglas Gilbert if (NULL == arr) { 201238d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 201338d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 201438d5c833SDouglas Gilbert return check_condition_result; 201538d5c833SDouglas Gilbert } 201638d5c833SDouglas Gilbert switch (reporting_opts) { 201738d5c833SDouglas Gilbert case 0: /* all commands */ 201838d5c833SDouglas Gilbert /* count number of commands */ 201938d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 202038d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 202138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 202238d5c833SDouglas Gilbert continue; 202338d5c833SDouglas Gilbert count += (oip->num_attached + 1); 202438d5c833SDouglas Gilbert } 202538d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 202638d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 202738d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 202838d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 202938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 203038d5c833SDouglas Gilbert continue; 203138d5c833SDouglas Gilbert na = oip->num_attached; 203238d5c833SDouglas Gilbert arr[offset] = oip->opcode; 203338d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 203438d5c833SDouglas Gilbert if (rctd) 203538d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 203638d5c833SDouglas Gilbert if (FF_SA & oip->flags) 203738d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 203838d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 203938d5c833SDouglas Gilbert if (rctd) 204038d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 204138d5c833SDouglas Gilbert r_oip = oip; 204238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 204338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 204438d5c833SDouglas Gilbert continue; 204538d5c833SDouglas Gilbert offset += bump; 204638d5c833SDouglas Gilbert arr[offset] = oip->opcode; 204738d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 204838d5c833SDouglas Gilbert if (rctd) 204938d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 205038d5c833SDouglas Gilbert if (FF_SA & oip->flags) 205138d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 205238d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 205338d5c833SDouglas Gilbert arr + offset + 6); 205438d5c833SDouglas Gilbert if (rctd) 205538d5c833SDouglas Gilbert put_unaligned_be16(0xa, 205638d5c833SDouglas Gilbert arr + offset + 8); 205738d5c833SDouglas Gilbert } 205838d5c833SDouglas Gilbert oip = r_oip; 205938d5c833SDouglas Gilbert offset += bump; 206038d5c833SDouglas Gilbert } 206138d5c833SDouglas Gilbert break; 206238d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 206338d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 206438d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 206538d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 206638d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 206738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 206838d5c833SDouglas Gilbert supp = 1; 206938d5c833SDouglas Gilbert offset = 4; 207038d5c833SDouglas Gilbert } else { 207138d5c833SDouglas Gilbert if (1 == reporting_opts) { 207238d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 207338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 207438d5c833SDouglas Gilbert 2, 2); 207538d5c833SDouglas Gilbert kfree(arr); 207638d5c833SDouglas Gilbert return check_condition_result; 207738d5c833SDouglas Gilbert } 207838d5c833SDouglas Gilbert req_sa = 0; 207938d5c833SDouglas Gilbert } else if (2 == reporting_opts && 208038d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 208138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 208238d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 208338d5c833SDouglas Gilbert return check_condition_result; 208438d5c833SDouglas Gilbert } 208538d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 208638d5c833SDouglas Gilbert req_opcode == oip->opcode) 208738d5c833SDouglas Gilbert supp = 3; 208838d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 208938d5c833SDouglas Gilbert na = oip->num_attached; 209038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 209138d5c833SDouglas Gilbert ++k, ++oip) { 209238d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 209338d5c833SDouglas Gilbert break; 209438d5c833SDouglas Gilbert } 209538d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 209638d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 209738d5c833SDouglas Gilbert na = oip->num_attached; 209838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 209938d5c833SDouglas Gilbert ++k, ++oip) { 210038d5c833SDouglas Gilbert if (req_sa == oip->sa) 210138d5c833SDouglas Gilbert break; 210238d5c833SDouglas Gilbert } 210338d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 210438d5c833SDouglas Gilbert } else 210538d5c833SDouglas Gilbert supp = 3; 210638d5c833SDouglas Gilbert if (3 == supp) { 210738d5c833SDouglas Gilbert u = oip->len_mask[0]; 210838d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 210938d5c833SDouglas Gilbert arr[4] = oip->opcode; 211038d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 211138d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 211238d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 211338d5c833SDouglas Gilbert offset = 4 + u; 211438d5c833SDouglas Gilbert } else 211538d5c833SDouglas Gilbert offset = 4; 211638d5c833SDouglas Gilbert } 211738d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 211838d5c833SDouglas Gilbert if (rctd) { 211938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 212038d5c833SDouglas Gilbert offset += 12; 212138d5c833SDouglas Gilbert } 212238d5c833SDouglas Gilbert break; 212338d5c833SDouglas Gilbert default: 212438d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 212538d5c833SDouglas Gilbert kfree(arr); 212638d5c833SDouglas Gilbert return check_condition_result; 212738d5c833SDouglas Gilbert } 212838d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 212938d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 213038d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 213138d5c833SDouglas Gilbert kfree(arr); 213238d5c833SDouglas Gilbert return errsts; 213338d5c833SDouglas Gilbert } 213438d5c833SDouglas Gilbert 2135fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2136fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 213738d5c833SDouglas Gilbert { 213838d5c833SDouglas Gilbert bool repd; 213938d5c833SDouglas Gilbert u32 alloc_len, len; 214038d5c833SDouglas Gilbert u8 arr[16]; 214138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 214238d5c833SDouglas Gilbert 214338d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 214438d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 214538d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 214638d5c833SDouglas Gilbert if (alloc_len < 4) { 214738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 214838d5c833SDouglas Gilbert return check_condition_result; 214938d5c833SDouglas Gilbert } 215038d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 215138d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 215238d5c833SDouglas Gilbert if (repd) { 215338d5c833SDouglas Gilbert arr[3] = 0xc; 215438d5c833SDouglas Gilbert len = 16; 215538d5c833SDouglas Gilbert } else 215638d5c833SDouglas Gilbert len = 4; 215738d5c833SDouglas Gilbert 215838d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 215938d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 216038d5c833SDouglas Gilbert } 216138d5c833SDouglas Gilbert 21621da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21631da177e4SLinus Torvalds 21641da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21651da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21661da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21671da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21681da177e4SLinus Torvalds 21691da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21701da177e4SLinus Torvalds if (1 == pcontrol) 21711da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21721da177e4SLinus Torvalds return sizeof(err_recov_pg); 21731da177e4SLinus Torvalds } 21741da177e4SLinus Torvalds 21751da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21761da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21771da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21781da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21791da177e4SLinus Torvalds 21801da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21811da177e4SLinus Torvalds if (1 == pcontrol) 21821da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21831da177e4SLinus Torvalds return sizeof(disconnect_pg); 21841da177e4SLinus Torvalds } 21851da177e4SLinus Torvalds 21861da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21871da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21881da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21891da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21901da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21911da177e4SLinus Torvalds 21921da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2193773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2194773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2195773642d9SDouglas Gilbert if (sdebug_removable) 21961da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 21971da177e4SLinus Torvalds if (1 == pcontrol) 21981da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 21991da177e4SLinus Torvalds return sizeof(format_pg); 22001da177e4SLinus Torvalds } 22011da177e4SLinus Torvalds 2202fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2203fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2204fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2205fd32119bSDouglas Gilbert 22061da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 22071da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2208cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2209cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2210cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 22111da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 22121da177e4SLinus Torvalds 2213773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2214cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22151da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22161da177e4SLinus Torvalds if (1 == pcontrol) 2217cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2218cbf67842SDouglas Gilbert else if (2 == pcontrol) 2219cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22201da177e4SLinus Torvalds return sizeof(caching_pg); 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds 2223fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2224fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2225fd32119bSDouglas Gilbert 22261da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22271da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2228c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2229c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2230c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22311da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22321da177e4SLinus Torvalds 2233773642d9SDouglas Gilbert if (sdebug_dsense) 22341da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2235c65b1445SDouglas Gilbert else 2236c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2237c6a44287SMartin K. Petersen 2238773642d9SDouglas Gilbert if (sdebug_ato) 2239c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2240c6a44287SMartin K. Petersen 22411da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22421da177e4SLinus Torvalds if (1 == pcontrol) 2243c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2244c65b1445SDouglas Gilbert else if (2 == pcontrol) 2245c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22461da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds 2249c65b1445SDouglas Gilbert 22501da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22511da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2252c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22531da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2254c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2255c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2256c65b1445SDouglas Gilbert 22571da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22581da177e4SLinus Torvalds if (1 == pcontrol) 2259c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2260c65b1445SDouglas Gilbert else if (2 == pcontrol) 2261c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22621da177e4SLinus Torvalds return sizeof(iec_m_pg); 22631da177e4SLinus Torvalds } 22641da177e4SLinus Torvalds 2265c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2266c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2267c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2268c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2269c65b1445SDouglas Gilbert 2270c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2271c65b1445SDouglas Gilbert if (1 == pcontrol) 2272c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2273c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2274c65b1445SDouglas Gilbert } 2275c65b1445SDouglas Gilbert 2276c65b1445SDouglas Gilbert 2277c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2278c65b1445SDouglas Gilbert int target_dev_id) 2279c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2280c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2281c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2282773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2283773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2284c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2285c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2286c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2287c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2288773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2289773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2290c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2291c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2292c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2293c65b1445SDouglas Gilbert }; 2294c65b1445SDouglas Gilbert int port_a, port_b; 2295c65b1445SDouglas Gilbert 22961b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 22971b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 22981b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 22991b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2300c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2301c65b1445SDouglas Gilbert port_b = port_a + 1; 2302c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2303773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2304773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2305c65b1445SDouglas Gilbert if (1 == pcontrol) 2306c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2307c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2308c65b1445SDouglas Gilbert } 2309c65b1445SDouglas Gilbert 2310c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2311c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2312c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2313c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2314c65b1445SDouglas Gilbert }; 2315c65b1445SDouglas Gilbert 2316c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2317c65b1445SDouglas Gilbert if (1 == pcontrol) 2318c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2319c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2320c65b1445SDouglas Gilbert } 2321c65b1445SDouglas Gilbert 23221da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23231da177e4SLinus Torvalds 2324fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2325fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23261da177e4SLinus Torvalds { 232723183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23281da177e4SLinus Torvalds unsigned char dev_spec; 232936e07d7eSGeorge Kennedy u32 alloc_len, offset, len; 233036e07d7eSGeorge Kennedy int target_dev_id; 2331c2248fc9SDouglas Gilbert int target = scp->device->id; 23321da177e4SLinus Torvalds unsigned char *ap; 23331da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 233401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2335d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23361da177e4SLinus Torvalds 2337760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23381da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23391da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23401da177e4SLinus Torvalds subpcode = cmd[3]; 23411da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2342760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2343760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 234464e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2345d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 234623183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 234723183910SDouglas Gilbert else 234823183910SDouglas Gilbert bd_len = 0; 2349773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23501da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23511da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2352cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23531da177e4SLinus Torvalds return check_condition_result; 23541da177e4SLinus Torvalds } 2355c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2356c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2357d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2358d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2359b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23609447b6ceSMartin K. Petersen if (sdebug_wp) 23619447b6ceSMartin K. Petersen dev_spec |= 0x80; 23629447b6ceSMartin K. Petersen } else 236323183910SDouglas Gilbert dev_spec = 0x0; 23641da177e4SLinus Torvalds if (msense_6) { 23651da177e4SLinus Torvalds arr[2] = dev_spec; 236623183910SDouglas Gilbert arr[3] = bd_len; 23671da177e4SLinus Torvalds offset = 4; 23681da177e4SLinus Torvalds } else { 23691da177e4SLinus Torvalds arr[3] = dev_spec; 237023183910SDouglas Gilbert if (16 == bd_len) 237123183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 237223183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23731da177e4SLinus Torvalds offset = 8; 23741da177e4SLinus Torvalds } 23751da177e4SLinus Torvalds ap = arr + offset; 237628898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 237728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 237828898873SFUJITA Tomonori 237923183910SDouglas Gilbert if (8 == bd_len) { 2380773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2381773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2382773642d9SDouglas Gilbert else 2383773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2384773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 238523183910SDouglas Gilbert offset += bd_len; 238623183910SDouglas Gilbert ap = arr + offset; 238723183910SDouglas Gilbert } else if (16 == bd_len) { 2388773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2389773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 239023183910SDouglas Gilbert offset += bd_len; 239123183910SDouglas Gilbert ap = arr + offset; 239223183910SDouglas Gilbert } 23931da177e4SLinus Torvalds 2394c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2395c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 239622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 23971da177e4SLinus Torvalds return check_condition_result; 23981da177e4SLinus Torvalds } 2399760f3b03SDouglas Gilbert bad_pcode = false; 2400760f3b03SDouglas Gilbert 24011da177e4SLinus Torvalds switch (pcode) { 24021da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 24031da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24041da177e4SLinus Torvalds offset += len; 24051da177e4SLinus Torvalds break; 24061da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 24071da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 24081da177e4SLinus Torvalds offset += len; 24091da177e4SLinus Torvalds break; 24101da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2411760f3b03SDouglas Gilbert if (is_disk) { 24121da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 24131da177e4SLinus Torvalds offset += len; 2414760f3b03SDouglas Gilbert } else 2415760f3b03SDouglas Gilbert bad_pcode = true; 24161da177e4SLinus Torvalds break; 24171da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2418d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24191da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24201da177e4SLinus Torvalds offset += len; 2421760f3b03SDouglas Gilbert } else 2422760f3b03SDouglas Gilbert bad_pcode = true; 24231da177e4SLinus Torvalds break; 24241da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24251da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24261da177e4SLinus Torvalds offset += len; 24271da177e4SLinus Torvalds break; 2428c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2429c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 243022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2431c65b1445SDouglas Gilbert return check_condition_result; 2432c65b1445SDouglas Gilbert } 2433c65b1445SDouglas Gilbert len = 0; 2434c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2435c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2436c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2437c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2438c65b1445SDouglas Gilbert target_dev_id); 2439c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2440c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2441c65b1445SDouglas Gilbert offset += len; 2442c65b1445SDouglas Gilbert break; 24431da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24441da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24451da177e4SLinus Torvalds offset += len; 24461da177e4SLinus Torvalds break; 24471da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2448c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24491da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24501da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2451760f3b03SDouglas Gilbert if (is_disk) { 2452760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2453760f3b03SDouglas Gilbert target); 2454760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2455760f3b03SDouglas Gilbert target); 2456d36da305SDouglas Gilbert } else if (is_zbc) { 2457d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2458d36da305SDouglas Gilbert target); 2459760f3b03SDouglas Gilbert } 24601da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2461c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2462c65b1445SDouglas Gilbert if (0xff == subpcode) { 2463c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2464c65b1445SDouglas Gilbert target, target_dev_id); 2465c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2466c65b1445SDouglas Gilbert } 24671da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2468760f3b03SDouglas Gilbert offset += len; 2469c65b1445SDouglas Gilbert } else { 247022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2471c65b1445SDouglas Gilbert return check_condition_result; 2472c65b1445SDouglas Gilbert } 24731da177e4SLinus Torvalds break; 24741da177e4SLinus Torvalds default: 2475760f3b03SDouglas Gilbert bad_pcode = true; 2476760f3b03SDouglas Gilbert break; 2477760f3b03SDouglas Gilbert } 2478760f3b03SDouglas Gilbert if (bad_pcode) { 247922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24801da177e4SLinus Torvalds return check_condition_result; 24811da177e4SLinus Torvalds } 24821da177e4SLinus Torvalds if (msense_6) 24831da177e4SLinus Torvalds arr[0] = offset - 1; 2484773642d9SDouglas Gilbert else 2485773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 248636e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 24871da177e4SLinus Torvalds } 24881da177e4SLinus Torvalds 2489c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2490c65b1445SDouglas Gilbert 2491fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2492fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2493c65b1445SDouglas Gilbert { 2494c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2495c2248fc9SDouglas Gilbert int param_len, res, mpage; 2496c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 249701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2498c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2499c65b1445SDouglas Gilbert 2500c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2501c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2502c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2503773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2504c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 250522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2506c65b1445SDouglas Gilbert return check_condition_result; 2507c65b1445SDouglas Gilbert } 2508c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2509c65b1445SDouglas Gilbert if (-1 == res) 2510773642d9SDouglas Gilbert return DID_ERROR << 16; 2511773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2512cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2513cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2514cbf67842SDouglas Gilbert __func__, param_len, res); 2515773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2516773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 2517e0a2c28dSGeorge Kennedy off = bd_len + (mselect6 ? 4 : 8); 2518e0a2c28dSGeorge Kennedy if (md_len > 2 || off >= res) { 251922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2520c65b1445SDouglas Gilbert return check_condition_result; 2521c65b1445SDouglas Gilbert } 2522c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2523c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2524c65b1445SDouglas Gilbert if (ps) { 252522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2526c65b1445SDouglas Gilbert return check_condition_result; 2527c65b1445SDouglas Gilbert } 2528c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2529773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2530c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2531c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2532cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2533c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2534c65b1445SDouglas Gilbert return check_condition_result; 2535c65b1445SDouglas Gilbert } 2536c65b1445SDouglas Gilbert switch (mpage) { 2537cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2538cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2539cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2540cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2541cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2542cbf67842SDouglas Gilbert } 2543cbf67842SDouglas Gilbert break; 2544c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2545c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2546c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2547c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25489447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25499447b6ceSMartin K. Petersen sdebug_wp = true; 25509447b6ceSMartin K. Petersen else 25519447b6ceSMartin K. Petersen sdebug_wp = false; 2552773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2553cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2554c65b1445SDouglas Gilbert } 2555c65b1445SDouglas Gilbert break; 2556c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2557c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2558c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2559c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2560cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2561c65b1445SDouglas Gilbert } 2562c65b1445SDouglas Gilbert break; 2563c65b1445SDouglas Gilbert default: 2564c65b1445SDouglas Gilbert break; 2565c65b1445SDouglas Gilbert } 256622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2567c65b1445SDouglas Gilbert return check_condition_result; 2568cbf67842SDouglas Gilbert set_mode_changed_ua: 2569cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2570cbf67842SDouglas Gilbert return 0; 2571c65b1445SDouglas Gilbert } 2572c65b1445SDouglas Gilbert 2573c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2574c65b1445SDouglas Gilbert { 2575c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2576c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2577c65b1445SDouglas Gilbert }; 2578c65b1445SDouglas Gilbert 2579c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2580c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2581c65b1445SDouglas Gilbert } 2582c65b1445SDouglas Gilbert 2583c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2584c65b1445SDouglas Gilbert { 2585c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2586c65b1445SDouglas Gilbert }; 2587c65b1445SDouglas Gilbert 2588c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2589c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2590c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2591c65b1445SDouglas Gilbert arr[5] = 0xff; 2592c65b1445SDouglas Gilbert } 2593c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2594c65b1445SDouglas Gilbert } 2595c65b1445SDouglas Gilbert 25960790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr) 25970790797aSDouglas Gilbert { 25980790797aSDouglas Gilbert unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8, 25990790797aSDouglas Gilbert 0x0, 40, 72, 0xff, 45, 18, 0, 0, 26000790797aSDouglas Gilbert 0x1, 0x0, 0x23, 0x8, 26010790797aSDouglas Gilbert 0x0, 55, 72, 35, 55, 45, 0, 0, 26020790797aSDouglas Gilbert }; 26030790797aSDouglas Gilbert 26040790797aSDouglas Gilbert memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg)); 26050790797aSDouglas Gilbert return sizeof(env_rep_l_spg); 26060790797aSDouglas Gilbert } 26070790797aSDouglas Gilbert 2608c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2609c65b1445SDouglas Gilbert 2610c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2611c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2612c65b1445SDouglas Gilbert { 261336e07d7eSGeorge Kennedy int ppc, sp, pcode, subpcode; 261436e07d7eSGeorge Kennedy u32 alloc_len, len, n; 2615c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 261601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2617c65b1445SDouglas Gilbert 2618c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2619c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2620c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2621c65b1445SDouglas Gilbert if (ppc || sp) { 262222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2623c65b1445SDouglas Gilbert return check_condition_result; 2624c65b1445SDouglas Gilbert } 2625c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 262623183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2627773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2628c65b1445SDouglas Gilbert arr[0] = pcode; 262923183910SDouglas Gilbert if (0 == subpcode) { 2630c65b1445SDouglas Gilbert switch (pcode) { 2631c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2632c65b1445SDouglas Gilbert n = 4; 2633c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2634c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2635c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2636c65b1445SDouglas Gilbert arr[3] = n - 4; 2637c65b1445SDouglas Gilbert break; 2638c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2639c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2640c65b1445SDouglas Gilbert break; 2641c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2642c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2643c65b1445SDouglas Gilbert break; 2644c65b1445SDouglas Gilbert default: 264522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2646c65b1445SDouglas Gilbert return check_condition_result; 2647c65b1445SDouglas Gilbert } 264823183910SDouglas Gilbert } else if (0xff == subpcode) { 264923183910SDouglas Gilbert arr[0] |= 0x40; 265023183910SDouglas Gilbert arr[1] = subpcode; 265123183910SDouglas Gilbert switch (pcode) { 265223183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 265323183910SDouglas Gilbert n = 4; 265423183910SDouglas Gilbert arr[n++] = 0x0; 265523183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 265623183910SDouglas Gilbert arr[n++] = 0x0; 265723183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 265823183910SDouglas Gilbert arr[n++] = 0xd; 265923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26600790797aSDouglas Gilbert arr[n++] = 0xd; 26610790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26620790797aSDouglas Gilbert arr[n++] = 0xd; 26630790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0xd subpages */ 266423183910SDouglas Gilbert arr[n++] = 0x2f; 266523183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26660790797aSDouglas Gilbert arr[n++] = 0x2f; 26670790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0x2f subpages */ 266823183910SDouglas Gilbert arr[3] = n - 4; 266923183910SDouglas Gilbert break; 267023183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 267123183910SDouglas Gilbert n = 4; 267223183910SDouglas Gilbert arr[n++] = 0xd; 267323183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26740790797aSDouglas Gilbert arr[n++] = 0xd; 26750790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26760790797aSDouglas Gilbert arr[n++] = 0xd; 26770790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 267823183910SDouglas Gilbert arr[3] = n - 4; 267923183910SDouglas Gilbert break; 268023183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 268123183910SDouglas Gilbert n = 4; 268223183910SDouglas Gilbert arr[n++] = 0x2f; 268323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26840790797aSDouglas Gilbert arr[n++] = 0x2f; 26850790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 268623183910SDouglas Gilbert arr[3] = n - 4; 268723183910SDouglas Gilbert break; 268823183910SDouglas Gilbert default: 268922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 269023183910SDouglas Gilbert return check_condition_result; 269123183910SDouglas Gilbert } 26920790797aSDouglas Gilbert } else if (subpcode > 0) { 26930790797aSDouglas Gilbert arr[0] |= 0x40; 26940790797aSDouglas Gilbert arr[1] = subpcode; 26950790797aSDouglas Gilbert if (pcode == 0xd && subpcode == 1) 26960790797aSDouglas Gilbert arr[3] = resp_env_rep_l_spg(arr + 4); 26970790797aSDouglas Gilbert else { 26980790797aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 26990790797aSDouglas Gilbert return check_condition_result; 27000790797aSDouglas Gilbert } 270123183910SDouglas Gilbert } else { 270222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 270323183910SDouglas Gilbert return check_condition_result; 270423183910SDouglas Gilbert } 270536e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 2706c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 270736e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 2708c65b1445SDouglas Gilbert } 2709c65b1445SDouglas Gilbert 2710f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2711f0d1cf93SDouglas Gilbert { 2712f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2713f0d1cf93SDouglas Gilbert } 2714f0d1cf93SDouglas Gilbert 2715f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2716f0d1cf93SDouglas Gilbert unsigned long long lba) 2717f0d1cf93SDouglas Gilbert { 2718108e36f0SDamien Le Moal return &devip->zstate[lba >> devip->zsize_shift]; 2719f0d1cf93SDouglas Gilbert } 2720f0d1cf93SDouglas Gilbert 2721f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2722f0d1cf93SDouglas Gilbert { 272364e14eceSDamien Le Moal return zsp->z_type == ZBC_ZONE_TYPE_CNV; 2724f0d1cf93SDouglas Gilbert } 2725f0d1cf93SDouglas Gilbert 2726f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2727f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2728f0d1cf93SDouglas Gilbert { 2729f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2730f0d1cf93SDouglas Gilbert 2731f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2732f0d1cf93SDouglas Gilbert return; 2733f0d1cf93SDouglas Gilbert 2734f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2735f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2736f0d1cf93SDouglas Gilbert return; 2737f0d1cf93SDouglas Gilbert 2738f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2739f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2740f0d1cf93SDouglas Gilbert else 2741f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2742f0d1cf93SDouglas Gilbert 2743f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2744f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2745f0d1cf93SDouglas Gilbert } else { 2746f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2747f0d1cf93SDouglas Gilbert devip->nr_closed++; 2748f0d1cf93SDouglas Gilbert } 2749f0d1cf93SDouglas Gilbert } 2750f0d1cf93SDouglas Gilbert 2751f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2752f0d1cf93SDouglas Gilbert { 2753f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2754f0d1cf93SDouglas Gilbert unsigned int i; 2755f0d1cf93SDouglas Gilbert 2756f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2757f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2758f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2759f0d1cf93SDouglas Gilbert return; 2760f0d1cf93SDouglas Gilbert } 2761f0d1cf93SDouglas Gilbert } 2762f0d1cf93SDouglas Gilbert } 2763f0d1cf93SDouglas Gilbert 2764f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2765f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2766f0d1cf93SDouglas Gilbert { 2767f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2768f0d1cf93SDouglas Gilbert 2769f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2770f0d1cf93SDouglas Gilbert return; 2771f0d1cf93SDouglas Gilbert 2772f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2773f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2774f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2775f0d1cf93SDouglas Gilbert return; 2776f0d1cf93SDouglas Gilbert 2777f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2778f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2779f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2780f0d1cf93SDouglas Gilbert else if (devip->max_open && 2781f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2782f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2783f0d1cf93SDouglas Gilbert 2784f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2785f0d1cf93SDouglas Gilbert devip->nr_closed--; 2786f0d1cf93SDouglas Gilbert if (explicit) { 2787f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2788f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2789f0d1cf93SDouglas Gilbert } else { 2790f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2791f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2792f0d1cf93SDouglas Gilbert } 2793f0d1cf93SDouglas Gilbert } 2794f0d1cf93SDouglas Gilbert 2795f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2796f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2797f0d1cf93SDouglas Gilbert { 2798f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 279964e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2800f0d1cf93SDouglas Gilbert 2801f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2802f0d1cf93SDouglas Gilbert return; 2803f0d1cf93SDouglas Gilbert 280464e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2805f0d1cf93SDouglas Gilbert zsp->z_wp += num; 280664e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2807f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 280864e14eceSDamien Le Moal return; 280964e14eceSDamien Le Moal } 281064e14eceSDamien Le Moal 281164e14eceSDamien Le Moal while (num) { 281264e14eceSDamien Le Moal if (lba != zsp->z_wp) 281364e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 281464e14eceSDamien Le Moal 281564e14eceSDamien Le Moal end = lba + num; 281664e14eceSDamien Le Moal if (end >= zend) { 281764e14eceSDamien Le Moal n = zend - lba; 281864e14eceSDamien Le Moal zsp->z_wp = zend; 281964e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 282064e14eceSDamien Le Moal n = num; 282164e14eceSDamien Le Moal zsp->z_wp = end; 282264e14eceSDamien Le Moal } else { 282364e14eceSDamien Le Moal n = num; 282464e14eceSDamien Le Moal } 282564e14eceSDamien Le Moal if (zsp->z_wp >= zend) 282664e14eceSDamien Le Moal zsp->z_cond = ZC5_FULL; 282764e14eceSDamien Le Moal 282864e14eceSDamien Le Moal num -= n; 282964e14eceSDamien Le Moal lba += n; 283064e14eceSDamien Le Moal if (num) { 283164e14eceSDamien Le Moal zsp++; 283264e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 283364e14eceSDamien Le Moal } 283464e14eceSDamien Le Moal } 2835f0d1cf93SDouglas Gilbert } 2836f0d1cf93SDouglas Gilbert 2837f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 28389447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 28391da177e4SLinus Torvalds { 2840f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2841f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2842f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2843f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2844f0d1cf93SDouglas Gilbert 2845f0d1cf93SDouglas Gilbert if (!write) { 284664e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 284764e14eceSDamien Le Moal return 0; 284864e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 2849f0d1cf93SDouglas Gilbert if (zsp_end != zsp && 2850f0d1cf93SDouglas Gilbert zbc_zone_is_conv(zsp) && 2851f0d1cf93SDouglas Gilbert !zbc_zone_is_conv(zsp_end)) { 2852f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2853f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2854f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2855f0d1cf93SDouglas Gilbert return check_condition_result; 2856f0d1cf93SDouglas Gilbert } 2857f0d1cf93SDouglas Gilbert return 0; 2858f0d1cf93SDouglas Gilbert } 2859f0d1cf93SDouglas Gilbert 2860f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2861f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2862f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2863f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2864f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2865f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2866f0d1cf93SDouglas Gilbert return check_condition_result; 2867f0d1cf93SDouglas Gilbert } 2868f0d1cf93SDouglas Gilbert return 0; 2869f0d1cf93SDouglas Gilbert } 2870f0d1cf93SDouglas Gilbert 287164e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2872f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2873f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2874f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2875f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2876f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2877f0d1cf93SDouglas Gilbert return check_condition_result; 2878f0d1cf93SDouglas Gilbert } 2879f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2880f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2881f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2882f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2883f0d1cf93SDouglas Gilbert return check_condition_result; 2884f0d1cf93SDouglas Gilbert } 2885f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2886f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2887f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2888f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2889f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2890f0d1cf93SDouglas Gilbert return check_condition_result; 2891f0d1cf93SDouglas Gilbert } 289264e14eceSDamien Le Moal } 2893f0d1cf93SDouglas Gilbert 2894f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2895f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2896f0d1cf93SDouglas Gilbert if (devip->max_open && 2897f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2898f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2899f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2900f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2901f0d1cf93SDouglas Gilbert return check_condition_result; 2902f0d1cf93SDouglas Gilbert } 2903f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2904f0d1cf93SDouglas Gilbert } 2905f0d1cf93SDouglas Gilbert 2906f0d1cf93SDouglas Gilbert return 0; 2907f0d1cf93SDouglas Gilbert } 2908f0d1cf93SDouglas Gilbert 2909f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2910f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2911f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2912f0d1cf93SDouglas Gilbert { 2913f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2914f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2915f0d1cf93SDouglas Gilbert 2916c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 291722017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 29181da177e4SLinus Torvalds return check_condition_result; 29191da177e4SLinus Torvalds } 2920c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2921c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 292222017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2923cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2924c65b1445SDouglas Gilbert return check_condition_result; 2925c65b1445SDouglas Gilbert } 29269447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 29279447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 29289447b6ceSMartin K. Petersen return check_condition_result; 29299447b6ceSMartin K. Petersen } 2930f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2931f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2932f0d1cf93SDouglas Gilbert 293319789100SFUJITA Tomonori return 0; 293419789100SFUJITA Tomonori } 293519789100SFUJITA Tomonori 2936b6ff8ca7SDouglas Gilbert /* 2937b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 2938b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 2939b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 2940b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 2941b6ff8ca7SDouglas Gilbert */ 2942b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 2943b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 294487c715dcSDouglas Gilbert { 2945b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 2946b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 2947b6ff8ca7SDouglas Gilbert return NULL; 2948b6ff8ca7SDouglas Gilbert } 2949b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 295087c715dcSDouglas Gilbert } 295187c715dcSDouglas Gilbert 2952a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 295387c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 295487c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 295519789100SFUJITA Tomonori { 295619789100SFUJITA Tomonori int ret; 2957c2248fc9SDouglas Gilbert u64 block, rest = 0; 2958a4517511SAkinobu Mita enum dma_data_direction dir; 295987c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 296087c715dcSDouglas Gilbert u8 *fsp; 296119789100SFUJITA Tomonori 2962c2248fc9SDouglas Gilbert if (do_write) { 2963a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 29644f2c8bf6SDouglas Gilbert write_since_sync = true; 2965a4517511SAkinobu Mita } else { 2966a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2967a4517511SAkinobu Mita } 2968a4517511SAkinobu Mita 296987c715dcSDouglas Gilbert if (!sdb->length || !sip) 2970a4517511SAkinobu Mita return 0; 297187c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2972a4517511SAkinobu Mita return -1; 297387c715dcSDouglas Gilbert fsp = sip->storep; 297419789100SFUJITA Tomonori 297519789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 297619789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 297719789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 297819789100SFUJITA Tomonori 2979386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 298087c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 29810a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2982773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2983a4517511SAkinobu Mita return ret; 2984a4517511SAkinobu Mita 2985a4517511SAkinobu Mita if (rest) { 2986386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 298787c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 29880a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 29890a7e69c7SDouglas Gilbert do_write); 2990a4517511SAkinobu Mita } 299119789100SFUJITA Tomonori 299219789100SFUJITA Tomonori return ret; 299319789100SFUJITA Tomonori } 299419789100SFUJITA Tomonori 299587c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 299687c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 299787c715dcSDouglas Gilbert { 299887c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 299987c715dcSDouglas Gilbert 300087c715dcSDouglas Gilbert if (!sdb->length) 300187c715dcSDouglas Gilbert return 0; 300287c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 300387c715dcSDouglas Gilbert return -1; 300487c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 300587c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 300687c715dcSDouglas Gilbert } 300787c715dcSDouglas Gilbert 300887c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 300987c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 301038d5c833SDouglas Gilbert * return false. */ 301187c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 3012c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 301338d5c833SDouglas Gilbert { 301438d5c833SDouglas Gilbert bool res; 301538d5c833SDouglas Gilbert u64 block, rest = 0; 301638d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 3017773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 301887c715dcSDouglas Gilbert u8 *fsp = sip->storep; 301938d5c833SDouglas Gilbert 302038d5c833SDouglas Gilbert block = do_div(lba, store_blks); 302138d5c833SDouglas Gilbert if (block + num > store_blks) 302238d5c833SDouglas Gilbert rest = block + num - store_blks; 302338d5c833SDouglas Gilbert 302487c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 302538d5c833SDouglas Gilbert if (!res) 302638d5c833SDouglas Gilbert return res; 302738d5c833SDouglas Gilbert if (rest) 302887c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 302938d5c833SDouglas Gilbert rest * lb_size); 303038d5c833SDouglas Gilbert if (!res) 303138d5c833SDouglas Gilbert return res; 3032c3e2fe92SDouglas Gilbert if (compare_only) 3033c3e2fe92SDouglas Gilbert return true; 303438d5c833SDouglas Gilbert arr += num * lb_size; 303587c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 303638d5c833SDouglas Gilbert if (rest) 303787c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 303838d5c833SDouglas Gilbert return res; 303938d5c833SDouglas Gilbert } 304038d5c833SDouglas Gilbert 304151d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 3042beb40ea4SAkinobu Mita { 304351d648afSAkinobu Mita __be16 csum; 3044beb40ea4SAkinobu Mita 3045773642d9SDouglas Gilbert if (sdebug_guard) 304651d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 304751d648afSAkinobu Mita else 3048beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 304951d648afSAkinobu Mita 3050beb40ea4SAkinobu Mita return csum; 3051beb40ea4SAkinobu Mita } 3052beb40ea4SAkinobu Mita 30536ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3054beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3055beb40ea4SAkinobu Mita { 3056773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3057beb40ea4SAkinobu Mita 3058beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3059c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3060beb40ea4SAkinobu Mita (unsigned long)sector, 3061beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3062beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3063beb40ea4SAkinobu Mita return 0x01; 3064beb40ea4SAkinobu Mita } 30658475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3066beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3067c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3068c1287970STomas Winkler (unsigned long)sector); 3069beb40ea4SAkinobu Mita return 0x03; 3070beb40ea4SAkinobu Mita } 30718475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3072beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3073c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3074c1287970STomas Winkler (unsigned long)sector); 3075beb40ea4SAkinobu Mita return 0x03; 3076beb40ea4SAkinobu Mita } 3077beb40ea4SAkinobu Mita return 0; 3078beb40ea4SAkinobu Mita } 3079beb40ea4SAkinobu Mita 308087c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 308165f72f2aSAkinobu Mita unsigned int sectors, bool read) 3082c6a44287SMartin K. Petersen { 3083be4e11beSAkinobu Mita size_t resid; 3084c6a44287SMartin K. Petersen void *paddr; 308587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3086b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 308787c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 308814faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3089be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3090c6a44287SMartin K. Petersen 3091e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3092e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3093c6a44287SMartin K. Petersen 309487c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 309587c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3096be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3097be4e11beSAkinobu Mita 3098be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 309987c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 310087c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3101be4e11beSAkinobu Mita size_t rest = 0; 310214faa944SAkinobu Mita 310314faa944SAkinobu Mita if (dif_store_end < start + len) 310414faa944SAkinobu Mita rest = start + len - dif_store_end; 3105c6a44287SMartin K. Petersen 3106be4e11beSAkinobu Mita paddr = miter.addr; 310714faa944SAkinobu Mita 310865f72f2aSAkinobu Mita if (read) 310965f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 311065f72f2aSAkinobu Mita else 311165f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 311265f72f2aSAkinobu Mita 311365f72f2aSAkinobu Mita if (rest) { 311465f72f2aSAkinobu Mita if (read) 311514faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 311665f72f2aSAkinobu Mita else 311765f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 311865f72f2aSAkinobu Mita } 3119c6a44287SMartin K. Petersen 3120e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3121c6a44287SMartin K. Petersen resid -= len; 3122c6a44287SMartin K. Petersen } 3123be4e11beSAkinobu Mita sg_miter_stop(&miter); 3124bb8c063cSAkinobu Mita } 3125c6a44287SMartin K. Petersen 312687c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3127bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3128bb8c063cSAkinobu Mita { 3129f7be6772SMartin K. Petersen int ret = 0; 3130bb8c063cSAkinobu Mita unsigned int i; 3131bb8c063cSAkinobu Mita sector_t sector; 313287c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3133b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 313487c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3135bb8c063cSAkinobu Mita 3136c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3137bb8c063cSAkinobu Mita sector = start_sec + i; 313887c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3139bb8c063cSAkinobu Mita 314051d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3141bb8c063cSAkinobu Mita continue; 3142bb8c063cSAkinobu Mita 3143f7be6772SMartin K. Petersen /* 3144f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3145f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3146f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3147f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3148f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3149f7be6772SMartin K. Petersen */ 3150f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3151f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3152f7be6772SMartin K. Petersen sector, ei_lba); 3153bb8c063cSAkinobu Mita if (ret) { 3154bb8c063cSAkinobu Mita dif_errors++; 3155f7be6772SMartin K. Petersen break; 3156f7be6772SMartin K. Petersen } 3157bb8c063cSAkinobu Mita } 3158bb8c063cSAkinobu Mita } 3159bb8c063cSAkinobu Mita 316087c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3161c6a44287SMartin K. Petersen dix_reads++; 3162c6a44287SMartin K. Petersen 3163f7be6772SMartin K. Petersen return ret; 3164c6a44287SMartin K. Petersen } 3165c6a44287SMartin K. Petersen 31667109f370SDouglas Gilbert static inline void 31677109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip) 31687109f370SDouglas Gilbert { 3169e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3170e9c47801SDamien Le Moal if (sip) 3171e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3172e9c47801SDamien Le Moal else 3173e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3174e9c47801SDamien Le Moal } else { 31757109f370SDouglas Gilbert if (sip) 31767109f370SDouglas Gilbert read_lock(&sip->macc_lck); 31777109f370SDouglas Gilbert else 31787109f370SDouglas Gilbert read_lock(&sdeb_fake_rw_lck); 31797109f370SDouglas Gilbert } 3180e9c47801SDamien Le Moal } 31817109f370SDouglas Gilbert 31827109f370SDouglas Gilbert static inline void 31837109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip) 31847109f370SDouglas Gilbert { 3185e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3186e9c47801SDamien Le Moal if (sip) 3187e9c47801SDamien Le Moal __release(&sip->macc_lck); 3188e9c47801SDamien Le Moal else 3189e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3190e9c47801SDamien Le Moal } else { 31917109f370SDouglas Gilbert if (sip) 31927109f370SDouglas Gilbert read_unlock(&sip->macc_lck); 31937109f370SDouglas Gilbert else 31947109f370SDouglas Gilbert read_unlock(&sdeb_fake_rw_lck); 31957109f370SDouglas Gilbert } 3196e9c47801SDamien Le Moal } 31977109f370SDouglas Gilbert 31987109f370SDouglas Gilbert static inline void 31997109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip) 32007109f370SDouglas Gilbert { 3201e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3202e9c47801SDamien Le Moal if (sip) 3203e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3204e9c47801SDamien Le Moal else 3205e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3206e9c47801SDamien Le Moal } else { 32077109f370SDouglas Gilbert if (sip) 32087109f370SDouglas Gilbert write_lock(&sip->macc_lck); 32097109f370SDouglas Gilbert else 32107109f370SDouglas Gilbert write_lock(&sdeb_fake_rw_lck); 32117109f370SDouglas Gilbert } 3212e9c47801SDamien Le Moal } 32137109f370SDouglas Gilbert 32147109f370SDouglas Gilbert static inline void 32157109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip) 32167109f370SDouglas Gilbert { 3217e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3218e9c47801SDamien Le Moal if (sip) 3219e9c47801SDamien Le Moal __release(&sip->macc_lck); 3220e9c47801SDamien Le Moal else 3221e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3222e9c47801SDamien Le Moal } else { 32237109f370SDouglas Gilbert if (sip) 32247109f370SDouglas Gilbert write_unlock(&sip->macc_lck); 32257109f370SDouglas Gilbert else 32267109f370SDouglas Gilbert write_unlock(&sdeb_fake_rw_lck); 32277109f370SDouglas Gilbert } 3228e9c47801SDamien Le Moal } 32297109f370SDouglas Gilbert 3230fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 323119789100SFUJITA Tomonori { 323287c715dcSDouglas Gilbert bool check_prot; 3233c2248fc9SDouglas Gilbert u32 num; 3234c2248fc9SDouglas Gilbert u32 ei_lba; 323519789100SFUJITA Tomonori int ret; 323687c715dcSDouglas Gilbert u64 lba; 3237b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 323887c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 323919789100SFUJITA Tomonori 3240c2248fc9SDouglas Gilbert switch (cmd[0]) { 3241c2248fc9SDouglas Gilbert case READ_16: 3242c2248fc9SDouglas Gilbert ei_lba = 0; 3243c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3244c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3245c2248fc9SDouglas Gilbert check_prot = true; 3246c2248fc9SDouglas Gilbert break; 3247c2248fc9SDouglas Gilbert case READ_10: 3248c2248fc9SDouglas Gilbert ei_lba = 0; 3249c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3250c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3251c2248fc9SDouglas Gilbert check_prot = true; 3252c2248fc9SDouglas Gilbert break; 3253c2248fc9SDouglas Gilbert case READ_6: 3254c2248fc9SDouglas Gilbert ei_lba = 0; 3255c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3256c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3257c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3258c2248fc9SDouglas Gilbert check_prot = true; 3259c2248fc9SDouglas Gilbert break; 3260c2248fc9SDouglas Gilbert case READ_12: 3261c2248fc9SDouglas Gilbert ei_lba = 0; 3262c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3263c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3264c2248fc9SDouglas Gilbert check_prot = true; 3265c2248fc9SDouglas Gilbert break; 3266c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3267c2248fc9SDouglas Gilbert ei_lba = 0; 3268c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3269c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3270c2248fc9SDouglas Gilbert check_prot = false; 3271c2248fc9SDouglas Gilbert break; 3272c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3273c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3274c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3275c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3276c2248fc9SDouglas Gilbert check_prot = false; 3277c2248fc9SDouglas Gilbert break; 3278c2248fc9SDouglas Gilbert } 3279f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 32808475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3281c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3282c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3283c2248fc9SDouglas Gilbert return check_condition_result; 3284c2248fc9SDouglas Gilbert } 32858475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 32868475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3287c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3288c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3289c2248fc9SDouglas Gilbert "to DIF device\n"); 3290c2248fc9SDouglas Gilbert } 32913a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 32923a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3293c2248fc9SDouglas Gilbert num /= 2; 32943a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3295c2248fc9SDouglas Gilbert } 3296c2248fc9SDouglas Gilbert 32979447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 32989447b6ceSMartin K. Petersen if (ret) 32999447b6ceSMartin K. Petersen return ret; 3300f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3301d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3302d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3303c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3304c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3305c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3306c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3307c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 330832f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 330932f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3310c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3311c65b1445SDouglas Gilbert } 3312c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 33131da177e4SLinus Torvalds return check_condition_result; 33141da177e4SLinus Torvalds } 3315c6a44287SMartin K. Petersen 33167109f370SDouglas Gilbert sdeb_read_lock(sip); 33176c78cc06SAkinobu Mita 3318c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3319f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3320f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3321f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3322f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33237109f370SDouglas Gilbert sdeb_read_unlock(sip); 3324f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3325f7be6772SMartin K. Petersen return check_condition_result; 3326f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 33277109f370SDouglas Gilbert sdeb_read_unlock(sip); 3328f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3329c6a44287SMartin K. Petersen return illegal_condition_result; 3330c6a44287SMartin K. Petersen } 3331f7be6772SMartin K. Petersen break; 3332f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3333f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33347109f370SDouglas Gilbert sdeb_read_unlock(sip); 3335f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3336f7be6772SMartin K. Petersen return check_condition_result; 3337f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 33387109f370SDouglas Gilbert sdeb_read_unlock(sip); 3339f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3340f7be6772SMartin K. Petersen return illegal_condition_result; 3341f7be6772SMartin K. Petersen } 3342f7be6772SMartin K. Petersen break; 3343f7be6772SMartin K. Petersen } 3344c6a44287SMartin K. Petersen } 3345c6a44287SMartin K. Petersen 334687c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 33477109f370SDouglas Gilbert sdeb_read_unlock(sip); 3348f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3349a4517511SAkinobu Mita return DID_ERROR << 16; 3350a4517511SAkinobu Mita 335142d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3352a4517511SAkinobu Mita 33533a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 33543a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 33553a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 33563a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 33573a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3358c2248fc9SDouglas Gilbert return check_condition_result; 33593a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3360c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3361c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 33623a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3363c2248fc9SDouglas Gilbert return illegal_condition_result; 33643a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3365c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 33663a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3367c2248fc9SDouglas Gilbert return illegal_condition_result; 3368c2248fc9SDouglas Gilbert } 3369c2248fc9SDouglas Gilbert } 3370a4517511SAkinobu Mita return 0; 33711da177e4SLinus Torvalds } 33721da177e4SLinus Torvalds 3373c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3374395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3375c6a44287SMartin K. Petersen { 3376be4e11beSAkinobu Mita int ret; 33776ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3378be4e11beSAkinobu Mita void *daddr; 337965f72f2aSAkinobu Mita sector_t sector = start_sec; 3380c6a44287SMartin K. Petersen int ppage_offset; 3381be4e11beSAkinobu Mita int dpage_offset; 3382be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3383be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3384c6a44287SMartin K. Petersen 3385c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3386c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3387c6a44287SMartin K. Petersen 3388be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3389be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3390be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3391be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3392be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3393c6a44287SMartin K. Petersen 3394be4e11beSAkinobu Mita /* For each protection page */ 3395be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3396be4e11beSAkinobu Mita dpage_offset = 0; 3397be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3398be4e11beSAkinobu Mita ret = 0x01; 3399be4e11beSAkinobu Mita goto out; 3400c6a44287SMartin K. Petersen } 3401c6a44287SMartin K. Petersen 3402be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 34036ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3404be4e11beSAkinobu Mita /* If we're at the end of the current 3405be4e11beSAkinobu Mita * data page advance to the next one 3406be4e11beSAkinobu Mita */ 3407be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3408be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3409be4e11beSAkinobu Mita ret = 0x01; 3410be4e11beSAkinobu Mita goto out; 3411be4e11beSAkinobu Mita } 3412be4e11beSAkinobu Mita dpage_offset = 0; 3413be4e11beSAkinobu Mita } 3414c6a44287SMartin K. Petersen 3415be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3416be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3417be4e11beSAkinobu Mita 3418f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3419be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3420c78be80dSMartin K. Petersen if (ret) 3421395cef03SMartin K. Petersen goto out; 3422395cef03SMartin K. Petersen } 3423395cef03SMartin K. Petersen 3424c6a44287SMartin K. Petersen sector++; 3425395cef03SMartin K. Petersen ei_lba++; 3426773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3427c6a44287SMartin K. Petersen } 3428be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3429be4e11beSAkinobu Mita sg_miter_stop(&diter); 3430c6a44287SMartin K. Petersen } 3431be4e11beSAkinobu Mita sg_miter_stop(&piter); 3432c6a44287SMartin K. Petersen 343365f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3434c6a44287SMartin K. Petersen dix_writes++; 3435c6a44287SMartin K. Petersen 3436c6a44287SMartin K. Petersen return 0; 3437c6a44287SMartin K. Petersen 3438c6a44287SMartin K. Petersen out: 3439c6a44287SMartin K. Petersen dif_errors++; 3440be4e11beSAkinobu Mita sg_miter_stop(&diter); 3441be4e11beSAkinobu Mita sg_miter_stop(&piter); 3442c6a44287SMartin K. Petersen return ret; 3443c6a44287SMartin K. Petersen } 3444c6a44287SMartin K. Petersen 3445b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3446b90ebc3dSAkinobu Mita { 3447773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3448773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3449773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3450b90ebc3dSAkinobu Mita return lba; 3451b90ebc3dSAkinobu Mita } 3452b90ebc3dSAkinobu Mita 3453b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3454b90ebc3dSAkinobu Mita { 3455773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3456a027b5b9SAkinobu Mita 3457773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3458773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3459a027b5b9SAkinobu Mita return lba; 3460a027b5b9SAkinobu Mita } 3461a027b5b9SAkinobu Mita 346287c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 346387c715dcSDouglas Gilbert unsigned int *num) 346444d92694SMartin K. Petersen { 3465b90ebc3dSAkinobu Mita sector_t end; 3466b90ebc3dSAkinobu Mita unsigned int mapped; 3467b90ebc3dSAkinobu Mita unsigned long index; 3468b90ebc3dSAkinobu Mita unsigned long next; 346944d92694SMartin K. Petersen 3470b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 347187c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 347244d92694SMartin K. Petersen 347344d92694SMartin K. Petersen if (mapped) 347487c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 347544d92694SMartin K. Petersen else 347687c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 347744d92694SMartin K. Petersen 3478b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 347944d92694SMartin K. Petersen *num = end - lba; 348044d92694SMartin K. Petersen return mapped; 348144d92694SMartin K. Petersen } 348244d92694SMartin K. Petersen 348387c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 348487c715dcSDouglas Gilbert unsigned int len) 348544d92694SMartin K. Petersen { 348644d92694SMartin K. Petersen sector_t end = lba + len; 348744d92694SMartin K. Petersen 348844d92694SMartin K. Petersen while (lba < end) { 3489b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 349044d92694SMartin K. Petersen 3491b90ebc3dSAkinobu Mita if (index < map_size) 349287c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 349344d92694SMartin K. Petersen 3494b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 349544d92694SMartin K. Petersen } 349644d92694SMartin K. Petersen } 349744d92694SMartin K. Petersen 349887c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 349987c715dcSDouglas Gilbert unsigned int len) 350044d92694SMartin K. Petersen { 350144d92694SMartin K. Petersen sector_t end = lba + len; 350287c715dcSDouglas Gilbert u8 *fsp = sip->storep; 350344d92694SMartin K. Petersen 350444d92694SMartin K. Petersen while (lba < end) { 3505b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 350644d92694SMartin K. Petersen 3507b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3508773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3509b90ebc3dSAkinobu Mita index < map_size) { 351087c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3511760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 351287c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3513760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3514773642d9SDouglas Gilbert sdebug_sector_size * 3515773642d9SDouglas Gilbert sdebug_unmap_granularity); 3516be1dd78dSEric Sandeen } 351787c715dcSDouglas Gilbert if (sip->dif_storep) { 351887c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 351987c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3520773642d9SDouglas Gilbert sdebug_unmap_granularity); 3521e9926b43SAkinobu Mita } 3522b90ebc3dSAkinobu Mita } 3523b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 352444d92694SMartin K. Petersen } 352544d92694SMartin K. Petersen } 352644d92694SMartin K. Petersen 3527fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 35281da177e4SLinus Torvalds { 352987c715dcSDouglas Gilbert bool check_prot; 3530c2248fc9SDouglas Gilbert u32 num; 3531c2248fc9SDouglas Gilbert u32 ei_lba; 353219789100SFUJITA Tomonori int ret; 353387c715dcSDouglas Gilbert u64 lba; 3534b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 353587c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 35361da177e4SLinus Torvalds 3537c2248fc9SDouglas Gilbert switch (cmd[0]) { 3538c2248fc9SDouglas Gilbert case WRITE_16: 3539c2248fc9SDouglas Gilbert ei_lba = 0; 3540c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3541c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3542c2248fc9SDouglas Gilbert check_prot = true; 3543c2248fc9SDouglas Gilbert break; 3544c2248fc9SDouglas Gilbert case WRITE_10: 3545c2248fc9SDouglas Gilbert ei_lba = 0; 3546c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3547c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3548c2248fc9SDouglas Gilbert check_prot = true; 3549c2248fc9SDouglas Gilbert break; 3550c2248fc9SDouglas Gilbert case WRITE_6: 3551c2248fc9SDouglas Gilbert ei_lba = 0; 3552c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3553c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3554c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3555c2248fc9SDouglas Gilbert check_prot = true; 3556c2248fc9SDouglas Gilbert break; 3557c2248fc9SDouglas Gilbert case WRITE_12: 3558c2248fc9SDouglas Gilbert ei_lba = 0; 3559c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3560c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3561c2248fc9SDouglas Gilbert check_prot = true; 3562c2248fc9SDouglas Gilbert break; 3563c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3564c2248fc9SDouglas Gilbert ei_lba = 0; 3565c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3566c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3567c2248fc9SDouglas Gilbert check_prot = false; 3568c2248fc9SDouglas Gilbert break; 3569c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3570c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3571c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3572c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3573c2248fc9SDouglas Gilbert check_prot = false; 3574c2248fc9SDouglas Gilbert break; 3575c2248fc9SDouglas Gilbert } 3576f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 35778475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3578c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3579c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3580c2248fc9SDouglas Gilbert return check_condition_result; 3581c2248fc9SDouglas Gilbert } 35828475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 35838475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3584c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3585c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3586c2248fc9SDouglas Gilbert "to DIF device\n"); 3587c2248fc9SDouglas Gilbert } 3588f0d1cf93SDouglas Gilbert 35897109f370SDouglas Gilbert sdeb_write_lock(sip); 3590f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3591f0d1cf93SDouglas Gilbert if (ret) { 35927109f370SDouglas Gilbert sdeb_write_unlock(sip); 3593f0d1cf93SDouglas Gilbert return ret; 3594f0d1cf93SDouglas Gilbert } 35956c78cc06SAkinobu Mita 3596c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3597f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3598f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3599f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3600f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 36017109f370SDouglas Gilbert sdeb_write_unlock(sip); 3602f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3603c6a44287SMartin K. Petersen return illegal_condition_result; 3604f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36057109f370SDouglas Gilbert sdeb_write_unlock(sip); 3606f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3607f7be6772SMartin K. Petersen return check_condition_result; 3608f7be6772SMartin K. Petersen } 3609f7be6772SMartin K. Petersen break; 3610f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3611f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 36127109f370SDouglas Gilbert sdeb_write_unlock(sip); 3613f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3614f7be6772SMartin K. Petersen return illegal_condition_result; 3615f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36167109f370SDouglas Gilbert sdeb_write_unlock(sip); 3617f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3618f7be6772SMartin K. Petersen return check_condition_result; 3619f7be6772SMartin K. Petersen } 3620f7be6772SMartin K. Petersen break; 3621c6a44287SMartin K. Petersen } 3622c6a44287SMartin K. Petersen } 3623c6a44287SMartin K. Petersen 362487c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3625f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 362687c715dcSDouglas Gilbert map_region(sip, lba, num); 3627f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3628f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3629f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 36307109f370SDouglas Gilbert sdeb_write_unlock(sip); 3631f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3632773642d9SDouglas Gilbert return DID_ERROR << 16; 3633c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3634c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3635c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3636cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3637773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 363844d92694SMartin K. Petersen 36393a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 36403a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 36413a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 36423a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 36433a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3644c2248fc9SDouglas Gilbert return check_condition_result; 36453a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3646c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3647c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 36483a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3649c2248fc9SDouglas Gilbert return illegal_condition_result; 36503a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3651c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 36523a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3653c2248fc9SDouglas Gilbert return illegal_condition_result; 3654c2248fc9SDouglas Gilbert } 3655c2248fc9SDouglas Gilbert } 36561da177e4SLinus Torvalds return 0; 36571da177e4SLinus Torvalds } 36581da177e4SLinus Torvalds 3659481b5e5cSDouglas Gilbert /* 3660481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3661481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3662481b5e5cSDouglas Gilbert */ 3663481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3664481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3665481b5e5cSDouglas Gilbert { 3666481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3667481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3668481b5e5cSDouglas Gilbert u8 *up; 3669b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3670481b5e5cSDouglas Gilbert u8 wrprotect; 3671481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3672481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3673481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3674481b5e5cSDouglas Gilbert u32 ei_lba; 3675481b5e5cSDouglas Gilbert u64 lba; 3676481b5e5cSDouglas Gilbert int ret, res; 3677481b5e5cSDouglas Gilbert bool is_16; 3678481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3679481b5e5cSDouglas Gilbert 3680481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3681481b5e5cSDouglas Gilbert is_16 = false; 3682481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3683481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3684481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3685481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3686481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3687481b5e5cSDouglas Gilbert is_16 = true; 3688481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3689481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3690481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3691481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3692481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3693481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3694481b5e5cSDouglas Gilbert wrprotect) { 3695481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3696481b5e5cSDouglas Gilbert return illegal_condition_result; 3697481b5e5cSDouglas Gilbert } 3698481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3699481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3700481b5e5cSDouglas Gilbert wrprotect == 0) 3701481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3702481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3703481b5e5cSDouglas Gilbert } 3704481b5e5cSDouglas Gilbert } 3705481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3706481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3707481b5e5cSDouglas Gilbert if (lbdof == 0) { 3708481b5e5cSDouglas Gilbert if (sdebug_verbose) 3709481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3710481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3711481b5e5cSDouglas Gilbert my_name, __func__); 3712481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3713481b5e5cSDouglas Gilbert return illegal_condition_result; 3714481b5e5cSDouglas Gilbert } 3715481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3716481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3717481b5e5cSDouglas Gilbert if (sdebug_verbose) 3718481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3719481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3720481b5e5cSDouglas Gilbert my_name, __func__); 3721481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3722481b5e5cSDouglas Gilbert return illegal_condition_result; 3723481b5e5cSDouglas Gilbert } 3724481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3725481b5e5cSDouglas Gilbert if (lrdp == NULL) 3726481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3727481b5e5cSDouglas Gilbert if (sdebug_verbose) 3728481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3729481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3730481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3731481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3732481b5e5cSDouglas Gilbert if (res == -1) { 3733481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3734481b5e5cSDouglas Gilbert goto err_out; 3735481b5e5cSDouglas Gilbert } 3736481b5e5cSDouglas Gilbert 37377109f370SDouglas Gilbert sdeb_write_lock(sip); 3738481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3739481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3740481b5e5cSDouglas Gilbert cum_lb = 0; 3741481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3742481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3743481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3744481b5e5cSDouglas Gilbert if (sdebug_verbose) 3745481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3746481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3747481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3748481b5e5cSDouglas Gilbert if (num == 0) 3749481b5e5cSDouglas Gilbert continue; 37509447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3751481b5e5cSDouglas Gilbert if (ret) 3752481b5e5cSDouglas Gilbert goto err_out_unlock; 3753481b5e5cSDouglas Gilbert num_by = num * lb_size; 3754481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3755481b5e5cSDouglas Gilbert 3756481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3757481b5e5cSDouglas Gilbert if (sdebug_verbose) 3758481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3759481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3760481b5e5cSDouglas Gilbert my_name, __func__); 3761481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3762481b5e5cSDouglas Gilbert 0); 3763481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3764481b5e5cSDouglas Gilbert goto err_out_unlock; 3765481b5e5cSDouglas Gilbert } 3766481b5e5cSDouglas Gilbert 3767481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3768481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3769481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3770481b5e5cSDouglas Gilbert ei_lba); 3771481b5e5cSDouglas Gilbert 3772481b5e5cSDouglas Gilbert if (prot_ret) { 3773481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3774481b5e5cSDouglas Gilbert prot_ret); 3775481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3776481b5e5cSDouglas Gilbert goto err_out_unlock; 3777481b5e5cSDouglas Gilbert } 3778481b5e5cSDouglas Gilbert } 3779481b5e5cSDouglas Gilbert 378087c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3781f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3782f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3783f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3784481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 378587c715dcSDouglas Gilbert map_region(sip, lba, num); 3786481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3787481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3788481b5e5cSDouglas Gilbert goto err_out_unlock; 3789481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3790481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3791481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3792481b5e5cSDouglas Gilbert my_name, num_by, ret); 3793481b5e5cSDouglas Gilbert 37943a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 37953a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 37963a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 37973a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 37983a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 37993a90a63dSDouglas Gilbert ret = check_condition_result; 3800481b5e5cSDouglas Gilbert goto err_out_unlock; 38013a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3802481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 38033a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 38043a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3805481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3806481b5e5cSDouglas Gilbert goto err_out_unlock; 38073a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 38083a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 38093a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3810481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3811481b5e5cSDouglas Gilbert goto err_out_unlock; 3812481b5e5cSDouglas Gilbert } 3813481b5e5cSDouglas Gilbert } 3814481b5e5cSDouglas Gilbert sg_off += num_by; 3815481b5e5cSDouglas Gilbert cum_lb += num; 3816481b5e5cSDouglas Gilbert } 3817481b5e5cSDouglas Gilbert ret = 0; 3818481b5e5cSDouglas Gilbert err_out_unlock: 38197109f370SDouglas Gilbert sdeb_write_unlock(sip); 3820481b5e5cSDouglas Gilbert err_out: 3821481b5e5cSDouglas Gilbert kfree(lrdp); 3822481b5e5cSDouglas Gilbert return ret; 3823481b5e5cSDouglas Gilbert } 3824481b5e5cSDouglas Gilbert 3825fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3826fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 382744d92694SMartin K. Petersen { 3828f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3829f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 383044d92694SMartin K. Petersen unsigned long long i; 383140d07b52SDouglas Gilbert u64 block, lbaa; 383287c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 383387c715dcSDouglas Gilbert int ret; 383487c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3835b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 383640d07b52SDouglas Gilbert u8 *fs1p; 383787c715dcSDouglas Gilbert u8 *fsp; 383844d92694SMartin K. Petersen 38397109f370SDouglas Gilbert sdeb_write_lock(sip); 384044d92694SMartin K. Petersen 3841f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3842f0d1cf93SDouglas Gilbert if (ret) { 38437109f370SDouglas Gilbert sdeb_write_unlock(sip); 3844f0d1cf93SDouglas Gilbert return ret; 3845f0d1cf93SDouglas Gilbert } 3846f0d1cf93SDouglas Gilbert 38479ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 384887c715dcSDouglas Gilbert unmap_region(sip, lba, num); 384944d92694SMartin K. Petersen goto out; 385044d92694SMartin K. Petersen } 385140d07b52SDouglas Gilbert lbaa = lba; 385240d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3853c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 385487c715dcSDouglas Gilbert fsp = sip->storep; 385587c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3856c2248fc9SDouglas Gilbert if (ndob) { 385740d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3858c2248fc9SDouglas Gilbert ret = 0; 3859c2248fc9SDouglas Gilbert } else 386040d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 386144d92694SMartin K. Petersen 386244d92694SMartin K. Petersen if (-1 == ret) { 38637109f370SDouglas Gilbert sdeb_write_unlock(sip); 3864773642d9SDouglas Gilbert return DID_ERROR << 16; 386540d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3866c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3867e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 386840d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 386944d92694SMartin K. Petersen 387044d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 387140d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 387240d07b52SDouglas Gilbert lbaa = lba + i; 387340d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 387487c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 387540d07b52SDouglas Gilbert } 38769ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 387787c715dcSDouglas Gilbert map_region(sip, lba, num); 3878f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3879f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3880f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 388144d92694SMartin K. Petersen out: 38827109f370SDouglas Gilbert sdeb_write_unlock(sip); 388344d92694SMartin K. Petersen 388444d92694SMartin K. Petersen return 0; 388544d92694SMartin K. Petersen } 388644d92694SMartin K. Petersen 3887fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3888fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3889c2248fc9SDouglas Gilbert { 3890c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3891c2248fc9SDouglas Gilbert u32 lba; 3892c2248fc9SDouglas Gilbert u16 num; 3893c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3894c2248fc9SDouglas Gilbert bool unmap = false; 3895c2248fc9SDouglas Gilbert 3896c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3897773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3898c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3899c2248fc9SDouglas Gilbert return check_condition_result; 3900c2248fc9SDouglas Gilbert } else 3901c2248fc9SDouglas Gilbert unmap = true; 3902c2248fc9SDouglas Gilbert } 3903c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3904c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3905773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3906c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3907c2248fc9SDouglas Gilbert return check_condition_result; 3908c2248fc9SDouglas Gilbert } 3909c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3910c2248fc9SDouglas Gilbert } 3911c2248fc9SDouglas Gilbert 3912fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3913fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3914c2248fc9SDouglas Gilbert { 3915c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3916c2248fc9SDouglas Gilbert u64 lba; 3917c2248fc9SDouglas Gilbert u32 num; 3918c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3919c2248fc9SDouglas Gilbert bool unmap = false; 3920c2248fc9SDouglas Gilbert bool ndob = false; 3921c2248fc9SDouglas Gilbert 3922c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3923773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3924c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3925c2248fc9SDouglas Gilbert return check_condition_result; 3926c2248fc9SDouglas Gilbert } else 3927c2248fc9SDouglas Gilbert unmap = true; 3928c2248fc9SDouglas Gilbert } 3929c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3930c2248fc9SDouglas Gilbert ndob = true; 3931c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3932c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3933773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3934c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3935c2248fc9SDouglas Gilbert return check_condition_result; 3936c2248fc9SDouglas Gilbert } 3937c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3938c2248fc9SDouglas Gilbert } 3939c2248fc9SDouglas Gilbert 3940acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3941acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3942acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3943fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3944fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3945acafd0b9SEwan D. Milne { 3946acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3947acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3948acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3949acafd0b9SEwan D. Milne u8 mode; 3950acafd0b9SEwan D. Milne 3951acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3952acafd0b9SEwan D. Milne switch (mode) { 3953acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3954acafd0b9SEwan D. Milne /* set UAs on this device only */ 3955acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3956acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3957acafd0b9SEwan D. Milne break; 3958acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3959acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3960acafd0b9SEwan D. Milne break; 3961acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3962acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3963acafd0b9SEwan D. Milne list_for_each_entry(dp, 3964acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3965acafd0b9SEwan D. Milne dev_list) 3966acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3967acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3968acafd0b9SEwan D. Milne if (devip != dp) 3969acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3970acafd0b9SEwan D. Milne dp->uas_bm); 3971acafd0b9SEwan D. Milne } 3972acafd0b9SEwan D. Milne break; 3973acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3974acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3975acafd0b9SEwan D. Milne list_for_each_entry(dp, 3976acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3977acafd0b9SEwan D. Milne dev_list) 3978acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3979acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3980acafd0b9SEwan D. Milne dp->uas_bm); 3981acafd0b9SEwan D. Milne break; 3982acafd0b9SEwan D. Milne default: 3983acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3984acafd0b9SEwan D. Milne break; 3985acafd0b9SEwan D. Milne } 3986acafd0b9SEwan D. Milne return 0; 3987acafd0b9SEwan D. Milne } 3988acafd0b9SEwan D. Milne 3989fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3990fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 399138d5c833SDouglas Gilbert { 399238d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 399338d5c833SDouglas Gilbert u8 *arr; 3994b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 399538d5c833SDouglas Gilbert u64 lba; 399638d5c833SDouglas Gilbert u32 dnum; 3997773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 399838d5c833SDouglas Gilbert u8 num; 399938d5c833SDouglas Gilbert int ret; 4000d467d31fSDouglas Gilbert int retval = 0; 400138d5c833SDouglas Gilbert 4002d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 400338d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 400438d5c833SDouglas Gilbert if (0 == num) 400538d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 40068475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 400738d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 400838d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 400938d5c833SDouglas Gilbert return check_condition_result; 401038d5c833SDouglas Gilbert } 40118475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 40128475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 401338d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 401438d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 401538d5c833SDouglas Gilbert "to DIF device\n"); 40169447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 40179447b6ceSMartin K. Petersen if (ret) 40189447b6ceSMartin K. Petersen return ret; 4019d467d31fSDouglas Gilbert dnum = 2 * num; 40206396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 4021d467d31fSDouglas Gilbert if (NULL == arr) { 4022d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4023d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 4024d467d31fSDouglas Gilbert return check_condition_result; 4025d467d31fSDouglas Gilbert } 402638d5c833SDouglas Gilbert 40277109f370SDouglas Gilbert sdeb_write_lock(sip); 402838d5c833SDouglas Gilbert 402987c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 403038d5c833SDouglas Gilbert if (ret == -1) { 4031d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 4032d467d31fSDouglas Gilbert goto cleanup; 4033773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 403438d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 403538d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 403638d5c833SDouglas Gilbert dnum * lb_size, ret); 4037c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 403838d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4039d467d31fSDouglas Gilbert retval = check_condition_result; 4040d467d31fSDouglas Gilbert goto cleanup; 404138d5c833SDouglas Gilbert } 404238d5c833SDouglas Gilbert if (scsi_debug_lbp()) 404387c715dcSDouglas Gilbert map_region(sip, lba, num); 4044d467d31fSDouglas Gilbert cleanup: 40457109f370SDouglas Gilbert sdeb_write_unlock(sip); 4046d467d31fSDouglas Gilbert kfree(arr); 4047d467d31fSDouglas Gilbert return retval; 404838d5c833SDouglas Gilbert } 404938d5c833SDouglas Gilbert 405044d92694SMartin K. Petersen struct unmap_block_desc { 405144d92694SMartin K. Petersen __be64 lba; 405244d92694SMartin K. Petersen __be32 blocks; 405344d92694SMartin K. Petersen __be32 __reserved; 405444d92694SMartin K. Petersen }; 405544d92694SMartin K. Petersen 4056fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 405744d92694SMartin K. Petersen { 405844d92694SMartin K. Petersen unsigned char *buf; 405944d92694SMartin K. Petersen struct unmap_block_desc *desc; 4060b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 406144d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 406244d92694SMartin K. Petersen int ret; 406344d92694SMartin K. Petersen 4064c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 4065c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 4066c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 4067c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 406844d92694SMartin K. Petersen 406944d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 4070773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 4071c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 407244d92694SMartin K. Petersen return check_condition_result; 4073c2248fc9SDouglas Gilbert } 407444d92694SMartin K. Petersen 4075b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 4076c2248fc9SDouglas Gilbert if (!buf) { 4077c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4078c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 4079c2248fc9SDouglas Gilbert return check_condition_result; 4080c2248fc9SDouglas Gilbert } 4081c2248fc9SDouglas Gilbert 4082c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 408344d92694SMartin K. Petersen 408444d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 408544d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 408644d92694SMartin K. Petersen 408744d92694SMartin K. Petersen desc = (void *)&buf[8]; 408844d92694SMartin K. Petersen 40897109f370SDouglas Gilbert sdeb_write_lock(sip); 40906c78cc06SAkinobu Mita 409144d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 409244d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 409344d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 409444d92694SMartin K. Petersen 40959447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 409644d92694SMartin K. Petersen if (ret) 409744d92694SMartin K. Petersen goto out; 409844d92694SMartin K. Petersen 409987c715dcSDouglas Gilbert unmap_region(sip, lba, num); 410044d92694SMartin K. Petersen } 410144d92694SMartin K. Petersen 410244d92694SMartin K. Petersen ret = 0; 410344d92694SMartin K. Petersen 410444d92694SMartin K. Petersen out: 41057109f370SDouglas Gilbert sdeb_write_unlock(sip); 410644d92694SMartin K. Petersen kfree(buf); 410744d92694SMartin K. Petersen 410844d92694SMartin K. Petersen return ret; 410944d92694SMartin K. Petersen } 411044d92694SMartin K. Petersen 411144d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 411244d92694SMartin K. Petersen 4113fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4114fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 411544d92694SMartin K. Petersen { 4116c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4117c2248fc9SDouglas Gilbert u64 lba; 4118c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 411944d92694SMartin K. Petersen int ret; 412087c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 412144d92694SMartin K. Petersen 4122c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4123c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 412444d92694SMartin K. Petersen 412544d92694SMartin K. Petersen if (alloc_len < 24) 412644d92694SMartin K. Petersen return 0; 412744d92694SMartin K. Petersen 41289447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 412944d92694SMartin K. Petersen if (ret) 413044d92694SMartin K. Petersen return ret; 413144d92694SMartin K. Petersen 4132b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4133b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4134b6ff8ca7SDouglas Gilbert 413587c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4136b6ff8ca7SDouglas Gilbert } else { 4137c2248fc9SDouglas Gilbert mapped = 1; 4138c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4139c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4140c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4141c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4142c2248fc9SDouglas Gilbert else 4143c2248fc9SDouglas Gilbert num = 0xffffffff; 4144c2248fc9SDouglas Gilbert } 414544d92694SMartin K. Petersen 414644d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4147c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4148c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4149c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4150c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 415144d92694SMartin K. Petersen 4152c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 415344d92694SMartin K. Petersen } 415444d92694SMartin K. Petersen 415580c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 415680c49563SDouglas Gilbert struct sdebug_dev_info *devip) 415780c49563SDouglas Gilbert { 41584f2c8bf6SDouglas Gilbert int res = 0; 415980c49563SDouglas Gilbert u64 lba; 416080c49563SDouglas Gilbert u32 num_blocks; 416180c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 416280c49563SDouglas Gilbert 416380c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 416480c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 416580c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 416680c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 416780c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 416880c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 416980c49563SDouglas Gilbert } 417080c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 417180c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 417280c49563SDouglas Gilbert return check_condition_result; 417380c49563SDouglas Gilbert } 4174fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 41754f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 41764f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 41774f2c8bf6SDouglas Gilbert write_since_sync = false; 41784f2c8bf6SDouglas Gilbert return res; 417980c49563SDouglas Gilbert } 418080c49563SDouglas Gilbert 4181ed9f3e25SDouglas Gilbert /* 4182ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4183ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4184ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4185ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4186ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4187ed9f3e25SDouglas Gilbert */ 4188ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4189ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4190ed9f3e25SDouglas Gilbert { 4191ed9f3e25SDouglas Gilbert int res = 0; 4192ed9f3e25SDouglas Gilbert u64 lba; 4193ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4194ed9f3e25SDouglas Gilbert u32 nblks; 4195ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4196b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4197b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4198ed9f3e25SDouglas Gilbert 4199ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4200ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4201ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4202ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4203ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4204ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4205ed9f3e25SDouglas Gilbert } 4206ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4207ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4208ed9f3e25SDouglas Gilbert return check_condition_result; 4209ed9f3e25SDouglas Gilbert } 4210ed9f3e25SDouglas Gilbert if (!fsp) 4211ed9f3e25SDouglas Gilbert goto fini; 4212ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4213ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4214ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4215ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4216ed9f3e25SDouglas Gilbert 4217ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 42187109f370SDouglas Gilbert sdeb_read_lock(sip); 4219ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4220ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4221ed9f3e25SDouglas Gilbert if (rest) 4222ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 42237109f370SDouglas Gilbert sdeb_read_unlock(sip); 4224ed9f3e25SDouglas Gilbert fini: 4225ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4226ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4227ed9f3e25SDouglas Gilbert return res | condition_met_result; 4228ed9f3e25SDouglas Gilbert } 4229ed9f3e25SDouglas Gilbert 4230fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4231fb0cc8d1SDouglas Gilbert 42328d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 42338d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 42348d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 42358d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 42368d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 42378d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 42388d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 42398d039e22SDouglas Gilbert */ 42401da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 42411da177e4SLinus Torvalds struct sdebug_dev_info *devip) 42421da177e4SLinus Torvalds { 424301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 42448d039e22SDouglas Gilbert unsigned int alloc_len; 42458d039e22SDouglas Gilbert unsigned char select_report; 42468d039e22SDouglas Gilbert u64 lun; 42478d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4248fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 42498d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 42508d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 42518d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 42528d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4253fb0cc8d1SDouglas Gilbert int k, j, n, res; 4254fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4255fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 42561da177e4SLinus Torvalds 425719c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 42588d039e22SDouglas Gilbert 42598d039e22SDouglas Gilbert select_report = cmd[2]; 42608d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 42618d039e22SDouglas Gilbert 42628d039e22SDouglas Gilbert if (alloc_len < 4) { 42638d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 42648d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 42651da177e4SLinus Torvalds return check_condition_result; 42661da177e4SLinus Torvalds } 42678d039e22SDouglas Gilbert 42688d039e22SDouglas Gilbert switch (select_report) { 42698d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4270773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 42718d039e22SDouglas Gilbert wlun_cnt = 0; 42728d039e22SDouglas Gilbert break; 42738d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4274c65b1445SDouglas Gilbert lun_cnt = 0; 42758d039e22SDouglas Gilbert wlun_cnt = 1; 42768d039e22SDouglas Gilbert break; 42778d039e22SDouglas Gilbert case 2: /* all LUNs */ 42788d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 42798d039e22SDouglas Gilbert wlun_cnt = 1; 42808d039e22SDouglas Gilbert break; 42818d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 42828d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 42838d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 42848d039e22SDouglas Gilbert default: 42858d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 42868d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 42878d039e22SDouglas Gilbert return check_condition_result; 42888d039e22SDouglas Gilbert } 42898d039e22SDouglas Gilbert 42908d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4291c65b1445SDouglas Gilbert --lun_cnt; 42928d039e22SDouglas Gilbert 42938d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4294fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4295fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 42968d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 42978d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 42988d039e22SDouglas Gilbert 4299fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 43008d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4301fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4302fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4303fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4304fb0cc8d1SDouglas Gilbert if (k == 0) { 4305fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4306fb0cc8d1SDouglas Gilbert ++lun_p; 4307fb0cc8d1SDouglas Gilbert j = 1; 4308fb0cc8d1SDouglas Gilbert } 4309fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4310fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4311fb0cc8d1SDouglas Gilbert break; 4312fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4313ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4314ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4315fb0cc8d1SDouglas Gilbert } 4316fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4317fb0cc8d1SDouglas Gilbert break; 4318fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4319fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4320fb0cc8d1SDouglas Gilbert if (res) 4321fb0cc8d1SDouglas Gilbert return res; 4322fb0cc8d1SDouglas Gilbert off_rsp += n; 4323fb0cc8d1SDouglas Gilbert } 4324fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4325fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4326fb0cc8d1SDouglas Gilbert ++j; 4327fb0cc8d1SDouglas Gilbert } 4328fb0cc8d1SDouglas Gilbert if (j > 0) 4329fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 43308d039e22SDouglas Gilbert return res; 43311da177e4SLinus Torvalds } 43321da177e4SLinus Torvalds 4333c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4334c3e2fe92SDouglas Gilbert { 4335c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4336c3e2fe92SDouglas Gilbert u8 bytchk; 4337c3e2fe92SDouglas Gilbert int ret, j; 4338c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4339c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4340c3e2fe92SDouglas Gilbert u64 lba; 4341c3e2fe92SDouglas Gilbert u8 *arr; 4342c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4343b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4344c3e2fe92SDouglas Gilbert 4345c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4346c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4347c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4348c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4349c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4350c3e2fe92SDouglas Gilbert return check_condition_result; 4351c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4352c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4353c3e2fe92SDouglas Gilbert } 4354c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4355c3e2fe92SDouglas Gilbert case VERIFY_16: 4356c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4357c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4358c3e2fe92SDouglas Gilbert break; 4359c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4360c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4361c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4362c3e2fe92SDouglas Gilbert break; 4363c3e2fe92SDouglas Gilbert default: 4364c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4365c3e2fe92SDouglas Gilbert return check_condition_result; 4366c3e2fe92SDouglas Gilbert } 43673344b58bSGeorge Kennedy if (vnum == 0) 43683344b58bSGeorge Kennedy return 0; /* not an error */ 4369c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4370c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4371c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4372c3e2fe92SDouglas Gilbert if (ret) 4373c3e2fe92SDouglas Gilbert return ret; 4374c3e2fe92SDouglas Gilbert 4375c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4376c3e2fe92SDouglas Gilbert if (!arr) { 4377c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4378c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4379c3e2fe92SDouglas Gilbert return check_condition_result; 4380c3e2fe92SDouglas Gilbert } 4381c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 43827109f370SDouglas Gilbert sdeb_read_lock(sip); 4383c3e2fe92SDouglas Gilbert 4384c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4385c3e2fe92SDouglas Gilbert if (ret == -1) { 4386c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4387c3e2fe92SDouglas Gilbert goto cleanup; 4388c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4389c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4390c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4391c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4392c3e2fe92SDouglas Gilbert } 4393c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4394c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4395c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4396c3e2fe92SDouglas Gilbert } 4397c3e2fe92SDouglas Gilbert ret = 0; 4398c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4399c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4400c3e2fe92SDouglas Gilbert ret = check_condition_result; 4401c3e2fe92SDouglas Gilbert goto cleanup; 4402c3e2fe92SDouglas Gilbert } 4403c3e2fe92SDouglas Gilbert cleanup: 44047109f370SDouglas Gilbert sdeb_read_unlock(sip); 4405c3e2fe92SDouglas Gilbert kfree(arr); 4406c3e2fe92SDouglas Gilbert return ret; 4407c3e2fe92SDouglas Gilbert } 4408c3e2fe92SDouglas Gilbert 4409f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4410f0d1cf93SDouglas Gilbert 4411f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */ 4412f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4413f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4414f0d1cf93SDouglas Gilbert { 4415f0d1cf93SDouglas Gilbert unsigned int i, max_zones, rep_max_zones, nrz = 0; 4416f0d1cf93SDouglas Gilbert int ret = 0; 4417f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4418f0d1cf93SDouglas Gilbert bool partial; 4419f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4420f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4421f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4422f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4423b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4424f0d1cf93SDouglas Gilbert 4425f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4426f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4427f0d1cf93SDouglas Gilbert return check_condition_result; 4428f0d1cf93SDouglas Gilbert } 4429f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4430f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 44313344b58bSGeorge Kennedy if (alloc_len == 0) 44323344b58bSGeorge Kennedy return 0; /* not an error */ 4433f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4434f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4435f0d1cf93SDouglas Gilbert 4436f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4437f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4438f0d1cf93SDouglas Gilbert return check_condition_result; 4439f0d1cf93SDouglas Gilbert } 4440f0d1cf93SDouglas Gilbert 4441108e36f0SDamien Le Moal max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift); 4442f0d1cf93SDouglas Gilbert rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), 4443f0d1cf93SDouglas Gilbert max_zones); 4444f0d1cf93SDouglas Gilbert 44457db0e0c8SShin'ichiro Kawasaki arr = kzalloc(alloc_len, GFP_ATOMIC); 4446f0d1cf93SDouglas Gilbert if (!arr) { 4447f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4448f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4449f0d1cf93SDouglas Gilbert return check_condition_result; 4450f0d1cf93SDouglas Gilbert } 4451f0d1cf93SDouglas Gilbert 44527109f370SDouglas Gilbert sdeb_read_lock(sip); 4453f0d1cf93SDouglas Gilbert 4454f0d1cf93SDouglas Gilbert desc = arr + 64; 4455f0d1cf93SDouglas Gilbert for (i = 0; i < max_zones; i++) { 4456f0d1cf93SDouglas Gilbert lba = zs_lba + devip->zsize * i; 4457f0d1cf93SDouglas Gilbert if (lba > sdebug_capacity) 4458f0d1cf93SDouglas Gilbert break; 4459f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4460f0d1cf93SDouglas Gilbert switch (rep_opts) { 4461f0d1cf93SDouglas Gilbert case 0x00: 4462f0d1cf93SDouglas Gilbert /* All zones */ 4463f0d1cf93SDouglas Gilbert break; 4464f0d1cf93SDouglas Gilbert case 0x01: 4465f0d1cf93SDouglas Gilbert /* Empty zones */ 4466f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4467f0d1cf93SDouglas Gilbert continue; 4468f0d1cf93SDouglas Gilbert break; 4469f0d1cf93SDouglas Gilbert case 0x02: 4470f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4471f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4472f0d1cf93SDouglas Gilbert continue; 4473f0d1cf93SDouglas Gilbert break; 4474f0d1cf93SDouglas Gilbert case 0x03: 4475f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4476f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4477f0d1cf93SDouglas Gilbert continue; 4478f0d1cf93SDouglas Gilbert break; 4479f0d1cf93SDouglas Gilbert case 0x04: 4480f0d1cf93SDouglas Gilbert /* Closed zones */ 4481f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4482f0d1cf93SDouglas Gilbert continue; 4483f0d1cf93SDouglas Gilbert break; 4484f0d1cf93SDouglas Gilbert case 0x05: 4485f0d1cf93SDouglas Gilbert /* Full zones */ 4486f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4487f0d1cf93SDouglas Gilbert continue; 4488f0d1cf93SDouglas Gilbert break; 4489f0d1cf93SDouglas Gilbert case 0x06: 4490f0d1cf93SDouglas Gilbert case 0x07: 4491f0d1cf93SDouglas Gilbert case 0x10: 4492f0d1cf93SDouglas Gilbert /* 449364e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 449464e14eceSDamien Le Moal * not emulated: no zones to report; 4495f0d1cf93SDouglas Gilbert */ 4496f0d1cf93SDouglas Gilbert continue; 449764e14eceSDamien Le Moal case 0x11: 449864e14eceSDamien Le Moal /* non-seq-resource set */ 449964e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 450064e14eceSDamien Le Moal continue; 450164e14eceSDamien Le Moal break; 4502f0d1cf93SDouglas Gilbert case 0x3f: 4503f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 4504f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp)) 4505f0d1cf93SDouglas Gilbert continue; 4506f0d1cf93SDouglas Gilbert break; 4507f0d1cf93SDouglas Gilbert default: 4508f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4509f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4510f0d1cf93SDouglas Gilbert ret = check_condition_result; 4511f0d1cf93SDouglas Gilbert goto fini; 4512f0d1cf93SDouglas Gilbert } 4513f0d1cf93SDouglas Gilbert 4514f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4515f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 451664e14eceSDamien Le Moal desc[0] = zsp->z_type; 4517f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 451864e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 451964e14eceSDamien Le Moal desc[1] |= 1 << 1; 4520f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4521f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4522f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4523f0d1cf93SDouglas Gilbert desc += 64; 4524f0d1cf93SDouglas Gilbert } 4525f0d1cf93SDouglas Gilbert 4526f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4527f0d1cf93SDouglas Gilbert break; 4528f0d1cf93SDouglas Gilbert 4529f0d1cf93SDouglas Gilbert nrz++; 4530f0d1cf93SDouglas Gilbert } 4531f0d1cf93SDouglas Gilbert 4532f0d1cf93SDouglas Gilbert /* Report header */ 4533f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 4534f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 4535f0d1cf93SDouglas Gilbert 4536f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 453736e07d7eSGeorge Kennedy ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)); 4538f0d1cf93SDouglas Gilbert 4539f0d1cf93SDouglas Gilbert fini: 45407109f370SDouglas Gilbert sdeb_read_unlock(sip); 4541f0d1cf93SDouglas Gilbert kfree(arr); 4542f0d1cf93SDouglas Gilbert return ret; 4543f0d1cf93SDouglas Gilbert } 4544f0d1cf93SDouglas Gilbert 4545f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4546f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4547f0d1cf93SDouglas Gilbert { 4548f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4549f0d1cf93SDouglas Gilbert unsigned int i; 4550f0d1cf93SDouglas Gilbert 4551f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4552f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4553f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4554f0d1cf93SDouglas Gilbert } 4555f0d1cf93SDouglas Gilbert } 4556f0d1cf93SDouglas Gilbert 4557f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4558f0d1cf93SDouglas Gilbert { 4559f0d1cf93SDouglas Gilbert int res = 0; 4560f0d1cf93SDouglas Gilbert u64 z_id; 4561f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4562f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4563f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4564f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4565b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4566f0d1cf93SDouglas Gilbert 4567f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4568f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4569f0d1cf93SDouglas Gilbert return check_condition_result; 4570f0d1cf93SDouglas Gilbert } 4571f0d1cf93SDouglas Gilbert 45727109f370SDouglas Gilbert sdeb_write_lock(sip); 4573f0d1cf93SDouglas Gilbert 4574f0d1cf93SDouglas Gilbert if (all) { 4575f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4576f0d1cf93SDouglas Gilbert if (devip->max_open && 4577f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4578f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4579f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4580f0d1cf93SDouglas Gilbert res = check_condition_result; 4581f0d1cf93SDouglas Gilbert goto fini; 4582f0d1cf93SDouglas Gilbert } 4583f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4584f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4585f0d1cf93SDouglas Gilbert goto fini; 4586f0d1cf93SDouglas Gilbert } 4587f0d1cf93SDouglas Gilbert 4588f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4589f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4590f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4591f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4592f0d1cf93SDouglas Gilbert res = check_condition_result; 4593f0d1cf93SDouglas Gilbert goto fini; 4594f0d1cf93SDouglas Gilbert } 4595f0d1cf93SDouglas Gilbert 4596f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4597f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4598f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4599f0d1cf93SDouglas Gilbert res = check_condition_result; 4600f0d1cf93SDouglas Gilbert goto fini; 4601f0d1cf93SDouglas Gilbert } 4602f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4603f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4604f0d1cf93SDouglas Gilbert res = check_condition_result; 4605f0d1cf93SDouglas Gilbert goto fini; 4606f0d1cf93SDouglas Gilbert } 4607f0d1cf93SDouglas Gilbert 4608f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4609f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4610f0d1cf93SDouglas Gilbert goto fini; 4611f0d1cf93SDouglas Gilbert 4612f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4613f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4614f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4615f0d1cf93SDouglas Gilbert res = check_condition_result; 4616f0d1cf93SDouglas Gilbert goto fini; 4617f0d1cf93SDouglas Gilbert } 4618f0d1cf93SDouglas Gilbert 4619f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4620f0d1cf93SDouglas Gilbert fini: 46217109f370SDouglas Gilbert sdeb_write_unlock(sip); 4622f0d1cf93SDouglas Gilbert return res; 4623f0d1cf93SDouglas Gilbert } 4624f0d1cf93SDouglas Gilbert 4625f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4626f0d1cf93SDouglas Gilbert { 4627f0d1cf93SDouglas Gilbert unsigned int i; 4628f0d1cf93SDouglas Gilbert 4629f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4630f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4631f0d1cf93SDouglas Gilbert } 4632f0d1cf93SDouglas Gilbert 4633f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4634f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4635f0d1cf93SDouglas Gilbert { 4636f0d1cf93SDouglas Gilbert int res = 0; 4637f0d1cf93SDouglas Gilbert u64 z_id; 4638f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4639f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4640f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4641b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4642f0d1cf93SDouglas Gilbert 4643f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4644f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4645f0d1cf93SDouglas Gilbert return check_condition_result; 4646f0d1cf93SDouglas Gilbert } 4647f0d1cf93SDouglas Gilbert 46487109f370SDouglas Gilbert sdeb_write_lock(sip); 4649f0d1cf93SDouglas Gilbert 4650f0d1cf93SDouglas Gilbert if (all) { 4651f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4652f0d1cf93SDouglas Gilbert goto fini; 4653f0d1cf93SDouglas Gilbert } 4654f0d1cf93SDouglas Gilbert 4655f0d1cf93SDouglas Gilbert /* Close specified zone */ 4656f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4657f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4658f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4659f0d1cf93SDouglas Gilbert res = check_condition_result; 4660f0d1cf93SDouglas Gilbert goto fini; 4661f0d1cf93SDouglas Gilbert } 4662f0d1cf93SDouglas Gilbert 4663f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4664f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4665f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4666f0d1cf93SDouglas Gilbert res = check_condition_result; 4667f0d1cf93SDouglas Gilbert goto fini; 4668f0d1cf93SDouglas Gilbert } 4669f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4670f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4671f0d1cf93SDouglas Gilbert res = check_condition_result; 4672f0d1cf93SDouglas Gilbert goto fini; 4673f0d1cf93SDouglas Gilbert } 4674f0d1cf93SDouglas Gilbert 4675f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4676f0d1cf93SDouglas Gilbert fini: 46777109f370SDouglas Gilbert sdeb_write_unlock(sip); 4678f0d1cf93SDouglas Gilbert return res; 4679f0d1cf93SDouglas Gilbert } 4680f0d1cf93SDouglas Gilbert 4681f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4682f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4683f0d1cf93SDouglas Gilbert { 4684f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4685f0d1cf93SDouglas Gilbert 4686f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4687f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4688f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4689f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4690f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4691f0d1cf93SDouglas Gilbert devip->nr_closed--; 4692f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4693f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4694f0d1cf93SDouglas Gilbert } 4695f0d1cf93SDouglas Gilbert } 4696f0d1cf93SDouglas Gilbert 4697f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4698f0d1cf93SDouglas Gilbert { 4699f0d1cf93SDouglas Gilbert unsigned int i; 4700f0d1cf93SDouglas Gilbert 4701f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4702f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4703f0d1cf93SDouglas Gilbert } 4704f0d1cf93SDouglas Gilbert 4705f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4706f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4707f0d1cf93SDouglas Gilbert { 4708f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4709f0d1cf93SDouglas Gilbert int res = 0; 4710f0d1cf93SDouglas Gilbert u64 z_id; 4711f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4712f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4713b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4714f0d1cf93SDouglas Gilbert 4715f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4716f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4717f0d1cf93SDouglas Gilbert return check_condition_result; 4718f0d1cf93SDouglas Gilbert } 4719f0d1cf93SDouglas Gilbert 47207109f370SDouglas Gilbert sdeb_write_lock(sip); 4721f0d1cf93SDouglas Gilbert 4722f0d1cf93SDouglas Gilbert if (all) { 4723f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4724f0d1cf93SDouglas Gilbert goto fini; 4725f0d1cf93SDouglas Gilbert } 4726f0d1cf93SDouglas Gilbert 4727f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4728f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4729f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4730f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4731f0d1cf93SDouglas Gilbert res = check_condition_result; 4732f0d1cf93SDouglas Gilbert goto fini; 4733f0d1cf93SDouglas Gilbert } 4734f0d1cf93SDouglas Gilbert 4735f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4736f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4737f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4738f0d1cf93SDouglas Gilbert res = check_condition_result; 4739f0d1cf93SDouglas Gilbert goto fini; 4740f0d1cf93SDouglas Gilbert } 4741f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4742f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4743f0d1cf93SDouglas Gilbert res = check_condition_result; 4744f0d1cf93SDouglas Gilbert goto fini; 4745f0d1cf93SDouglas Gilbert } 4746f0d1cf93SDouglas Gilbert 4747f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4748f0d1cf93SDouglas Gilbert fini: 47497109f370SDouglas Gilbert sdeb_write_unlock(sip); 4750f0d1cf93SDouglas Gilbert return res; 4751f0d1cf93SDouglas Gilbert } 4752f0d1cf93SDouglas Gilbert 4753f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4754f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4755f0d1cf93SDouglas Gilbert { 4756f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 47572d62253eSShin'ichiro Kawasaki struct sdeb_store_info *sip = devip2sip(devip, false); 4758f0d1cf93SDouglas Gilbert 4759f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4760f0d1cf93SDouglas Gilbert return; 4761f0d1cf93SDouglas Gilbert 4762f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4763f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4764f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4765f0d1cf93SDouglas Gilbert 4766f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4767f0d1cf93SDouglas Gilbert devip->nr_closed--; 4768f0d1cf93SDouglas Gilbert 47692d62253eSShin'ichiro Kawasaki if (zsp->z_wp > zsp->z_start) 47702d62253eSShin'ichiro Kawasaki memset(sip->storep + zsp->z_start * sdebug_sector_size, 0, 47712d62253eSShin'ichiro Kawasaki (zsp->z_wp - zsp->z_start) * sdebug_sector_size); 47722d62253eSShin'ichiro Kawasaki 477364e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4774f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4775f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4776f0d1cf93SDouglas Gilbert } 4777f0d1cf93SDouglas Gilbert 4778f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4779f0d1cf93SDouglas Gilbert { 4780f0d1cf93SDouglas Gilbert unsigned int i; 4781f0d1cf93SDouglas Gilbert 4782f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4783f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4784f0d1cf93SDouglas Gilbert } 4785f0d1cf93SDouglas Gilbert 4786f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4787f0d1cf93SDouglas Gilbert { 4788f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4789f0d1cf93SDouglas Gilbert int res = 0; 4790f0d1cf93SDouglas Gilbert u64 z_id; 4791f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4792f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4793b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4794f0d1cf93SDouglas Gilbert 4795f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4796f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4797f0d1cf93SDouglas Gilbert return check_condition_result; 4798f0d1cf93SDouglas Gilbert } 4799f0d1cf93SDouglas Gilbert 48007109f370SDouglas Gilbert sdeb_write_lock(sip); 4801f0d1cf93SDouglas Gilbert 4802f0d1cf93SDouglas Gilbert if (all) { 4803f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4804f0d1cf93SDouglas Gilbert goto fini; 4805f0d1cf93SDouglas Gilbert } 4806f0d1cf93SDouglas Gilbert 4807f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4808f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4809f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4810f0d1cf93SDouglas Gilbert res = check_condition_result; 4811f0d1cf93SDouglas Gilbert goto fini; 4812f0d1cf93SDouglas Gilbert } 4813f0d1cf93SDouglas Gilbert 4814f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4815f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4816f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4817f0d1cf93SDouglas Gilbert res = check_condition_result; 4818f0d1cf93SDouglas Gilbert goto fini; 4819f0d1cf93SDouglas Gilbert } 4820f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4821f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4822f0d1cf93SDouglas Gilbert res = check_condition_result; 4823f0d1cf93SDouglas Gilbert goto fini; 4824f0d1cf93SDouglas Gilbert } 4825f0d1cf93SDouglas Gilbert 4826f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4827f0d1cf93SDouglas Gilbert fini: 48287109f370SDouglas Gilbert sdeb_write_unlock(sip); 4829f0d1cf93SDouglas Gilbert return res; 4830f0d1cf93SDouglas Gilbert } 4831f0d1cf93SDouglas Gilbert 4832c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4833c4837394SDouglas Gilbert { 4834c10fa55fSJohn Garry u16 hwq; 4835a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4836c10fa55fSJohn Garry 4837c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4838c4837394SDouglas Gilbert 4839458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4840458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4841458df78bSBart Van Assche hwq = 0; 4842f7c4cdc7SJohn Garry 4843458df78bSBart Van Assche return sdebug_q_arr + hwq; 4844c4837394SDouglas Gilbert } 4845c4837394SDouglas Gilbert 4846c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4847c10fa55fSJohn Garry { 4848a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4849c10fa55fSJohn Garry } 4850c10fa55fSJohn Garry 4851c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4852fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 48531da177e4SLinus Torvalds { 48547382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4855c4837394SDouglas Gilbert int qc_idx; 4856cbf67842SDouglas Gilbert int retiring = 0; 48571da177e4SLinus Torvalds unsigned long iflags; 4858c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4859cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4860cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4861cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 48621da177e4SLinus Torvalds 48637382f9d8SDouglas Gilbert if (unlikely(aborted)) 48647382f9d8SDouglas Gilbert sd_dp->aborted = false; 4865c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4866c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4867c4837394SDouglas Gilbert if (sdebug_statistics) { 4868cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4869c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4870c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4871c4837394SDouglas Gilbert } 4872c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4873c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 48741da177e4SLinus Torvalds return; 48751da177e4SLinus Torvalds } 4876c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4877d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 4878c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4879cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4880b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4881c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4882c10fa55fSJohn Garry pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n", 4883c10fa55fSJohn Garry sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx); 48841da177e4SLinus Torvalds return; 48851da177e4SLinus Torvalds } 4886cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4887f46eb0e9SDouglas Gilbert if (likely(devip)) 4888cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4889cbf67842SDouglas Gilbert else 4890c1287970STomas Winkler pr_err("devip=NULL\n"); 4891f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4892cbf67842SDouglas Gilbert retiring = 1; 4893cbf67842SDouglas Gilbert 4894cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4895c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4896c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4897c1287970STomas Winkler pr_err("Unexpected completion\n"); 4898cbf67842SDouglas Gilbert return; 48991da177e4SLinus Torvalds } 49001da177e4SLinus Torvalds 4901cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4902cbf67842SDouglas Gilbert int k, retval; 4903cbf67842SDouglas Gilbert 4904cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4905c4837394SDouglas Gilbert if (qc_idx >= retval) { 4906c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4907c1287970STomas Winkler pr_err("index %d too large\n", retval); 4908cbf67842SDouglas Gilbert return; 4909cbf67842SDouglas Gilbert } 4910c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4911773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4912cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4913cbf67842SDouglas Gilbert else 4914cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4915cbf67842SDouglas Gilbert } 4916c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 49177382f9d8SDouglas Gilbert if (unlikely(aborted)) { 49187382f9d8SDouglas Gilbert if (sdebug_verbose) 49197382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 49207382f9d8SDouglas Gilbert return; 49217382f9d8SDouglas Gilbert } 49226c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 4923cbf67842SDouglas Gilbert } 4924cbf67842SDouglas Gilbert 4925cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4926fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4927cbf67842SDouglas Gilbert { 4928a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4929a10bc12aSDouglas Gilbert hrt); 4930a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4931cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4932cbf67842SDouglas Gilbert } 49331da177e4SLinus Torvalds 4934a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4935fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4936a10bc12aSDouglas Gilbert { 4937a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4938a10bc12aSDouglas Gilbert ew.work); 4939a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4940a10bc12aSDouglas Gilbert } 4941a10bc12aSDouglas Gilbert 494209ba24c1SDouglas Gilbert static bool got_shared_uuid; 4943bf476433SChristoph Hellwig static uuid_t shared_uuid; 494409ba24c1SDouglas Gilbert 4945f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 4946f0d1cf93SDouglas Gilbert { 4947f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4948f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 4949f0d1cf93SDouglas Gilbert sector_t zstart = 0; 4950f0d1cf93SDouglas Gilbert unsigned int i; 4951f0d1cf93SDouglas Gilbert 4952f0d1cf93SDouglas Gilbert /* 495398e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 495498e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 4955f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 4956f0d1cf93SDouglas Gilbert * created for the device. 4957f0d1cf93SDouglas Gilbert */ 495898e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 4959f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 4960f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4961f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 4962f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 4963f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 4964f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 4965f0d1cf93SDouglas Gilbert return -EINVAL; 4966f0d1cf93SDouglas Gilbert } 4967f0d1cf93SDouglas Gilbert } else { 4968108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 4969108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 4970108e36f0SDamien Le Moal return -EINVAL; 4971108e36f0SDamien Le Moal } 497298e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 4973f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4974f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 4975f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 4976f0d1cf93SDouglas Gilbert return -EINVAL; 4977f0d1cf93SDouglas Gilbert } 4978f0d1cf93SDouglas Gilbert } 4979f0d1cf93SDouglas Gilbert 4980f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 4981f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 4982f0d1cf93SDouglas Gilbert 4983aa8fecf9SDamien Le Moal if (sdeb_zbc_nr_conv >= devip->nr_zones) { 4984aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 4985aa8fecf9SDamien Le Moal return -EINVAL; 4986aa8fecf9SDamien Le Moal } 4987aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 4988aa8fecf9SDamien Le Moal 498964e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 499064e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 4991380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 4992f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 4993f0d1cf93SDouglas Gilbert else 4994380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 499564e14eceSDamien Le Moal } 4996f0d1cf93SDouglas Gilbert 4997f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 4998f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 4999f0d1cf93SDouglas Gilbert if (!devip->zstate) 5000f0d1cf93SDouglas Gilbert return -ENOMEM; 5001f0d1cf93SDouglas Gilbert 5002f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 5003f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 5004f0d1cf93SDouglas Gilbert 5005f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 5006f0d1cf93SDouglas Gilbert 5007aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 500864e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_CNV; 5009f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 5010f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 5011f0d1cf93SDouglas Gilbert } else { 501264e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 501364e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWR; 501464e14eceSDamien Le Moal else 501564e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWP; 5016f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 5017f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 5018f0d1cf93SDouglas Gilbert } 5019f0d1cf93SDouglas Gilbert 5020f0d1cf93SDouglas Gilbert if (zsp->z_start + devip->zsize < capacity) 5021f0d1cf93SDouglas Gilbert zsp->z_size = devip->zsize; 5022f0d1cf93SDouglas Gilbert else 5023f0d1cf93SDouglas Gilbert zsp->z_size = capacity - zsp->z_start; 5024f0d1cf93SDouglas Gilbert 5025f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 5026f0d1cf93SDouglas Gilbert } 5027f0d1cf93SDouglas Gilbert 5028f0d1cf93SDouglas Gilbert return 0; 5029f0d1cf93SDouglas Gilbert } 5030f0d1cf93SDouglas Gilbert 5031fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 5032fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 50335cb2fc06SFUJITA Tomonori { 50345cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 50355cb2fc06SFUJITA Tomonori 50365cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 50375cb2fc06SFUJITA Tomonori if (devip) { 503809ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 5039bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 504009ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 504109ba24c1SDouglas Gilbert if (got_shared_uuid) 504209ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 504309ba24c1SDouglas Gilbert else { 5044bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 504509ba24c1SDouglas Gilbert got_shared_uuid = true; 504609ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 504709ba24c1SDouglas Gilbert } 504809ba24c1SDouglas Gilbert } 50495cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 5050f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 505164e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 5052f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 5053f0d1cf93SDouglas Gilbert kfree(devip); 5054f0d1cf93SDouglas Gilbert return NULL; 5055f0d1cf93SDouglas Gilbert } 505664e14eceSDamien Le Moal } else { 505764e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 5058f0d1cf93SDouglas Gilbert } 5059f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 5060fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 5061fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 50625cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 50635cb2fc06SFUJITA Tomonori } 50645cb2fc06SFUJITA Tomonori return devip; 50655cb2fc06SFUJITA Tomonori } 50665cb2fc06SFUJITA Tomonori 5067f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 50681da177e4SLinus Torvalds { 50691da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 50701da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 5071f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 50721da177e4SLinus Torvalds 5073d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 50741da177e4SLinus Torvalds if (!sdbg_host) { 5075c1287970STomas Winkler pr_err("Host info NULL\n"); 50761da177e4SLinus Torvalds return NULL; 50771da177e4SLinus Torvalds } 5078ad0c7775SDouglas Gilbert 50791da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 50801da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 50811da177e4SLinus Torvalds (devip->target == sdev->id) && 50821da177e4SLinus Torvalds (devip->lun == sdev->lun)) 50831da177e4SLinus Torvalds return devip; 50841da177e4SLinus Torvalds else { 50851da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 50861da177e4SLinus Torvalds open_devip = devip; 50871da177e4SLinus Torvalds } 50881da177e4SLinus Torvalds } 50895cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 50905cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 50915cb2fc06SFUJITA Tomonori if (!open_devip) { 5092c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 50931da177e4SLinus Torvalds return NULL; 50941da177e4SLinus Torvalds } 50951da177e4SLinus Torvalds } 5096a75869d1SFUJITA Tomonori 50971da177e4SLinus Torvalds open_devip->channel = sdev->channel; 50981da177e4SLinus Torvalds open_devip->target = sdev->id; 50991da177e4SLinus Torvalds open_devip->lun = sdev->lun; 51001da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 5101cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 5102500d0d24SDouglas Gilbert set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm); 5103c2248fc9SDouglas Gilbert open_devip->used = true; 51041da177e4SLinus Torvalds return open_devip; 51051da177e4SLinus Torvalds } 51061da177e4SLinus Torvalds 51078dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 51081da177e4SLinus Torvalds { 5109773642d9SDouglas Gilbert if (sdebug_verbose) 5110c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 51118dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 51128dea0d02SFUJITA Tomonori return 0; 51138dea0d02SFUJITA Tomonori } 51141da177e4SLinus Torvalds 51158dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 51168dea0d02SFUJITA Tomonori { 5117f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5118f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5119a34c4e98SFUJITA Tomonori 5120773642d9SDouglas Gilbert if (sdebug_verbose) 5121c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 51228dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5123b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5124b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 51252aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 51262aad3cd8SDouglas Gilbert pr_info("Exit early due to deflect_incoming\n"); 51272aad3cd8SDouglas Gilbert return 1; 51282aad3cd8SDouglas Gilbert } 5129b01f6f83SDouglas Gilbert if (devip == NULL) { 5130f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5131b01f6f83SDouglas Gilbert if (devip == NULL) 51328dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5133f46eb0e9SDouglas Gilbert } 5134c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5135773642d9SDouglas Gilbert if (sdebug_no_uld) 513678d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 51379b760fd8SDouglas Gilbert config_cdb_len(sdp); 51388dea0d02SFUJITA Tomonori return 0; 51398dea0d02SFUJITA Tomonori } 51408dea0d02SFUJITA Tomonori 51418dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 51428dea0d02SFUJITA Tomonori { 51438dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 51448dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 51458dea0d02SFUJITA Tomonori 5146773642d9SDouglas Gilbert if (sdebug_verbose) 5147c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 51488dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 51498dea0d02SFUJITA Tomonori if (devip) { 515025985edcSLucas De Marchi /* make this slot available for re-use */ 5151c2248fc9SDouglas Gilbert devip->used = false; 51528dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 51538dea0d02SFUJITA Tomonori } 51548dea0d02SFUJITA Tomonori } 51558dea0d02SFUJITA Tomonori 515610bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 515710bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5158c4837394SDouglas Gilbert { 5159c4837394SDouglas Gilbert if (!sd_dp) 5160c4837394SDouglas Gilbert return; 516110bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5162c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 516310bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5164c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5165c4837394SDouglas Gilbert } 5166c4837394SDouglas Gilbert 5167a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5168a10bc12aSDouglas Gilbert returns false */ 5169a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 51708dea0d02SFUJITA Tomonori { 51718dea0d02SFUJITA Tomonori unsigned long iflags; 5172c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 517310bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5174c4837394SDouglas Gilbert struct sdebug_queue *sqp; 51758dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5176cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5177a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 51788dea0d02SFUJITA Tomonori 5179c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5180c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5181773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5182cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5183cbf67842SDouglas Gilbert if (r_qmax > qmax) 5184cbf67842SDouglas Gilbert qmax = r_qmax; 5185cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5186c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5187c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5188a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5189a10bc12aSDouglas Gilbert continue; 5190c4837394SDouglas Gilbert /* found */ 5191db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5192db525fceSDouglas Gilbert cmnd->device->hostdata; 5193db525fceSDouglas Gilbert if (devip) 5194db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5195db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5196a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 519710bde980SDouglas Gilbert if (sd_dp) { 5198d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5199d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 520010bde980SDouglas Gilbert } else 520110bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5202c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 520310bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5204c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5205a10bc12aSDouglas Gilbert return true; 52068dea0d02SFUJITA Tomonori } 5207cbf67842SDouglas Gilbert } 5208c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5209c4837394SDouglas Gilbert } 5210a10bc12aSDouglas Gilbert return false; 52118dea0d02SFUJITA Tomonori } 52128dea0d02SFUJITA Tomonori 5213a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 52142aad3cd8SDouglas Gilbert static void stop_all_queued(bool done_with_no_conn) 52158dea0d02SFUJITA Tomonori { 52168dea0d02SFUJITA Tomonori unsigned long iflags; 5217c4837394SDouglas Gilbert int j, k; 521810bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5219c4837394SDouglas Gilbert struct sdebug_queue *sqp; 52208dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5221cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5222a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 52232aad3cd8SDouglas Gilbert struct scsi_cmnd *scp; 52248dea0d02SFUJITA Tomonori 5225c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5226c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5227c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5228c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5229c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 52302aad3cd8SDouglas Gilbert scp = sqcp->a_cmnd; 52312aad3cd8SDouglas Gilbert if (!scp) 5232a10bc12aSDouglas Gilbert continue; 5233db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5234db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5235db525fceSDouglas Gilbert if (devip) 5236db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5237db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5238a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 523910bde980SDouglas Gilbert if (sd_dp) { 5240d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5241d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 524210bde980SDouglas Gilbert } else 524310bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5244c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 524510bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 52462aad3cd8SDouglas Gilbert if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) { 52472aad3cd8SDouglas Gilbert scp->result = DID_NO_CONNECT << 16; 52482aad3cd8SDouglas Gilbert scsi_done(scp); 52492aad3cd8SDouglas Gilbert } 5250c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5251c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 52528dea0d02SFUJITA Tomonori } 52538dea0d02SFUJITA Tomonori } 5254c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5255c4837394SDouglas Gilbert } 5256cbf67842SDouglas Gilbert } 5257cbf67842SDouglas Gilbert 5258cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5259cbf67842SDouglas Gilbert static void free_all_queued(void) 5260cbf67842SDouglas Gilbert { 5261c4837394SDouglas Gilbert int j, k; 5262c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5263cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5264cbf67842SDouglas Gilbert 5265c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5266c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5267c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5268a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5269a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5270cbf67842SDouglas Gilbert } 52711da177e4SLinus Torvalds } 5272c4837394SDouglas Gilbert } 52731da177e4SLinus Torvalds 52741da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 52751da177e4SLinus Torvalds { 5276a10bc12aSDouglas Gilbert bool ok; 5277a10bc12aSDouglas Gilbert 52781da177e4SLinus Torvalds ++num_aborts; 5279cbf67842SDouglas Gilbert if (SCpnt) { 5280a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5281a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5282a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5283a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5284a10bc12aSDouglas Gilbert ok ? "" : " not"); 5285cbf67842SDouglas Gilbert } 52861da177e4SLinus Torvalds return SUCCESS; 52871da177e4SLinus Torvalds } 52881da177e4SLinus Torvalds 52891da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 52901da177e4SLinus Torvalds { 52911da177e4SLinus Torvalds ++num_dev_resets; 5292cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5293cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5294f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5295f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5296cbf67842SDouglas Gilbert 5297773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5298cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 52991da177e4SLinus Torvalds if (devip) 5300cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 53011da177e4SLinus Torvalds } 53021da177e4SLinus Torvalds return SUCCESS; 53031da177e4SLinus Torvalds } 53041da177e4SLinus Torvalds 5305cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5306cbf67842SDouglas Gilbert { 5307cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5308cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5309cbf67842SDouglas Gilbert struct scsi_device *sdp; 5310cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5311cbf67842SDouglas Gilbert int k = 0; 5312cbf67842SDouglas Gilbert 5313cbf67842SDouglas Gilbert ++num_target_resets; 5314cbf67842SDouglas Gilbert if (!SCpnt) 5315cbf67842SDouglas Gilbert goto lie; 5316cbf67842SDouglas Gilbert sdp = SCpnt->device; 5317cbf67842SDouglas Gilbert if (!sdp) 5318cbf67842SDouglas Gilbert goto lie; 5319773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5320cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5321cbf67842SDouglas Gilbert hp = sdp->host; 5322cbf67842SDouglas Gilbert if (!hp) 5323cbf67842SDouglas Gilbert goto lie; 5324cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5325cbf67842SDouglas Gilbert if (sdbg_host) { 5326cbf67842SDouglas Gilbert list_for_each_entry(devip, 5327cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5328cbf67842SDouglas Gilbert dev_list) 5329cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5330cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5331cbf67842SDouglas Gilbert ++k; 5332cbf67842SDouglas Gilbert } 5333cbf67842SDouglas Gilbert } 5334773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5335cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5336cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5337cbf67842SDouglas Gilbert lie: 5338cbf67842SDouglas Gilbert return SUCCESS; 5339cbf67842SDouglas Gilbert } 5340cbf67842SDouglas Gilbert 53411da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 53421da177e4SLinus Torvalds { 53431da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5344cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 53451da177e4SLinus Torvalds struct scsi_device *sdp; 53461da177e4SLinus Torvalds struct Scsi_Host *hp; 5347cbf67842SDouglas Gilbert int k = 0; 53481da177e4SLinus Torvalds 53491da177e4SLinus Torvalds ++num_bus_resets; 5350cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5351cbf67842SDouglas Gilbert goto lie; 5352cbf67842SDouglas Gilbert sdp = SCpnt->device; 5353773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5354cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5355cbf67842SDouglas Gilbert hp = sdp->host; 5356cbf67842SDouglas Gilbert if (hp) { 5357d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 53581da177e4SLinus Torvalds if (sdbg_host) { 5359cbf67842SDouglas Gilbert list_for_each_entry(devip, 53601da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5361cbf67842SDouglas Gilbert dev_list) { 5362cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5363cbf67842SDouglas Gilbert ++k; 53641da177e4SLinus Torvalds } 53651da177e4SLinus Torvalds } 5366cbf67842SDouglas Gilbert } 5367773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5368cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5369cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5370cbf67842SDouglas Gilbert lie: 53711da177e4SLinus Torvalds return SUCCESS; 53721da177e4SLinus Torvalds } 53731da177e4SLinus Torvalds 53741da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 53751da177e4SLinus Torvalds { 53761da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5377cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5378cbf67842SDouglas Gilbert int k = 0; 53791da177e4SLinus Torvalds 53801da177e4SLinus Torvalds ++num_host_resets; 5381773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5382cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 53831da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 53841da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5385cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5386cbf67842SDouglas Gilbert dev_list) { 5387cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5388cbf67842SDouglas Gilbert ++k; 5389cbf67842SDouglas Gilbert } 53901da177e4SLinus Torvalds } 53911da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 53922aad3cd8SDouglas Gilbert stop_all_queued(false); 5393773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5394cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5395cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 53961da177e4SLinus Torvalds return SUCCESS; 53971da177e4SLinus Torvalds } 53981da177e4SLinus Torvalds 539987c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 54001da177e4SLinus Torvalds { 54011442f76dSChristoph Hellwig struct msdos_partition *pp; 5402979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 54031da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 54041da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 54051da177e4SLinus Torvalds 54061da177e4SLinus Torvalds /* assume partition table already zeroed */ 5407773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 54081da177e4SLinus Torvalds return; 5409773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5410773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5411c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 54121da177e4SLinus Torvalds } 54138c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 54141da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5415773642d9SDouglas Gilbert / sdebug_num_parts; 54161da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 54171da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5418979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5419979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 54201da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 54211da177e4SLinus Torvalds * heads_by_sects; 5422979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5423979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5424979e0dc3SJohn Pittman } 5425773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5426773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 54271da177e4SLinus Torvalds 54281da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 54291da177e4SLinus Torvalds ramp[511] = 0xAA; 54301442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 54311da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 54321da177e4SLinus Torvalds start_sec = starts[k]; 5433979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 54341da177e4SLinus Torvalds pp->boot_ind = 0; 54351da177e4SLinus Torvalds 54361da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 54371da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 54381da177e4SLinus Torvalds / sdebug_sectors_per; 54391da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 54401da177e4SLinus Torvalds 54411da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 54421da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 54431da177e4SLinus Torvalds / sdebug_sectors_per; 54441da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 54451da177e4SLinus Torvalds 5446150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5447150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 54481da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 54491da177e4SLinus Torvalds } 54501da177e4SLinus Torvalds } 54511da177e4SLinus Torvalds 54522aad3cd8SDouglas Gilbert static void sdeb_block_all_queues(void) 5453c4837394SDouglas Gilbert { 5454c4837394SDouglas Gilbert int j; 5455c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5456c4837394SDouglas Gilbert 5457c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 54582aad3cd8SDouglas Gilbert atomic_set(&sqp->blocked, (int)true); 54592aad3cd8SDouglas Gilbert } 54602aad3cd8SDouglas Gilbert 54612aad3cd8SDouglas Gilbert static void sdeb_unblock_all_queues(void) 54622aad3cd8SDouglas Gilbert { 54632aad3cd8SDouglas Gilbert int j; 54642aad3cd8SDouglas Gilbert struct sdebug_queue *sqp; 54652aad3cd8SDouglas Gilbert 54662aad3cd8SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 54672aad3cd8SDouglas Gilbert atomic_set(&sqp->blocked, (int)false); 54682aad3cd8SDouglas Gilbert } 54692aad3cd8SDouglas Gilbert 54702aad3cd8SDouglas Gilbert static void 54712aad3cd8SDouglas Gilbert sdeb_add_n_hosts(int num_hosts) 54722aad3cd8SDouglas Gilbert { 54732aad3cd8SDouglas Gilbert if (num_hosts < 1) 54742aad3cd8SDouglas Gilbert return; 54752aad3cd8SDouglas Gilbert do { 54762aad3cd8SDouglas Gilbert bool found; 54772aad3cd8SDouglas Gilbert unsigned long idx; 54782aad3cd8SDouglas Gilbert struct sdeb_store_info *sip; 54792aad3cd8SDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 54802aad3cd8SDouglas Gilbert 54812aad3cd8SDouglas Gilbert found = false; 54822aad3cd8SDouglas Gilbert if (want_phs) { 54832aad3cd8SDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) { 54842aad3cd8SDouglas Gilbert sdeb_most_recent_idx = (int)idx; 54852aad3cd8SDouglas Gilbert found = true; 54862aad3cd8SDouglas Gilbert break; 54872aad3cd8SDouglas Gilbert } 54882aad3cd8SDouglas Gilbert if (found) /* re-use case */ 54892aad3cd8SDouglas Gilbert sdebug_add_host_helper((int)idx); 54902aad3cd8SDouglas Gilbert else 54912aad3cd8SDouglas Gilbert sdebug_do_add_host(true /* make new store */); 54922aad3cd8SDouglas Gilbert } else { 54932aad3cd8SDouglas Gilbert sdebug_do_add_host(false); 54942aad3cd8SDouglas Gilbert } 54952aad3cd8SDouglas Gilbert } while (--num_hosts); 5496c4837394SDouglas Gilbert } 5497c4837394SDouglas Gilbert 5498c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5499c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5500c4837394SDouglas Gilbert */ 5501c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5502c4837394SDouglas Gilbert { 5503c4837394SDouglas Gilbert int count, modulo; 5504c4837394SDouglas Gilbert 5505c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5506c4837394SDouglas Gilbert if (modulo < 2) 5507c4837394SDouglas Gilbert return; 55082aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 5509c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5510c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 55112aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 5512c4837394SDouglas Gilbert } 5513c4837394SDouglas Gilbert 5514c4837394SDouglas Gilbert static void clear_queue_stats(void) 5515c4837394SDouglas Gilbert { 5516c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5517c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5518c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5519c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5520c4837394SDouglas Gilbert } 5521c4837394SDouglas Gilbert 55223a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5523c4837394SDouglas Gilbert { 55243a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 55253a90a63dSDouglas Gilbert return false; 55263a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5527c4837394SDouglas Gilbert } 5528c4837394SDouglas Gilbert 55292aad3cd8SDouglas Gilbert static int process_deflect_incoming(struct scsi_cmnd *scp) 55302aad3cd8SDouglas Gilbert { 55312aad3cd8SDouglas Gilbert u8 opcode = scp->cmnd[0]; 55322aad3cd8SDouglas Gilbert 55332aad3cd8SDouglas Gilbert if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16) 55342aad3cd8SDouglas Gilbert return 0; 55352aad3cd8SDouglas Gilbert return DID_NO_CONNECT << 16; 55362aad3cd8SDouglas Gilbert } 55372aad3cd8SDouglas Gilbert 5538a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5539a2aede97SDouglas Gilbert 5540c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5541c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5542c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5543c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5544c4837394SDouglas Gilbert */ 5545fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5546f66b8517SMartin Wilck int scsi_result, 55472aad3cd8SDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *), 5548f66b8517SMartin Wilck int delta_jiff, int ndelay) 55491da177e4SLinus Torvalds { 5550a2aede97SDouglas Gilbert bool new_sd_dp; 55513a90a63dSDouglas Gilbert bool inject = false; 55526ce913feSChristoph Hellwig bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED; 55533a90a63dSDouglas Gilbert int k, num_in_q, qdepth; 5554a2aede97SDouglas Gilbert unsigned long iflags; 5555a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5556c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5557c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5558299b6c07STomas Winkler struct scsi_device *sdp; 5559a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 55601da177e4SLinus Torvalds 5561b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5562b01f6f83SDouglas Gilbert if (scsi_result == 0) 5563f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5564f46eb0e9SDouglas Gilbert goto respond_in_thread; 55651da177e4SLinus Torvalds } 5566299b6c07STomas Winkler sdp = cmnd->device; 5567299b6c07STomas Winkler 55682aad3cd8SDouglas Gilbert if (delta_jiff == 0) { 55692aad3cd8SDouglas Gilbert sqp = get_queue(cmnd); 55702aad3cd8SDouglas Gilbert if (atomic_read(&sqp->blocked)) { 55712aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) 55722aad3cd8SDouglas Gilbert return process_deflect_incoming(cmnd); 55732aad3cd8SDouglas Gilbert else 55742aad3cd8SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 55752aad3cd8SDouglas Gilbert } 5576cd62b7daSDouglas Gilbert goto respond_in_thread; 55772aad3cd8SDouglas Gilbert } 55781da177e4SLinus Torvalds 5579c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5580c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5581c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5582c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 55832aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 55842aad3cd8SDouglas Gilbert scsi_result = process_deflect_incoming(cmnd); 55852aad3cd8SDouglas Gilbert goto respond_in_thread; 55862aad3cd8SDouglas Gilbert } 55872aad3cd8SDouglas Gilbert if (sdebug_verbose) 55882aad3cd8SDouglas Gilbert pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n"); 5589c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5590c4837394SDouglas Gilbert } 5591cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5592cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5593f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5594cd62b7daSDouglas Gilbert if (scsi_result) { 5595c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5596cd62b7daSDouglas Gilbert goto respond_in_thread; 5597cd62b7daSDouglas Gilbert } else 5598cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5599c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5600773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5601f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5602cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5603cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5604773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5605cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 56063a90a63dSDouglas Gilbert inject = true; 5607cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 56081da177e4SLinus Torvalds } 5609cbf67842SDouglas Gilbert } 5610cbf67842SDouglas Gilbert 5611c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5612f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5613c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5614cd62b7daSDouglas Gilbert if (scsi_result) 5615cd62b7daSDouglas Gilbert goto respond_in_thread; 5616cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5617773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 56187d5a129bSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n", 56197d5a129bSDouglas Gilbert __func__, sdebug_max_queue); 5620cd62b7daSDouglas Gilbert goto respond_in_thread; 56211da177e4SLinus Torvalds } 562274595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5623cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5624c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 56251da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5626c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5627a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5628c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5629c4b57d89SKashyap Desai 563074595c04SDouglas Gilbert if (!sd_dp) { 563110bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 563274595c04SDouglas Gilbert if (!sd_dp) { 563374595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 563474595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 563510bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 563674595c04SDouglas Gilbert } 5637a2aede97SDouglas Gilbert new_sd_dp = true; 5638a2aede97SDouglas Gilbert } else { 5639a2aede97SDouglas Gilbert new_sd_dp = false; 564010bde980SDouglas Gilbert } 5641f66b8517SMartin Wilck 5642c10fa55fSJohn Garry /* Set the hostwide tag */ 5643c10fa55fSJohn Garry if (sdebug_host_max_queue) 5644c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5645c10fa55fSJohn Garry 56466ce913feSChristoph Hellwig if (polled) 5647a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5648a2aede97SDouglas Gilbert 5649a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 56503a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5651f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5652f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5653f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5654f66b8517SMartin Wilck } 5655f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5656f66b8517SMartin Wilck cmnd->result = scsi_result; 56573a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 56583a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 56593a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 56603a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 56613a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 56623a90a63dSDouglas Gilbert } 56633a90a63dSDouglas Gilbert } 5664f66b8517SMartin Wilck 5665f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5666f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5667f66b8517SMartin Wilck __func__, cmnd->result); 5668f66b8517SMartin Wilck 566910bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5670b333a819SDouglas Gilbert ktime_t kt; 5671cbf67842SDouglas Gilbert 5672b333a819SDouglas Gilbert if (delta_jiff > 0) { 56730c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 56740c4bc91dSDouglas Gilbert 56750c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 56760c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 56770c4bc91dSDouglas Gilbert } else if (sdebug_random) { 56780c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 56790c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 56800c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 56810c4bc91dSDouglas Gilbert ns <<= 12; 56820c4bc91dSDouglas Gilbert } 56830c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 56840c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 56850c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 56860c4bc91dSDouglas Gilbert (u32)ndelay; 5687a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5688a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5689a2aede97SDouglas Gilbert 5690a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5691223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5692a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5693a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5694a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5695223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5696a2aede97SDouglas Gilbert if (new_sd_dp) 5697a2aede97SDouglas Gilbert kfree(sd_dp); 5698a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 56996c2c7d6aSBart Van Assche scsi_done(cmnd); 5700a2aede97SDouglas Gilbert return 0; 5701a2aede97SDouglas Gilbert } 5702a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5703a2aede97SDouglas Gilbert kt -= d; 5704a2aede97SDouglas Gilbert } 57050c4bc91dSDouglas Gilbert } 57066ce913feSChristoph Hellwig if (polled) { 57074a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 57084a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57094a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57104a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57114a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57124a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57134a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57144a0c6f43SDouglas Gilbert } 5715d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57164a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57174a0c6f43SDouglas Gilbert } else { 571810bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 571910bde980SDouglas Gilbert sd_dp->init_hrt = true; 5720a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5721a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5722c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5723a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5724c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5725c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5726cbf67842SDouglas Gilbert } 5727d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); 5728a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5729c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 57304a0c6f43SDouglas Gilbert } 57314a0c6f43SDouglas Gilbert if (sdebug_statistics) 57324a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 5733c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 57344a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 57354a0c6f43SDouglas Gilbert atomic_read(&sdeb_inject_pending))) 57364a0c6f43SDouglas Gilbert sd_dp->aborted = true; 57376ce913feSChristoph Hellwig if (polled) { 57384a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 57394a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57404a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57414a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57424a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57434a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57444a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57454a0c6f43SDouglas Gilbert } 5746d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57474a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57484a0c6f43SDouglas Gilbert } else { 574910bde980SDouglas Gilbert if (!sd_dp->init_wq) { 575010bde980SDouglas Gilbert sd_dp->init_wq = true; 5751a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5752c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5753c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5754a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5755cbf67842SDouglas Gilbert } 5756d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); 57574a0c6f43SDouglas Gilbert schedule_work(&sd_dp->ew.work); 57584a0c6f43SDouglas Gilbert } 5759c4837394SDouglas Gilbert if (sdebug_statistics) 5760c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 57614a0c6f43SDouglas Gilbert if (unlikely(sd_dp->aborted)) { 5762a6e76e6fSBart Van Assche sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 5763a6e76e6fSBart Van Assche scsi_cmd_to_rq(cmnd)->tag); 5764a6e76e6fSBart Van Assche blk_abort_request(scsi_cmd_to_rq(cmnd)); 57653a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 57664a0c6f43SDouglas Gilbert sd_dp->aborted = false; 57677382f9d8SDouglas Gilbert } 5768cbf67842SDouglas Gilbert } 57693a90a63dSDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result)) 57703a90a63dSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__, 57713a90a63dSDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL"); 57721da177e4SLinus Torvalds return 0; 5773cd62b7daSDouglas Gilbert 5774cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5775f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5776f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 57772aad3cd8SDouglas Gilbert if (cmnd->result == 0 && scsi_result != 0) { 5778cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 57792aad3cd8SDouglas Gilbert if (sdebug_verbose) 57802aad3cd8SDouglas Gilbert pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n", 57812aad3cd8SDouglas Gilbert blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result); 57822aad3cd8SDouglas Gilbert } 57836c2c7d6aSBart Van Assche scsi_done(cmnd); 5784cd62b7daSDouglas Gilbert return 0; 57851da177e4SLinus Torvalds } 5786cbf67842SDouglas Gilbert 578723183910SDouglas Gilbert /* Note: The following macros create attribute files in the 578823183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 578923183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 579023183910SDouglas Gilbert as it can when the corresponding attribute in the 579123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 579223183910SDouglas Gilbert */ 5793773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5794773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 57959b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5796773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5797c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5798773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5799773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5800773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5801773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5802773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5803773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5804773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5805773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5806c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5807e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5808e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5809e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5810e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 58115d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 58125d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 58135d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5814773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5815773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5816773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5817773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5818ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5819773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5820773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 58215d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 58225d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 58235d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 58245d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5825773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5826773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 58277109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR); 5828773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5829773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5830773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5831773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 58325d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5833773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 583487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 583587c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5836773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5837773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 58380c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5839773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5840773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5841773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5842c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5843773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5844c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5845c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5846fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5847773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5848773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5849773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5850773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 585109ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 58525d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5853773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 585423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 58559447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5856773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 58575b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 58589267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 5859380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5860aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 586198e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 58621da177e4SLinus Torvalds 58631da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 58641da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 58651da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5866b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 58671da177e4SLinus Torvalds 58685d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 58695b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 58709b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 58710759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5872cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5873c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 58745b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 58755b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5876c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5877beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 587823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 58795b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5880185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5881c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5882c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5883e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 58849b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 58859b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 58865d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 58875d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 58885d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 58895b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 58905b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 58915b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 58925b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5893ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5894fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5895cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5896d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 58975d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5898cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5899c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 59007109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)"); 590178d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 59021da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5903c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 590432c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 590586e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 59065d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 59075d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 59085d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5909fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 59101da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 59110c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5912d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5913760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5914ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5915c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5916c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5917c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5918fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 59195b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 59205b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 59216014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 59226014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 592309ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 592409ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5925c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 59265b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 59279447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 59285b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 59299267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 5930380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5931aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 593298e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 59331da177e4SLinus Torvalds 5934760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5935760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 59361da177e4SLinus Torvalds 59371da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 59381da177e4SLinus Torvalds { 5939c4837394SDouglas Gilbert int k; 5940c4837394SDouglas Gilbert 5941760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5942760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5943760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5944c4837394SDouglas Gilbert return sdebug_info; 5945760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5946760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5947760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5948760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 59491da177e4SLinus Torvalds return sdebug_info; 59501da177e4SLinus Torvalds } 59511da177e4SLinus Torvalds 5952cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5953fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5954fd32119bSDouglas Gilbert int length) 59551da177e4SLinus Torvalds { 59561da177e4SLinus Torvalds char arr[16]; 5957c8ed555aSAl Viro int opts; 59581da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 59591da177e4SLinus Torvalds 59601da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 59611da177e4SLinus Torvalds return -EACCES; 59621da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 59631da177e4SLinus Torvalds arr[minLen] = '\0'; 5964c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 59651da177e4SLinus Torvalds return -EINVAL; 5966773642d9SDouglas Gilbert sdebug_opts = opts; 5967773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5968773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5969773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5970c4837394SDouglas Gilbert tweak_cmnd_count(); 59711da177e4SLinus Torvalds return length; 59721da177e4SLinus Torvalds } 5973c8ed555aSAl Viro 5974cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5975cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5976cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5977c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5978c8ed555aSAl Viro { 5979c4837394SDouglas Gilbert int f, j, l; 5980c4837394SDouglas Gilbert struct sdebug_queue *sqp; 598187c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5982cbf67842SDouglas Gilbert 5983c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5984c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5985c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5986c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5987c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 5988c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 5989c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 5990c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 5991c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 5992c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 5993c4837394SDouglas Gilbert num_aborts); 5994c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 5995c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 5996c4837394SDouglas Gilbert num_host_resets); 5997c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 5998c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 5999458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 6000458df78bSBart Van Assche sdebug_statistics); 60014a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 6002c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 6003c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 6004c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 60054a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 60064a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 6007cbf67842SDouglas Gilbert 6008c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 6009c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 6010c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 6011c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 6012773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 6013c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 6014c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 6015c4837394SDouglas Gilbert "first,last bits", f, l); 6016c4837394SDouglas Gilbert } 6017cbf67842SDouglas Gilbert } 601887c715dcSDouglas Gilbert 601987c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 602087c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 602187c715dcSDouglas Gilbert bool niu; 602287c715dcSDouglas Gilbert int idx; 602387c715dcSDouglas Gilbert unsigned long l_idx; 602487c715dcSDouglas Gilbert struct sdeb_store_info *sip; 602587c715dcSDouglas Gilbert 602687c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 602787c715dcSDouglas Gilbert j = 0; 602887c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 602987c715dcSDouglas Gilbert idx = sdhp->si_idx; 603087c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 603187c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 603287c715dcSDouglas Gilbert ++j; 603387c715dcSDouglas Gilbert } 603487c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 603587c715dcSDouglas Gilbert sdeb_most_recent_idx); 603687c715dcSDouglas Gilbert j = 0; 603787c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 603887c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 603987c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 604087c715dcSDouglas Gilbert idx = (int)l_idx; 604187c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 604287c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 604387c715dcSDouglas Gilbert ++j; 604487c715dcSDouglas Gilbert } 604587c715dcSDouglas Gilbert } 6046c8ed555aSAl Viro return 0; 60471da177e4SLinus Torvalds } 60481da177e4SLinus Torvalds 604982069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 60501da177e4SLinus Torvalds { 6051c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 60521da177e4SLinus Torvalds } 6053c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 6054c4837394SDouglas Gilbert * of delay is jiffies. 6055c4837394SDouglas Gilbert */ 605682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 605782069379SAkinobu Mita size_t count) 60581da177e4SLinus Torvalds { 6059c2206098SDouglas Gilbert int jdelay, res; 60601da177e4SLinus Torvalds 6061b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 6062cbf67842SDouglas Gilbert res = count; 6063c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 6064c4837394SDouglas Gilbert int j, k; 6065c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6066cbf67842SDouglas Gilbert 60672aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 6068c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6069c4837394SDouglas Gilbert ++j, ++sqp) { 6070c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6071c4837394SDouglas Gilbert sdebug_max_queue); 6072c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6073c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6074c4837394SDouglas Gilbert break; 6075c4837394SDouglas Gilbert } 6076c4837394SDouglas Gilbert } 6077c4837394SDouglas Gilbert if (res > 0) { 6078c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 6079773642d9SDouglas Gilbert sdebug_ndelay = 0; 60801da177e4SLinus Torvalds } 60812aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 6082cbf67842SDouglas Gilbert } 6083cbf67842SDouglas Gilbert return res; 60841da177e4SLinus Torvalds } 60851da177e4SLinus Torvalds return -EINVAL; 60861da177e4SLinus Torvalds } 608782069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 60881da177e4SLinus Torvalds 6089cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 6090cbf67842SDouglas Gilbert { 6091773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 6092cbf67842SDouglas Gilbert } 6093cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 6094c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 6095cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 6096cbf67842SDouglas Gilbert size_t count) 6097cbf67842SDouglas Gilbert { 6098c4837394SDouglas Gilbert int ndelay, res; 6099cbf67842SDouglas Gilbert 6100cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 6101c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 6102cbf67842SDouglas Gilbert res = count; 6103773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 6104c4837394SDouglas Gilbert int j, k; 6105c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6106c4837394SDouglas Gilbert 61072aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 6108c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6109c4837394SDouglas Gilbert ++j, ++sqp) { 6110c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6111c4837394SDouglas Gilbert sdebug_max_queue); 6112c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6113c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6114c4837394SDouglas Gilbert break; 6115c4837394SDouglas Gilbert } 6116c4837394SDouglas Gilbert } 6117c4837394SDouglas Gilbert if (res > 0) { 6118773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 6119c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 6120c2206098SDouglas Gilbert : DEF_JDELAY; 6121cbf67842SDouglas Gilbert } 61222aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 6123cbf67842SDouglas Gilbert } 6124cbf67842SDouglas Gilbert return res; 6125cbf67842SDouglas Gilbert } 6126cbf67842SDouglas Gilbert return -EINVAL; 6127cbf67842SDouglas Gilbert } 6128cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 6129cbf67842SDouglas Gilbert 613082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 61311da177e4SLinus Torvalds { 6132773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 61331da177e4SLinus Torvalds } 61341da177e4SLinus Torvalds 613582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 613682069379SAkinobu Mita size_t count) 61371da177e4SLinus Torvalds { 61381da177e4SLinus Torvalds int opts; 61391da177e4SLinus Torvalds char work[20]; 61401da177e4SLinus Torvalds 61419a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 61429a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 61439a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 61441da177e4SLinus Torvalds goto opts_done; 61451da177e4SLinus Torvalds } else { 61469a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 61471da177e4SLinus Torvalds goto opts_done; 61481da177e4SLinus Torvalds } 61491da177e4SLinus Torvalds } 61501da177e4SLinus Torvalds return -EINVAL; 61511da177e4SLinus Torvalds opts_done: 6152773642d9SDouglas Gilbert sdebug_opts = opts; 6153773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 6154773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 6155c4837394SDouglas Gilbert tweak_cmnd_count(); 61561da177e4SLinus Torvalds return count; 61571da177e4SLinus Torvalds } 615882069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 61591da177e4SLinus Torvalds 616082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 61611da177e4SLinus Torvalds { 6162773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 61631da177e4SLinus Torvalds } 616482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 616582069379SAkinobu Mita size_t count) 61661da177e4SLinus Torvalds { 61671da177e4SLinus Torvalds int n; 61681da177e4SLinus Torvalds 6169f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 6170f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 6171f0d1cf93SDouglas Gilbert return -EINVAL; 6172f0d1cf93SDouglas Gilbert 61731da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6174f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 6175f0d1cf93SDouglas Gilbert return -EINVAL; 6176773642d9SDouglas Gilbert sdebug_ptype = n; 61771da177e4SLinus Torvalds return count; 61781da177e4SLinus Torvalds } 61791da177e4SLinus Torvalds return -EINVAL; 61801da177e4SLinus Torvalds } 618182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 61821da177e4SLinus Torvalds 618382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 61841da177e4SLinus Torvalds { 6185773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 61861da177e4SLinus Torvalds } 618782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 618882069379SAkinobu Mita size_t count) 61891da177e4SLinus Torvalds { 61901da177e4SLinus Torvalds int n; 61911da177e4SLinus Torvalds 61921da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6193773642d9SDouglas Gilbert sdebug_dsense = n; 61941da177e4SLinus Torvalds return count; 61951da177e4SLinus Torvalds } 61961da177e4SLinus Torvalds return -EINVAL; 61971da177e4SLinus Torvalds } 619882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 61991da177e4SLinus Torvalds 620082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 620123183910SDouglas Gilbert { 6202773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 620323183910SDouglas Gilbert } 620482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 620582069379SAkinobu Mita size_t count) 620623183910SDouglas Gilbert { 620787c715dcSDouglas Gilbert int n, idx; 620823183910SDouglas Gilbert 620923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 621087c715dcSDouglas Gilbert bool want_store = (n == 0); 621187c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 621287c715dcSDouglas Gilbert 6213cbf67842SDouglas Gilbert n = (n > 0); 6214773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 621587c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 621687c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6217cbf67842SDouglas Gilbert 621887c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 621987c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 622087c715dcSDouglas Gilbert idx = sdebug_add_store(); 622187c715dcSDouglas Gilbert if (idx < 0) 622287c715dcSDouglas Gilbert return idx; 622387c715dcSDouglas Gilbert } else { 622487c715dcSDouglas Gilbert idx = sdeb_first_idx; 622587c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 622687c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6227cbf67842SDouglas Gilbert } 622887c715dcSDouglas Gilbert /* make all hosts use same store */ 622987c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 623087c715dcSDouglas Gilbert host_list) { 623187c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 623287c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 623387c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 623487c715dcSDouglas Gilbert sdhp->si_idx = idx; 623587c715dcSDouglas Gilbert } 623687c715dcSDouglas Gilbert } 623787c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 623887c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 623987c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6240cbf67842SDouglas Gilbert } 6241773642d9SDouglas Gilbert sdebug_fake_rw = n; 624223183910SDouglas Gilbert return count; 624323183910SDouglas Gilbert } 624423183910SDouglas Gilbert return -EINVAL; 624523183910SDouglas Gilbert } 624682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 624723183910SDouglas Gilbert 624882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6249c65b1445SDouglas Gilbert { 6250773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6251c65b1445SDouglas Gilbert } 625282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 625382069379SAkinobu Mita size_t count) 6254c65b1445SDouglas Gilbert { 6255c65b1445SDouglas Gilbert int n; 6256c65b1445SDouglas Gilbert 6257c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6258773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6259c65b1445SDouglas Gilbert return count; 6260c65b1445SDouglas Gilbert } 6261c65b1445SDouglas Gilbert return -EINVAL; 6262c65b1445SDouglas Gilbert } 626382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6264c65b1445SDouglas Gilbert 626582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 62661da177e4SLinus Torvalds { 6267773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 62681da177e4SLinus Torvalds } 626982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 627082069379SAkinobu Mita size_t count) 62711da177e4SLinus Torvalds { 62721da177e4SLinus Torvalds int n; 62731da177e4SLinus Torvalds 62741da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6275773642d9SDouglas Gilbert sdebug_num_tgts = n; 62761da177e4SLinus Torvalds sdebug_max_tgts_luns(); 62771da177e4SLinus Torvalds return count; 62781da177e4SLinus Torvalds } 62791da177e4SLinus Torvalds return -EINVAL; 62801da177e4SLinus Torvalds } 628182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 62821da177e4SLinus Torvalds 628382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 62841da177e4SLinus Torvalds { 6285773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 62861da177e4SLinus Torvalds } 628782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 62881da177e4SLinus Torvalds 628987c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 629087c715dcSDouglas Gilbert { 629187c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 629287c715dcSDouglas Gilbert } 629387c715dcSDouglas Gilbert 629487c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 629587c715dcSDouglas Gilbert size_t count) 629687c715dcSDouglas Gilbert { 629787c715dcSDouglas Gilbert bool v; 629887c715dcSDouglas Gilbert 629987c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 630087c715dcSDouglas Gilbert return -EINVAL; 630187c715dcSDouglas Gilbert 630287c715dcSDouglas Gilbert sdebug_per_host_store = v; 630387c715dcSDouglas Gilbert return count; 630487c715dcSDouglas Gilbert } 630587c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 630687c715dcSDouglas Gilbert 630782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 63081da177e4SLinus Torvalds { 6309773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 63101da177e4SLinus Torvalds } 631182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 63121da177e4SLinus Torvalds 631382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 63141da177e4SLinus Torvalds { 6315773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 63161da177e4SLinus Torvalds } 631782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 631882069379SAkinobu Mita size_t count) 63191da177e4SLinus Torvalds { 63201da177e4SLinus Torvalds int nth; 63213a90a63dSDouglas Gilbert char work[20]; 63221da177e4SLinus Torvalds 63233a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 63243a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 63253a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 63263a90a63dSDouglas Gilbert goto every_nth_done; 63273a90a63dSDouglas Gilbert } else { 63283a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 63293a90a63dSDouglas Gilbert goto every_nth_done; 63303a90a63dSDouglas Gilbert } 63313a90a63dSDouglas Gilbert } 63323a90a63dSDouglas Gilbert return -EINVAL; 63333a90a63dSDouglas Gilbert 63343a90a63dSDouglas Gilbert every_nth_done: 6335773642d9SDouglas Gilbert sdebug_every_nth = nth; 6336c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6337c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6338c4837394SDouglas Gilbert sdebug_statistics = true; 6339c4837394SDouglas Gilbert } 6340c4837394SDouglas Gilbert tweak_cmnd_count(); 63411da177e4SLinus Torvalds return count; 63421da177e4SLinus Torvalds } 634382069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 63441da177e4SLinus Torvalds 6345ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6346ad0c7775SDouglas Gilbert { 6347ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6348ad0c7775SDouglas Gilbert } 6349ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6350ad0c7775SDouglas Gilbert size_t count) 6351ad0c7775SDouglas Gilbert { 6352ad0c7775SDouglas Gilbert int n; 6353ad0c7775SDouglas Gilbert bool changed; 6354ad0c7775SDouglas Gilbert 6355ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6356ad0c7775SDouglas Gilbert return -EINVAL; 6357ad0c7775SDouglas Gilbert if (n >= 0) { 6358ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6359ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6360ad0c7775SDouglas Gilbert return -EINVAL; 6361ad0c7775SDouglas Gilbert } 6362ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6363ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6364ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6365ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6366ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6367ad0c7775SDouglas Gilbert 6368ad0c7775SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 6369ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6370ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6371ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6372ad0c7775SDouglas Gilbert } 6373ad0c7775SDouglas Gilbert } 6374ad0c7775SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 6375ad0c7775SDouglas Gilbert } 6376ad0c7775SDouglas Gilbert return count; 6377ad0c7775SDouglas Gilbert } 6378ad0c7775SDouglas Gilbert return -EINVAL; 6379ad0c7775SDouglas Gilbert } 6380ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6381ad0c7775SDouglas Gilbert 638282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 63831da177e4SLinus Torvalds { 6384773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 63851da177e4SLinus Torvalds } 638682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 638782069379SAkinobu Mita size_t count) 63881da177e4SLinus Torvalds { 63891da177e4SLinus Torvalds int n; 639019c8ead7SEwan D. Milne bool changed; 63911da177e4SLinus Torvalds 63921da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 63938d039e22SDouglas Gilbert if (n > 256) { 63948d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 63958d039e22SDouglas Gilbert return -EINVAL; 63968d039e22SDouglas Gilbert } 6397773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6398773642d9SDouglas Gilbert sdebug_max_luns = n; 63991da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6400773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 640119c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 640219c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 640319c8ead7SEwan D. Milne 640419c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 640519c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 640619c8ead7SEwan D. Milne host_list) { 640719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 640819c8ead7SEwan D. Milne dev_list) { 640919c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 641019c8ead7SEwan D. Milne dp->uas_bm); 641119c8ead7SEwan D. Milne } 641219c8ead7SEwan D. Milne } 641319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 641419c8ead7SEwan D. Milne } 64151da177e4SLinus Torvalds return count; 64161da177e4SLinus Torvalds } 64171da177e4SLinus Torvalds return -EINVAL; 64181da177e4SLinus Torvalds } 641982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 64201da177e4SLinus Torvalds 642182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 642278d4e5a0SDouglas Gilbert { 6423773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 642478d4e5a0SDouglas Gilbert } 6425cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6426cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 642782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 642882069379SAkinobu Mita size_t count) 642978d4e5a0SDouglas Gilbert { 6430c4837394SDouglas Gilbert int j, n, k, a; 6431c4837394SDouglas Gilbert struct sdebug_queue *sqp; 643278d4e5a0SDouglas Gilbert 643378d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6434c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6435c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 64362aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 6437c4837394SDouglas Gilbert k = 0; 6438c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6439c4837394SDouglas Gilbert ++j, ++sqp) { 6440c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6441c4837394SDouglas Gilbert if (a > k) 6442c4837394SDouglas Gilbert k = a; 6443c4837394SDouglas Gilbert } 6444773642d9SDouglas Gilbert sdebug_max_queue = n; 6445c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6446cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6447cbf67842SDouglas Gilbert else if (k >= n) 6448cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6449cbf67842SDouglas Gilbert else 6450cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 64512aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 645278d4e5a0SDouglas Gilbert return count; 645378d4e5a0SDouglas Gilbert } 645478d4e5a0SDouglas Gilbert return -EINVAL; 645578d4e5a0SDouglas Gilbert } 645682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 645778d4e5a0SDouglas Gilbert 6458c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6459c10fa55fSJohn Garry { 6460c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6461c10fa55fSJohn Garry } 6462c10fa55fSJohn Garry 64637109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf) 64647109f370SDouglas Gilbert { 64657109f370SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock); 64667109f370SDouglas Gilbert } 64677109f370SDouglas Gilbert 64687109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count) 64697109f370SDouglas Gilbert { 64707109f370SDouglas Gilbert bool v; 64717109f370SDouglas Gilbert 64727109f370SDouglas Gilbert if (kstrtobool(buf, &v)) 64737109f370SDouglas Gilbert return -EINVAL; 64747109f370SDouglas Gilbert 64757109f370SDouglas Gilbert sdebug_no_rwlock = v; 64767109f370SDouglas Gilbert return count; 64777109f370SDouglas Gilbert } 64787109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock); 64797109f370SDouglas Gilbert 6480c10fa55fSJohn Garry /* 6481c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6482c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6483c10fa55fSJohn Garry */ 6484c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6485c10fa55fSJohn Garry 648682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 648778d4e5a0SDouglas Gilbert { 6488773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 648978d4e5a0SDouglas Gilbert } 649082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 649178d4e5a0SDouglas Gilbert 649282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 64931da177e4SLinus Torvalds { 6494773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 64951da177e4SLinus Torvalds } 649682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 64971da177e4SLinus Torvalds 649882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6499c65b1445SDouglas Gilbert { 6500773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6501c65b1445SDouglas Gilbert } 650282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 650382069379SAkinobu Mita size_t count) 6504c65b1445SDouglas Gilbert { 6505c65b1445SDouglas Gilbert int n; 65060d01c5dfSDouglas Gilbert bool changed; 6507c65b1445SDouglas Gilbert 6508f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6509f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6510f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6511f0d1cf93SDouglas Gilbert 6512c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6513773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6514773642d9SDouglas Gilbert sdebug_virtual_gb = n; 651528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 65160d01c5dfSDouglas Gilbert if (changed) { 65170d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 65180d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 651928898873SFUJITA Tomonori 65204bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 65210d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 65220d01c5dfSDouglas Gilbert host_list) { 65230d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 65240d01c5dfSDouglas Gilbert dev_list) { 65250d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 65260d01c5dfSDouglas Gilbert dp->uas_bm); 65270d01c5dfSDouglas Gilbert } 65280d01c5dfSDouglas Gilbert } 65294bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 65300d01c5dfSDouglas Gilbert } 6531c65b1445SDouglas Gilbert return count; 6532c65b1445SDouglas Gilbert } 6533c65b1445SDouglas Gilbert return -EINVAL; 6534c65b1445SDouglas Gilbert } 653582069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6536c65b1445SDouglas Gilbert 653782069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 65381da177e4SLinus Torvalds { 653987c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 65402aad3cd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts)); 65411da177e4SLinus Torvalds } 65421da177e4SLinus Torvalds 65432aad3cd8SDouglas Gilbert /* 65442aad3cd8SDouglas Gilbert * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'. 65452aad3cd8SDouglas Gilbert * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing. 65462aad3cd8SDouglas Gilbert * Returns -EBUSY if another add_host sysfs invocation is active. 65472aad3cd8SDouglas Gilbert */ 654882069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 654982069379SAkinobu Mita size_t count) 65501da177e4SLinus Torvalds { 65511da177e4SLinus Torvalds int delta_hosts; 65521da177e4SLinus Torvalds 65532aad3cd8SDouglas Gilbert if (count == 0 || kstrtoint(buf, 0, &delta_hosts)) 65541da177e4SLinus Torvalds return -EINVAL; 65552aad3cd8SDouglas Gilbert if (sdebug_verbose) 65562aad3cd8SDouglas Gilbert pr_info("prior num_hosts=%d, num_to_add=%d\n", 65572aad3cd8SDouglas Gilbert atomic_read(&sdebug_num_hosts), delta_hosts); 65582aad3cd8SDouglas Gilbert if (delta_hosts == 0) 65592aad3cd8SDouglas Gilbert return count; 65602aad3cd8SDouglas Gilbert if (mutex_trylock(&add_host_mutex) == 0) 65612aad3cd8SDouglas Gilbert return -EBUSY; 65621da177e4SLinus Torvalds if (delta_hosts > 0) { 65632aad3cd8SDouglas Gilbert sdeb_add_n_hosts(delta_hosts); 65642aad3cd8SDouglas Gilbert } else if (delta_hosts < 0) { 65652aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, true); 65662aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 65672aad3cd8SDouglas Gilbert if (delta_hosts >= atomic_read(&sdebug_num_hosts)) 65682aad3cd8SDouglas Gilbert stop_all_queued(true); 65691da177e4SLinus Torvalds do { 65702aad3cd8SDouglas Gilbert if (atomic_read(&sdebug_num_hosts) < 1) { 65712aad3cd8SDouglas Gilbert free_all_queued(); 657287c715dcSDouglas Gilbert break; 657387c715dcSDouglas Gilbert } 657487c715dcSDouglas Gilbert sdebug_do_remove_host(false); 65751da177e4SLinus Torvalds } while (++delta_hosts); 65762aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 65772aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, false); 65781da177e4SLinus Torvalds } 65792aad3cd8SDouglas Gilbert mutex_unlock(&add_host_mutex); 65802aad3cd8SDouglas Gilbert if (sdebug_verbose) 65812aad3cd8SDouglas Gilbert pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts)); 65821da177e4SLinus Torvalds return count; 65831da177e4SLinus Torvalds } 658482069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 65851da177e4SLinus Torvalds 658682069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 658723183910SDouglas Gilbert { 6588773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 658923183910SDouglas Gilbert } 659082069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 659182069379SAkinobu Mita size_t count) 659223183910SDouglas Gilbert { 659323183910SDouglas Gilbert int n; 659423183910SDouglas Gilbert 659523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6596773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 659723183910SDouglas Gilbert return count; 659823183910SDouglas Gilbert } 659923183910SDouglas Gilbert return -EINVAL; 660023183910SDouglas Gilbert } 660182069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 660223183910SDouglas Gilbert 6603c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6604c4837394SDouglas Gilbert { 6605c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6606c4837394SDouglas Gilbert } 6607c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6608c4837394SDouglas Gilbert size_t count) 6609c4837394SDouglas Gilbert { 6610c4837394SDouglas Gilbert int n; 6611c4837394SDouglas Gilbert 6612c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6613c4837394SDouglas Gilbert if (n > 0) 6614c4837394SDouglas Gilbert sdebug_statistics = true; 6615c4837394SDouglas Gilbert else { 6616c4837394SDouglas Gilbert clear_queue_stats(); 6617c4837394SDouglas Gilbert sdebug_statistics = false; 6618c4837394SDouglas Gilbert } 6619c4837394SDouglas Gilbert return count; 6620c4837394SDouglas Gilbert } 6621c4837394SDouglas Gilbert return -EINVAL; 6622c4837394SDouglas Gilbert } 6623c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6624c4837394SDouglas Gilbert 662582069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6626597136abSMartin K. Petersen { 6627773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6628597136abSMartin K. Petersen } 662982069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6630597136abSMartin K. Petersen 6631c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6632c4837394SDouglas Gilbert { 6633c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6634c4837394SDouglas Gilbert } 6635c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6636c4837394SDouglas Gilbert 663782069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6638c6a44287SMartin K. Petersen { 6639773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6640c6a44287SMartin K. Petersen } 664182069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6642c6a44287SMartin K. Petersen 664382069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6644c6a44287SMartin K. Petersen { 6645773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6646c6a44287SMartin K. Petersen } 664782069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6648c6a44287SMartin K. Petersen 664982069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6650c6a44287SMartin K. Petersen { 6651773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6652c6a44287SMartin K. Petersen } 665382069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6654c6a44287SMartin K. Petersen 665582069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6656c6a44287SMartin K. Petersen { 6657773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6658c6a44287SMartin K. Petersen } 665982069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6660c6a44287SMartin K. Petersen 666182069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 666244d92694SMartin K. Petersen { 666387c715dcSDouglas Gilbert ssize_t count = 0; 666444d92694SMartin K. Petersen 66655b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 666644d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 666744d92694SMartin K. Petersen sdebug_store_sectors); 666844d92694SMartin K. Petersen 666987c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 667087c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 667187c715dcSDouglas Gilbert 667287c715dcSDouglas Gilbert if (sip) 6673c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 667487c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 667587c715dcSDouglas Gilbert } 667644d92694SMartin K. Petersen buf[count++] = '\n'; 6677c7badc90STejun Heo buf[count] = '\0'; 667844d92694SMartin K. Petersen 667944d92694SMartin K. Petersen return count; 668044d92694SMartin K. Petersen } 668182069379SAkinobu Mita static DRIVER_ATTR_RO(map); 668244d92694SMartin K. Petersen 66830c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 66840c4bc91dSDouglas Gilbert { 66850c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 66860c4bc91dSDouglas Gilbert } 66870c4bc91dSDouglas Gilbert 66880c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 66890c4bc91dSDouglas Gilbert size_t count) 66900c4bc91dSDouglas Gilbert { 66910c4bc91dSDouglas Gilbert bool v; 66920c4bc91dSDouglas Gilbert 66930c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 66940c4bc91dSDouglas Gilbert return -EINVAL; 66950c4bc91dSDouglas Gilbert 66960c4bc91dSDouglas Gilbert sdebug_random = v; 66970c4bc91dSDouglas Gilbert return count; 66980c4bc91dSDouglas Gilbert } 66990c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 67000c4bc91dSDouglas Gilbert 670182069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6702d986788bSMartin Pitt { 6703773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6704d986788bSMartin Pitt } 670582069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 670682069379SAkinobu Mita size_t count) 6707d986788bSMartin Pitt { 6708d986788bSMartin Pitt int n; 6709d986788bSMartin Pitt 6710d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6711773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6712d986788bSMartin Pitt return count; 6713d986788bSMartin Pitt } 6714d986788bSMartin Pitt return -EINVAL; 6715d986788bSMartin Pitt } 671682069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6717d986788bSMartin Pitt 6718cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6719cbf67842SDouglas Gilbert { 6720773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6721cbf67842SDouglas Gilbert } 6722185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6723cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6724cbf67842SDouglas Gilbert size_t count) 6725cbf67842SDouglas Gilbert { 6726185dd232SDouglas Gilbert int n; 6727cbf67842SDouglas Gilbert 6728cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6729185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6730185dd232SDouglas Gilbert return count; 6731cbf67842SDouglas Gilbert } 6732cbf67842SDouglas Gilbert return -EINVAL; 6733cbf67842SDouglas Gilbert } 6734cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6735cbf67842SDouglas Gilbert 6736c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6737c2248fc9SDouglas Gilbert { 6738773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6739c2248fc9SDouglas Gilbert } 6740c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6741c2248fc9SDouglas Gilbert size_t count) 6742c2248fc9SDouglas Gilbert { 6743c2248fc9SDouglas Gilbert int n; 6744c2248fc9SDouglas Gilbert 6745c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6746773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6747c2248fc9SDouglas Gilbert return count; 6748c2248fc9SDouglas Gilbert } 6749c2248fc9SDouglas Gilbert return -EINVAL; 6750c2248fc9SDouglas Gilbert } 6751c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6752c2248fc9SDouglas Gilbert 675309ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 675409ba24c1SDouglas Gilbert { 675509ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 675609ba24c1SDouglas Gilbert } 675709ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 675809ba24c1SDouglas Gilbert 67599b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 67609b760fd8SDouglas Gilbert { 67619b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 67629b760fd8SDouglas Gilbert } 67639b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 67649b760fd8SDouglas Gilbert size_t count) 67659b760fd8SDouglas Gilbert { 67669b760fd8SDouglas Gilbert int ret, n; 67679b760fd8SDouglas Gilbert 67689b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 67699b760fd8SDouglas Gilbert if (ret) 67709b760fd8SDouglas Gilbert return ret; 67719b760fd8SDouglas Gilbert sdebug_cdb_len = n; 67729b760fd8SDouglas Gilbert all_config_cdb_len(); 67739b760fd8SDouglas Gilbert return count; 67749b760fd8SDouglas Gilbert } 67759b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 67769b760fd8SDouglas Gilbert 67779267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 67789267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 67799267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 67809267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 67819267e0ebSDouglas Gilbert }; 67829267e0ebSDouglas Gilbert 67839267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 67849267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 67859267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 67869267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 67879267e0ebSDouglas Gilbert }; 67889267e0ebSDouglas Gilbert 67899267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 67909267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 67919267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 67929267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 67939267e0ebSDouglas Gilbert }; 67949267e0ebSDouglas Gilbert 67959267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 67969267e0ebSDouglas Gilbert { 67979267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 67989267e0ebSDouglas Gilbert 67999267e0ebSDouglas Gilbert if (res < 0) { 68009267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 68019267e0ebSDouglas Gilbert if (res < 0) { 68029267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 680347742bdeSDan Carpenter if (res < 0) 68049267e0ebSDouglas Gilbert return -EINVAL; 68059267e0ebSDouglas Gilbert } 68069267e0ebSDouglas Gilbert } 68079267e0ebSDouglas Gilbert return res; 68089267e0ebSDouglas Gilbert } 68099267e0ebSDouglas Gilbert 68109267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 68119267e0ebSDouglas Gilbert { 68129267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 68139267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 68149267e0ebSDouglas Gilbert } 68159267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6816cbf67842SDouglas Gilbert 6817fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6818fc13638aSDouglas Gilbert { 6819fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6820fc13638aSDouglas Gilbert } 6821fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6822fc13638aSDouglas Gilbert 682382069379SAkinobu Mita /* Note: The following array creates attribute files in the 682423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 682523183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 682623183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 682787c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 682823183910SDouglas Gilbert */ 68296ecaff7fSRandy Dunlap 683082069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 683182069379SAkinobu Mita &driver_attr_delay.attr, 683282069379SAkinobu Mita &driver_attr_opts.attr, 683382069379SAkinobu Mita &driver_attr_ptype.attr, 683482069379SAkinobu Mita &driver_attr_dsense.attr, 683582069379SAkinobu Mita &driver_attr_fake_rw.attr, 6836c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 683782069379SAkinobu Mita &driver_attr_no_lun_0.attr, 683882069379SAkinobu Mita &driver_attr_num_tgts.attr, 683982069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 684082069379SAkinobu Mita &driver_attr_num_parts.attr, 684182069379SAkinobu Mita &driver_attr_every_nth.attr, 6842ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 684382069379SAkinobu Mita &driver_attr_max_luns.attr, 684482069379SAkinobu Mita &driver_attr_max_queue.attr, 68457109f370SDouglas Gilbert &driver_attr_no_rwlock.attr, 684682069379SAkinobu Mita &driver_attr_no_uld.attr, 684782069379SAkinobu Mita &driver_attr_scsi_level.attr, 684882069379SAkinobu Mita &driver_attr_virtual_gb.attr, 684982069379SAkinobu Mita &driver_attr_add_host.attr, 685087c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 685182069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 685282069379SAkinobu Mita &driver_attr_sector_size.attr, 6853c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6854c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 685582069379SAkinobu Mita &driver_attr_dix.attr, 685682069379SAkinobu Mita &driver_attr_dif.attr, 685782069379SAkinobu Mita &driver_attr_guard.attr, 685882069379SAkinobu Mita &driver_attr_ato.attr, 685982069379SAkinobu Mita &driver_attr_map.attr, 68600c4bc91dSDouglas Gilbert &driver_attr_random.attr, 686182069379SAkinobu Mita &driver_attr_removable.attr, 6862cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6863cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6864c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 686509ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 68669b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6867fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 68689267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 686982069379SAkinobu Mita NULL, 687082069379SAkinobu Mita }; 687182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 68721da177e4SLinus Torvalds 687311ddcecaSAkinobu Mita static struct device *pseudo_primary; 68748dea0d02SFUJITA Tomonori 68751da177e4SLinus Torvalds static int __init scsi_debug_init(void) 68761da177e4SLinus Torvalds { 687787c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 68785f2578e5SFUJITA Tomonori unsigned long sz; 687987c715dcSDouglas Gilbert int k, ret, hosts_to_add; 688087c715dcSDouglas Gilbert int idx = -1; 68811da177e4SLinus Torvalds 688287c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 688387c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6884cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6885cbf67842SDouglas Gilbert 6886773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6887c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6888773642d9SDouglas Gilbert sdebug_ndelay = 0; 6889773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6890c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6891cbf67842SDouglas Gilbert 6892773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6893597136abSMartin K. Petersen case 512: 6894597136abSMartin K. Petersen case 1024: 6895597136abSMartin K. Petersen case 2048: 6896597136abSMartin K. Petersen case 4096: 6897597136abSMartin K. Petersen break; 6898597136abSMartin K. Petersen default: 6899773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6900597136abSMartin K. Petersen return -EINVAL; 6901597136abSMartin K. Petersen } 6902597136abSMartin K. Petersen 6903773642d9SDouglas Gilbert switch (sdebug_dif) { 69048475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6905f46eb0e9SDouglas Gilbert break; 69068475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 69078475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 69088475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6909f46eb0e9SDouglas Gilbert have_dif_prot = true; 6910c6a44287SMartin K. Petersen break; 6911c6a44287SMartin K. Petersen 6912c6a44287SMartin K. Petersen default: 6913c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6914c6a44287SMartin K. Petersen return -EINVAL; 6915c6a44287SMartin K. Petersen } 6916c6a44287SMartin K. Petersen 6917aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6918aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6919aa5334c4SMaurizio Lombardi return -EINVAL; 6920aa5334c4SMaurizio Lombardi } 6921aa5334c4SMaurizio Lombardi 6922773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6923c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6924c6a44287SMartin K. Petersen return -EINVAL; 6925c6a44287SMartin K. Petersen } 6926c6a44287SMartin K. Petersen 6927773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6928c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6929c6a44287SMartin K. Petersen return -EINVAL; 6930c6a44287SMartin K. Petersen } 6931c6a44287SMartin K. Petersen 6932773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6933773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6934ea61fca5SMartin K. Petersen return -EINVAL; 6935ea61fca5SMartin K. Petersen } 6936ad0c7775SDouglas Gilbert 6937ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6938ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6939ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6940ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6941ad0c7775SDouglas Gilbert } 6942ad0c7775SDouglas Gilbert 69438d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6944ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6945ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 69468d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 69478d039e22SDouglas Gilbert } 6948ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6949ad0c7775SDouglas Gilbert } 6950ea61fca5SMartin K. Petersen 6951773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6952773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6953ea61fca5SMartin K. Petersen return -EINVAL; 6954ea61fca5SMartin K. Petersen } 6955ea61fca5SMartin K. Petersen 6956c4837394SDouglas Gilbert if (submit_queues < 1) { 6957c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6958c4837394SDouglas Gilbert return -EINVAL; 6959c4837394SDouglas Gilbert } 6960c87bf24cSJohn Garry 6961c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6962c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6963c87bf24cSJohn Garry return -EINVAL; 6964c87bf24cSJohn Garry } 6965c87bf24cSJohn Garry 6966c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6967c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6968c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6969c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6970c10fa55fSJohn Garry return -EINVAL; 6971c10fa55fSJohn Garry } 6972c10fa55fSJohn Garry 6973c10fa55fSJohn Garry if (sdebug_host_max_queue && 6974c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6975c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6976c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6977c10fa55fSJohn Garry sdebug_max_queue); 6978c10fa55fSJohn Garry } 6979c10fa55fSJohn Garry 6980c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6981c4837394SDouglas Gilbert GFP_KERNEL); 6982c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6983c4837394SDouglas Gilbert return -ENOMEM; 6984c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6985c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6986c4837394SDouglas Gilbert 6987f0d1cf93SDouglas Gilbert /* 69889267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 69899267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 6990f0d1cf93SDouglas Gilbert */ 69919267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 69929267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 69939267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 69949267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 69959267e0ebSDouglas Gilbert if (k < 0) { 69969267e0ebSDouglas Gilbert ret = k; 69973b01d7eaSDinghao Liu goto free_q_arr; 69989267e0ebSDouglas Gilbert } 69999267e0ebSDouglas Gilbert sdeb_zbc_model = k; 70009267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 70019267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 700264e14eceSDamien Le Moal case BLK_ZONED_HA: 70039267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 70049267e0ebSDouglas Gilbert break; 70059267e0ebSDouglas Gilbert case BLK_ZONED_HM: 70069267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 70079267e0ebSDouglas Gilbert break; 70089267e0ebSDouglas Gilbert default: 70099267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 70103b01d7eaSDinghao Liu ret = -EINVAL; 70113b01d7eaSDinghao Liu goto free_q_arr; 70129267e0ebSDouglas Gilbert } 70139267e0ebSDouglas Gilbert } 70149267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 7015f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 70169267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70179267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 70189267e0ebSDouglas Gilbert } 7019f0d1cf93SDouglas Gilbert 70209267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70219267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 7022773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 7023773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 7024773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 7025773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 702628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 70271da177e4SLinus Torvalds 70281da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 70291da177e4SLinus Torvalds sdebug_heads = 8; 70301da177e4SLinus Torvalds sdebug_sectors_per = 32; 7031773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 70321da177e4SLinus Torvalds sdebug_heads = 64; 7033773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 7034fa785f0aSAndy Shevchenko sdebug_heads = 32; 70351da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70361da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70371da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 70381da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 70391da177e4SLinus Torvalds sdebug_heads = 255; 70401da177e4SLinus Torvalds sdebug_sectors_per = 63; 70411da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70421da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70431da177e4SLinus Torvalds } 70445b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 7045773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 7046773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 70476014759cSMartin K. Petersen 7048773642d9SDouglas Gilbert sdebug_unmap_max_desc = 7049773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 70506014759cSMartin K. Petersen 7051773642d9SDouglas Gilbert sdebug_unmap_granularity = 7052773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 70536014759cSMartin K. Petersen 7054773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 7055773642d9SDouglas Gilbert sdebug_unmap_granularity <= 7056773642d9SDouglas Gilbert sdebug_unmap_alignment) { 7057c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 7058c4837394SDouglas Gilbert ret = -EINVAL; 705987c715dcSDouglas Gilbert goto free_q_arr; 706044d92694SMartin K. Petersen } 706144d92694SMartin K. Petersen } 706287c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 706387c715dcSDouglas Gilbert if (want_store) { 706487c715dcSDouglas Gilbert idx = sdebug_add_store(); 706587c715dcSDouglas Gilbert if (idx < 0) { 706687c715dcSDouglas Gilbert ret = idx; 706787c715dcSDouglas Gilbert goto free_q_arr; 706887c715dcSDouglas Gilbert } 706944d92694SMartin K. Petersen } 707044d92694SMartin K. Petersen 70719b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 70729b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 7073c1287970STomas Winkler pr_warn("root_device_register() error\n"); 70749b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 70756ecaff7fSRandy Dunlap goto free_vm; 70766ecaff7fSRandy Dunlap } 70776ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 70786ecaff7fSRandy Dunlap if (ret < 0) { 7079c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 70806ecaff7fSRandy Dunlap goto dev_unreg; 70816ecaff7fSRandy Dunlap } 70826ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 70836ecaff7fSRandy Dunlap if (ret < 0) { 7084c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 70856ecaff7fSRandy Dunlap goto bus_unreg; 70866ecaff7fSRandy Dunlap } 70871da177e4SLinus Torvalds 708887c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 7089773642d9SDouglas Gilbert sdebug_add_host = 0; 70901da177e4SLinus Torvalds 709187c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 70922aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 70932aad3cd8SDouglas Gilbert pr_info("exit early as sdebug_deflect_incoming is set\n"); 70942aad3cd8SDouglas Gilbert return 0; 70952aad3cd8SDouglas Gilbert } 709687c715dcSDouglas Gilbert if (want_store && k == 0) { 709787c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 709887c715dcSDouglas Gilbert if (ret < 0) { 709987c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 710087c715dcSDouglas Gilbert k, -ret); 710187c715dcSDouglas Gilbert break; 710287c715dcSDouglas Gilbert } 710387c715dcSDouglas Gilbert } else { 710487c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 710587c715dcSDouglas Gilbert sdebug_per_host_store); 710687c715dcSDouglas Gilbert if (ret < 0) { 710787c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 71081da177e4SLinus Torvalds break; 71091da177e4SLinus Torvalds } 71101da177e4SLinus Torvalds } 711187c715dcSDouglas Gilbert } 7112773642d9SDouglas Gilbert if (sdebug_verbose) 71132aad3cd8SDouglas Gilbert pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts)); 7114c1287970STomas Winkler 71152aad3cd8SDouglas Gilbert /* 71162aad3cd8SDouglas Gilbert * Even though all the hosts have been established, due to async device (LU) scanning 71172aad3cd8SDouglas Gilbert * by the scsi mid-level, there may still be devices (LUs) being set up. 71182aad3cd8SDouglas Gilbert */ 71191da177e4SLinus Torvalds return 0; 71206ecaff7fSRandy Dunlap 71216ecaff7fSRandy Dunlap bus_unreg: 71226ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 71236ecaff7fSRandy Dunlap dev_unreg: 71249b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71256ecaff7fSRandy Dunlap free_vm: 712687c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 7127c4837394SDouglas Gilbert free_q_arr: 7128c4837394SDouglas Gilbert kfree(sdebug_q_arr); 71296ecaff7fSRandy Dunlap return ret; 71301da177e4SLinus Torvalds } 71311da177e4SLinus Torvalds 71321da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 71331da177e4SLinus Torvalds { 71342aad3cd8SDouglas Gilbert int k; 71351da177e4SLinus Torvalds 71362aad3cd8SDouglas Gilbert /* Possible race with LUs still being set up; stop them asap */ 71372aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 71382aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, true); 71392aad3cd8SDouglas Gilbert stop_all_queued(false); 71402aad3cd8SDouglas Gilbert for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++) 714187c715dcSDouglas Gilbert sdebug_do_remove_host(true); 714252ab9768SLuis Henriques free_all_queued(); 71432aad3cd8SDouglas Gilbert if (sdebug_verbose) 71442aad3cd8SDouglas Gilbert pr_info("removed %d hosts\n", k); 71451da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 71461da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 71479b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71481da177e4SLinus Torvalds 714987c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 715087c715dcSDouglas Gilbert xa_destroy(per_store_ap); 7151f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 71521da177e4SLinus Torvalds } 71531da177e4SLinus Torvalds 71541da177e4SLinus Torvalds device_initcall(scsi_debug_init); 71551da177e4SLinus Torvalds module_exit(scsi_debug_exit); 71561da177e4SLinus Torvalds 71571da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 71581da177e4SLinus Torvalds { 71591da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71601da177e4SLinus Torvalds 71611da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 71621da177e4SLinus Torvalds kfree(sdbg_host); 71631da177e4SLinus Torvalds } 71641da177e4SLinus Torvalds 716587c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 716687c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 71671da177e4SLinus Torvalds { 716887c715dcSDouglas Gilbert if (idx < 0) 716987c715dcSDouglas Gilbert return; 717087c715dcSDouglas Gilbert if (!sip) { 717187c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 717287c715dcSDouglas Gilbert return; 717387c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 717487c715dcSDouglas Gilbert if (!sip) 717587c715dcSDouglas Gilbert return; 717687c715dcSDouglas Gilbert } 717787c715dcSDouglas Gilbert vfree(sip->map_storep); 717887c715dcSDouglas Gilbert vfree(sip->dif_storep); 717987c715dcSDouglas Gilbert vfree(sip->storep); 718087c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 718187c715dcSDouglas Gilbert kfree(sip); 718287c715dcSDouglas Gilbert } 718387c715dcSDouglas Gilbert 718487c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 718587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 718687c715dcSDouglas Gilbert { 718787c715dcSDouglas Gilbert unsigned long idx; 718887c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 718987c715dcSDouglas Gilbert 719087c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 719187c715dcSDouglas Gilbert if (apart_from_first) 719287c715dcSDouglas Gilbert apart_from_first = false; 719387c715dcSDouglas Gilbert else 719487c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 719587c715dcSDouglas Gilbert } 719687c715dcSDouglas Gilbert if (apart_from_first) 719787c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 719887c715dcSDouglas Gilbert } 719987c715dcSDouglas Gilbert 720087c715dcSDouglas Gilbert /* 720187c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 720287c715dcSDouglas Gilbert * Limit the number of stores to 65536. 720387c715dcSDouglas Gilbert */ 720487c715dcSDouglas Gilbert static int sdebug_add_store(void) 720587c715dcSDouglas Gilbert { 720687c715dcSDouglas Gilbert int res; 720787c715dcSDouglas Gilbert u32 n_idx; 720887c715dcSDouglas Gilbert unsigned long iflags; 720987c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 721087c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 721187c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 721287c715dcSDouglas Gilbert 721387c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 721487c715dcSDouglas Gilbert if (!sip) 721587c715dcSDouglas Gilbert return -ENOMEM; 721687c715dcSDouglas Gilbert 721787c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 721887c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 721987c715dcSDouglas Gilbert if (unlikely(res < 0)) { 722087c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 722187c715dcSDouglas Gilbert kfree(sip); 722287c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 722387c715dcSDouglas Gilbert return res; 722487c715dcSDouglas Gilbert } 722587c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 722687c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 722787c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 722887c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 722987c715dcSDouglas Gilbert 723087c715dcSDouglas Gilbert res = -ENOMEM; 723187c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 723287c715dcSDouglas Gilbert if (!sip->storep) { 723387c715dcSDouglas Gilbert pr_err("user data oom\n"); 723487c715dcSDouglas Gilbert goto err; 723587c715dcSDouglas Gilbert } 723687c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 723787c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 723887c715dcSDouglas Gilbert 723987c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 724087c715dcSDouglas Gilbert if (sdebug_dix) { 724187c715dcSDouglas Gilbert int dif_size; 724287c715dcSDouglas Gilbert 724387c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 724487c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 724587c715dcSDouglas Gilbert 724687c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 724787c715dcSDouglas Gilbert sip->dif_storep); 724887c715dcSDouglas Gilbert 724987c715dcSDouglas Gilbert if (!sip->dif_storep) { 725087c715dcSDouglas Gilbert pr_err("DIX oom\n"); 725187c715dcSDouglas Gilbert goto err; 725287c715dcSDouglas Gilbert } 725387c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 725487c715dcSDouglas Gilbert } 725587c715dcSDouglas Gilbert /* Logical Block Provisioning */ 725687c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 725787c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 725887c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 725987c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 726087c715dcSDouglas Gilbert 726187c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 726287c715dcSDouglas Gilbert 726387c715dcSDouglas Gilbert if (!sip->map_storep) { 726487c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 726587c715dcSDouglas Gilbert goto err; 726687c715dcSDouglas Gilbert } 726787c715dcSDouglas Gilbert 726887c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 726987c715dcSDouglas Gilbert 727087c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 727187c715dcSDouglas Gilbert if (sdebug_num_parts) 727287c715dcSDouglas Gilbert map_region(sip, 0, 2); 727387c715dcSDouglas Gilbert } 727487c715dcSDouglas Gilbert 727587c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 727687c715dcSDouglas Gilbert return (int)n_idx; 727787c715dcSDouglas Gilbert err: 727887c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 727987c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 728087c715dcSDouglas Gilbert return res; 728187c715dcSDouglas Gilbert } 728287c715dcSDouglas Gilbert 728387c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 728487c715dcSDouglas Gilbert { 728587c715dcSDouglas Gilbert int k, devs_per_host, idx; 728687c715dcSDouglas Gilbert int error = -ENOMEM; 72871da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72888b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 72891da177e4SLinus Torvalds 729024669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 729187c715dcSDouglas Gilbert if (!sdbg_host) 72921da177e4SLinus Torvalds return -ENOMEM; 729387c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 729487c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 729587c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 729687c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 72971da177e4SLinus Torvalds 72981da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 72991da177e4SLinus Torvalds 7300773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 73011da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 73025cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 730387c715dcSDouglas Gilbert if (!sdbg_devinfo) 73041da177e4SLinus Torvalds goto clean; 73051da177e4SLinus Torvalds } 73061da177e4SLinus Torvalds 73071da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73081da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 73091da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73101da177e4SLinus Torvalds 73111da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 73129b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 73131da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 73142aad3cd8SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts)); 73151da177e4SLinus Torvalds 73161da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 73171da177e4SLinus Torvalds if (error) 73181da177e4SLinus Torvalds goto clean; 73191da177e4SLinus Torvalds 73202aad3cd8SDouglas Gilbert atomic_inc(&sdebug_num_hosts); 732187c715dcSDouglas Gilbert return 0; 73221da177e4SLinus Torvalds 73231da177e4SLinus Torvalds clean: 73248b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 73258b40228fSFUJITA Tomonori dev_list) { 73261da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7327f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 73281da177e4SLinus Torvalds kfree(sdbg_devinfo); 73291da177e4SLinus Torvalds } 73301da177e4SLinus Torvalds kfree(sdbg_host); 733187c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 73321da177e4SLinus Torvalds return error; 73331da177e4SLinus Torvalds } 73341da177e4SLinus Torvalds 733587c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 73361da177e4SLinus Torvalds { 733787c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 733887c715dcSDouglas Gilbert 733987c715dcSDouglas Gilbert if (mk_new_store) { 734087c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 734187c715dcSDouglas Gilbert if (ph_idx < 0) 734287c715dcSDouglas Gilbert return ph_idx; 734387c715dcSDouglas Gilbert } 734487c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 734587c715dcSDouglas Gilbert } 734687c715dcSDouglas Gilbert 734787c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 734887c715dcSDouglas Gilbert { 734987c715dcSDouglas Gilbert int idx = -1; 73501da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 735187c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 73521da177e4SLinus Torvalds 73531da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73541da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 73551da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 73561da177e4SLinus Torvalds struct sdebug_host_info, host_list); 735787c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 73581da177e4SLinus Torvalds } 735987c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 736087c715dcSDouglas Gilbert bool unique = true; 736187c715dcSDouglas Gilbert 736287c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 736387c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 736487c715dcSDouglas Gilbert continue; 736587c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 736687c715dcSDouglas Gilbert unique = false; 736787c715dcSDouglas Gilbert break; 736887c715dcSDouglas Gilbert } 736987c715dcSDouglas Gilbert } 737087c715dcSDouglas Gilbert if (unique) { 737187c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 737287c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 737387c715dcSDouglas Gilbert --sdeb_most_recent_idx; 737487c715dcSDouglas Gilbert } 737587c715dcSDouglas Gilbert } 737687c715dcSDouglas Gilbert if (sdbg_host) 737787c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 73781da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73791da177e4SLinus Torvalds 73801da177e4SLinus Torvalds if (!sdbg_host) 73811da177e4SLinus Torvalds return; 73821da177e4SLinus Torvalds 73831da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 73842aad3cd8SDouglas Gilbert atomic_dec(&sdebug_num_hosts); 73851da177e4SLinus Torvalds } 73861da177e4SLinus Torvalds 7387fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7388cbf67842SDouglas Gilbert { 7389cbf67842SDouglas Gilbert int num_in_q = 0; 7390cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7391cbf67842SDouglas Gilbert 73922aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 7393cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7394cbf67842SDouglas Gilbert if (NULL == devip) { 73952aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 7396cbf67842SDouglas Gilbert return -ENODEV; 7397cbf67842SDouglas Gilbert } 7398cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7399c40ecc12SChristoph Hellwig 7400fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7401fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7402fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7403fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7404fc09acb7SDouglas Gilbert } 7405cbf67842SDouglas Gilbert if (qdepth < 1) 7406cbf67842SDouglas Gilbert qdepth = 1; 7407fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7408db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7409cbf67842SDouglas Gilbert 7410773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7411c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7412c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7413cbf67842SDouglas Gilbert } 74142aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 7415cbf67842SDouglas Gilbert return sdev->queue_depth; 7416cbf67842SDouglas Gilbert } 7417cbf67842SDouglas Gilbert 7418c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7419817fd66bSDouglas Gilbert { 7420c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7421773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7422773642d9SDouglas Gilbert sdebug_every_nth = -1; 7423773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7424c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7425773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7426817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7427c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7428817fd66bSDouglas Gilbert } 7429c4837394SDouglas Gilbert return false; 7430817fd66bSDouglas Gilbert } 7431817fd66bSDouglas Gilbert 7432fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7433fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7434fc13638aSDouglas Gilbert { 7435fc13638aSDouglas Gilbert int stopped_state; 7436fc13638aSDouglas Gilbert u64 diff_ns = 0; 7437fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7438fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7439fc13638aSDouglas Gilbert 7440fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7441fc13638aSDouglas Gilbert if (stopped_state == 2) { 7442fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7443fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7444fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7445fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7446fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7447fc13638aSDouglas Gilbert return 0; 7448fc13638aSDouglas Gilbert } 7449fc13638aSDouglas Gilbert } 7450fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7451fc13638aSDouglas Gilbert if (sdebug_verbose) 7452fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7453fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7454fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7455fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7456fc13638aSDouglas Gilbert 7457fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7458fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7459fc13638aSDouglas Gilbert else 7460fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7461fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7462fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7463fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7464fc13638aSDouglas Gilbert diff_ns); 7465fc13638aSDouglas Gilbert return check_condition_result; 7466fc13638aSDouglas Gilbert } 7467fc13638aSDouglas Gilbert } 7468fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7469fc13638aSDouglas Gilbert if (sdebug_verbose) 7470fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7471fc13638aSDouglas Gilbert my_name); 7472fc13638aSDouglas Gilbert return check_condition_result; 7473fc13638aSDouglas Gilbert } 7474fc13638aSDouglas Gilbert 7475c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost) 7476c4b57d89SKashyap Desai { 7477c4b57d89SKashyap Desai int i, qoff; 7478c4b57d89SKashyap Desai 7479c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7480c4b57d89SKashyap Desai return 0; 7481c4b57d89SKashyap Desai 7482c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7483c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7484c4b57d89SKashyap Desai 7485c4b57d89SKashyap Desai map->nr_queues = 0; 7486c4b57d89SKashyap Desai 7487c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7488c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7489c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7490c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7491c4b57d89SKashyap Desai 7492c4b57d89SKashyap Desai if (!map->nr_queues) { 7493c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7494c4b57d89SKashyap Desai continue; 7495c4b57d89SKashyap Desai } 7496c4b57d89SKashyap Desai 7497c4b57d89SKashyap Desai map->queue_offset = qoff; 7498c4b57d89SKashyap Desai blk_mq_map_queues(map); 7499c4b57d89SKashyap Desai 7500c4b57d89SKashyap Desai qoff += map->nr_queues; 7501c4b57d89SKashyap Desai } 7502c4b57d89SKashyap Desai 7503c4b57d89SKashyap Desai return 0; 7504c4b57d89SKashyap Desai 7505c4b57d89SKashyap Desai } 7506c4b57d89SKashyap Desai 7507c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7508c4b57d89SKashyap Desai { 75094a0c6f43SDouglas Gilbert bool first; 75104a0c6f43SDouglas Gilbert bool retiring = false; 75114a0c6f43SDouglas Gilbert int num_entries = 0; 75124a0c6f43SDouglas Gilbert unsigned int qc_idx = 0; 7513c4b57d89SKashyap Desai unsigned long iflags; 75144a0c6f43SDouglas Gilbert ktime_t kt_from_boot = ktime_get_boottime(); 7515c4b57d89SKashyap Desai struct sdebug_queue *sqp; 7516c4b57d89SKashyap Desai struct sdebug_queued_cmd *sqcp; 7517c4b57d89SKashyap Desai struct scsi_cmnd *scp; 7518c4b57d89SKashyap Desai struct sdebug_dev_info *devip; 75194a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7520c4b57d89SKashyap Desai 7521c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 75224a0c6f43SDouglas Gilbert 7523c4b57d89SKashyap Desai spin_lock_irqsave(&sqp->qc_lock, iflags); 75244a0c6f43SDouglas Gilbert 7525*6a0d0ae3SDamien Le Moal qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 7526*6a0d0ae3SDamien Le Moal if (qc_idx >= sdebug_max_queue) 7527*6a0d0ae3SDamien Le Moal goto unlock; 7528*6a0d0ae3SDamien Le Moal 75294a0c6f43SDouglas Gilbert for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { 75304a0c6f43SDouglas Gilbert if (first) { 75314a0c6f43SDouglas Gilbert first = false; 7532b05d4e48SDouglas Gilbert if (!test_bit(qc_idx, sqp->in_use_bm)) 7533b05d4e48SDouglas Gilbert continue; 75344a0c6f43SDouglas Gilbert } else { 75354a0c6f43SDouglas Gilbert qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1); 75364a0c6f43SDouglas Gilbert } 7537b05d4e48SDouglas Gilbert if (qc_idx >= sdebug_max_queue) 75384a0c6f43SDouglas Gilbert break; 7539c4b57d89SKashyap Desai 7540c4b57d89SKashyap Desai sqcp = &sqp->qc_arr[qc_idx]; 75414a0c6f43SDouglas Gilbert sd_dp = sqcp->sd_dp; 75424a0c6f43SDouglas Gilbert if (unlikely(!sd_dp)) 75434a0c6f43SDouglas Gilbert continue; 7544c4b57d89SKashyap Desai scp = sqcp->a_cmnd; 7545c4b57d89SKashyap Desai if (unlikely(scp == NULL)) { 75464a0c6f43SDouglas Gilbert pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n", 7547c4b57d89SKashyap Desai queue_num, qc_idx, __func__); 75484a0c6f43SDouglas Gilbert break; 7549c4b57d89SKashyap Desai } 7550d9d23a5aSDouglas Gilbert if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) { 75514a0c6f43SDouglas Gilbert if (kt_from_boot < sd_dp->cmpl_ts) 75524a0c6f43SDouglas Gilbert continue; 75534a0c6f43SDouglas Gilbert 75546ce913feSChristoph Hellwig } else /* ignoring non REQ_POLLED requests */ 75554a0c6f43SDouglas Gilbert continue; 7556c4b57d89SKashyap Desai devip = (struct sdebug_dev_info *)scp->device->hostdata; 7557c4b57d89SKashyap Desai if (likely(devip)) 7558c4b57d89SKashyap Desai atomic_dec(&devip->num_in_q); 7559c4b57d89SKashyap Desai else 7560c4b57d89SKashyap Desai pr_err("devip=NULL from %s\n", __func__); 7561c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 75624a0c6f43SDouglas Gilbert retiring = true; 7563c4b57d89SKashyap Desai 7564c4b57d89SKashyap Desai sqcp->a_cmnd = NULL; 7565c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 75664a0c6f43SDouglas Gilbert pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n", 7567c4b57d89SKashyap Desai sqp, queue_num, qc_idx, __func__); 75684a0c6f43SDouglas Gilbert break; 7569c4b57d89SKashyap Desai } 7570c4b57d89SKashyap Desai if (unlikely(retiring)) { /* user has reduced max_queue */ 7571c4b57d89SKashyap Desai int k, retval; 7572c4b57d89SKashyap Desai 7573c4b57d89SKashyap Desai retval = atomic_read(&retired_max_queue); 7574c4b57d89SKashyap Desai if (qc_idx >= retval) { 7575c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 75764a0c6f43SDouglas Gilbert break; 7577c4b57d89SKashyap Desai } 7578c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7579c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7580c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7581c4b57d89SKashyap Desai else 7582c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7583c4b57d89SKashyap Desai } 7584d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 7585c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 75866c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 7587c4b57d89SKashyap Desai num_entries++; 75883fd07aecSDamien Le Moal spin_lock_irqsave(&sqp->qc_lock, iflags); 7589b05d4e48SDouglas Gilbert if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue) 75903fd07aecSDamien Le Moal break; 75914a0c6f43SDouglas Gilbert } 75923fd07aecSDamien Le Moal 7593*6a0d0ae3SDamien Le Moal unlock: 7594c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 75953fd07aecSDamien Le Moal 75964a0c6f43SDouglas Gilbert if (num_entries > 0) 75974a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7598c4b57d89SKashyap Desai return num_entries; 7599c4b57d89SKashyap Desai } 7600c4b57d89SKashyap Desai 7601fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7602fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7603c2248fc9SDouglas Gilbert { 7604c2248fc9SDouglas Gilbert u8 sdeb_i; 7605c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7606c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7607c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7608c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7609c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7610c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7611f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7612c2248fc9SDouglas Gilbert int k, na; 7613c2248fc9SDouglas Gilbert int errsts = 0; 7614ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7615c2248fc9SDouglas Gilbert u32 flags; 7616c2248fc9SDouglas Gilbert u16 sa; 7617c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7618c2248fc9SDouglas Gilbert bool has_wlun_rl; 76193a90a63dSDouglas Gilbert bool inject_now; 7620c2248fc9SDouglas Gilbert 7621c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 76223a90a63dSDouglas Gilbert if (sdebug_statistics) { 7623c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 76243a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 76253a90a63dSDouglas Gilbert } else { 76263a90a63dSDouglas Gilbert inject_now = false; 76273a90a63dSDouglas Gilbert } 7628f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7629f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7630c2248fc9SDouglas Gilbert char b[120]; 7631c2248fc9SDouglas Gilbert int n, len, sb; 7632c2248fc9SDouglas Gilbert 7633c2248fc9SDouglas Gilbert len = scp->cmd_len; 7634c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7635c2248fc9SDouglas Gilbert if (len > 32) 7636c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7637c2248fc9SDouglas Gilbert else { 7638c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7639c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7640c2248fc9SDouglas Gilbert (u32)cmd[k]); 7641c2248fc9SDouglas Gilbert } 7642458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7643a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7644c2248fc9SDouglas Gilbert } 76453a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 76467ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 764734d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7648ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7649f46eb0e9SDouglas Gilbert goto err_out; 7650c2248fc9SDouglas Gilbert 7651c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7652c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7653c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7654f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7655f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7656c2248fc9SDouglas Gilbert if (NULL == devip) 7657f46eb0e9SDouglas Gilbert goto err_out; 7658c2248fc9SDouglas Gilbert } 76593a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 76603a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 76613a90a63dSDouglas Gilbert 7662c2248fc9SDouglas Gilbert na = oip->num_attached; 7663c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7664c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7665c2248fc9SDouglas Gilbert r_oip = oip; 7666c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7667c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7668c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7669c2248fc9SDouglas Gilbert else 7670c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7671c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7672c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7673c2248fc9SDouglas Gilbert break; 7674c2248fc9SDouglas Gilbert } 7675c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7676c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7677c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7678c2248fc9SDouglas Gilbert break; 7679c2248fc9SDouglas Gilbert } 7680c2248fc9SDouglas Gilbert } 7681c2248fc9SDouglas Gilbert if (k > na) { 7682c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7683c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7684c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7685c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7686c2248fc9SDouglas Gilbert else 7687c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7688c2248fc9SDouglas Gilbert goto check_cond; 7689c2248fc9SDouglas Gilbert } 7690c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7691c2248fc9SDouglas Gilbert flags = oip->flags; 7692f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7693c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7694c2248fc9SDouglas Gilbert goto check_cond; 7695c2248fc9SDouglas Gilbert } 7696f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7697773642d9SDouglas Gilbert if (sdebug_verbose) 7698773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7699773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7700c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7701c2248fc9SDouglas Gilbert goto check_cond; 7702c2248fc9SDouglas Gilbert } 7703f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7704c2248fc9SDouglas Gilbert u8 rem; 7705c2248fc9SDouglas Gilbert int j; 7706c2248fc9SDouglas Gilbert 7707c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7708c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7709c2248fc9SDouglas Gilbert if (rem) { 7710c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7711c2248fc9SDouglas Gilbert if (0x80 & rem) 7712c2248fc9SDouglas Gilbert break; 7713c2248fc9SDouglas Gilbert } 7714c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7715c2248fc9SDouglas Gilbert goto check_cond; 7716c2248fc9SDouglas Gilbert } 7717c2248fc9SDouglas Gilbert } 7718c2248fc9SDouglas Gilbert } 7719f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7720b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7721b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7722f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7723c2248fc9SDouglas Gilbert if (errsts) 7724c2248fc9SDouglas Gilbert goto check_cond; 7725c2248fc9SDouglas Gilbert } 7726fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7727fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7728fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7729fc13638aSDouglas Gilbert if (errsts) 7730c2248fc9SDouglas Gilbert goto fini; 7731c2248fc9SDouglas Gilbert } 7732773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7733c2248fc9SDouglas Gilbert goto fini; 7734f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7735c4837394SDouglas Gilbert if (fake_timeout(scp)) 7736c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7737c2248fc9SDouglas Gilbert } 7738f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7739f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7740f66b8517SMartin Wilck else 7741f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7742c2248fc9SDouglas Gilbert 7743c2248fc9SDouglas Gilbert fini: 774467da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7745f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 774675aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 774775aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 774880c49563SDouglas Gilbert /* 774975aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 775075aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 775175aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 775275aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 775380c49563SDouglas Gilbert */ 775480c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 77554f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 775680c49563SDouglas Gilbert 77574f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7758f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 775980c49563SDouglas Gilbert } else 7760f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 776110bde980SDouglas Gilbert sdebug_ndelay); 7762c2248fc9SDouglas Gilbert check_cond: 7763f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7764f46eb0e9SDouglas Gilbert err_out: 7765f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7766c2248fc9SDouglas Gilbert } 7767c2248fc9SDouglas Gilbert 77689e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7769c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7770c8ed555aSAl Viro .write_info = scsi_debug_write_info, 77719e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 77729e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 77739e603ca0SFUJITA Tomonori .info = scsi_debug_info, 77749e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 77759e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 77769e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 77779e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7778185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7779cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7780c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7781c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 77829e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 77839e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7784cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7785cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 77869e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7787c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 77889e603ca0SFUJITA Tomonori .this_id = 7, 778965e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7790cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 77916bb5e6e7SAkinobu Mita .max_sectors = -1U, 779250c2e910SChristoph Hellwig .max_segment_size = -1U, 77939e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7794c40ecc12SChristoph Hellwig .track_queue_depth = 1, 77959e603ca0SFUJITA Tomonori }; 77969e603ca0SFUJITA Tomonori 77971da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 77981da177e4SLinus Torvalds { 77991da177e4SLinus Torvalds int error = 0; 78001da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 78011da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7802f46eb0e9SDouglas Gilbert int hprot; 78031da177e4SLinus Torvalds 78041da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 78051da177e4SLinus Torvalds 7806773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7807fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 78082a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 78094af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 78104af14d11SChristoph Hellwig 78111da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 78121da177e4SLinus Torvalds if (NULL == hpnt) { 7813c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 78141da177e4SLinus Torvalds error = -ENODEV; 78151da177e4SLinus Torvalds return error; 78161da177e4SLinus Torvalds } 7817c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 78189b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7819c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7820c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7821c4837394SDouglas Gilbert } 7822c10fa55fSJohn Garry /* 7823c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7824f7c4cdc7SJohn Garry * following should give the same answer for each host. 7825c10fa55fSJohn Garry */ 7826c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7827f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7828f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 78291da177e4SLinus Torvalds 7830c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7831c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7832c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7833c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7834c4b57d89SKashyap Desai poll_queues = 0; 7835c4b57d89SKashyap Desai } 7836c4b57d89SKashyap Desai 7837c4b57d89SKashyap Desai /* 7838c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7839c4b57d89SKashyap Desai * left over for non-polled I/O. 7840c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7841c4b57d89SKashyap Desai */ 7842c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7843fc09acb7SDouglas Gilbert if (submit_queues < 3) 7844c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7845fc09acb7SDouglas Gilbert else 7846fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7847fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7848c4b57d89SKashyap Desai poll_queues = 1; 7849c4b57d89SKashyap Desai } 7850c4b57d89SKashyap Desai if (poll_queues) 7851c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7852c4b57d89SKashyap Desai 78531da177e4SLinus Torvalds sdbg_host->shost = hpnt; 78541da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7855773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7856773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 78571da177e4SLinus Torvalds else 7858773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7859773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7860f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 78611da177e4SLinus Torvalds 7862f46eb0e9SDouglas Gilbert hprot = 0; 7863c6a44287SMartin K. Petersen 7864773642d9SDouglas Gilbert switch (sdebug_dif) { 7865c6a44287SMartin K. Petersen 78668475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7867f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7868773642d9SDouglas Gilbert if (sdebug_dix) 7869f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7870c6a44287SMartin K. Petersen break; 7871c6a44287SMartin K. Petersen 78728475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7873f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7874773642d9SDouglas Gilbert if (sdebug_dix) 7875f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7876c6a44287SMartin K. Petersen break; 7877c6a44287SMartin K. Petersen 78788475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7879f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7880773642d9SDouglas Gilbert if (sdebug_dix) 7881f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7882c6a44287SMartin K. Petersen break; 7883c6a44287SMartin K. Petersen 7884c6a44287SMartin K. Petersen default: 7885773642d9SDouglas Gilbert if (sdebug_dix) 7886f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7887c6a44287SMartin K. Petersen break; 7888c6a44287SMartin K. Petersen } 7889c6a44287SMartin K. Petersen 7890f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7891c6a44287SMartin K. Petersen 7892f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7893c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7894f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7895f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7896f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7897f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7898f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7899f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7900f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7901c6a44287SMartin K. Petersen 7902773642d9SDouglas Gilbert if (sdebug_guard == 1) 7903c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7904c6a44287SMartin K. Petersen else 7905c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7906c6a44287SMartin K. Petersen 7907773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7908773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7909c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7910c4837394SDouglas Gilbert sdebug_statistics = true; 79111da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 79121da177e4SLinus Torvalds if (error) { 7913c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 79141da177e4SLinus Torvalds error = -ENODEV; 79151da177e4SLinus Torvalds scsi_host_put(hpnt); 791687c715dcSDouglas Gilbert } else { 79171da177e4SLinus Torvalds scsi_scan_host(hpnt); 791887c715dcSDouglas Gilbert } 79191da177e4SLinus Torvalds 79201da177e4SLinus Torvalds return error; 79211da177e4SLinus Torvalds } 79221da177e4SLinus Torvalds 7923fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev) 79241da177e4SLinus Torvalds { 79251da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 79268b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 79271da177e4SLinus Torvalds 79281da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 79291da177e4SLinus Torvalds 79301da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 79311da177e4SLinus Torvalds 79328b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 79338b40228fSFUJITA Tomonori dev_list) { 79341da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7935f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 79361da177e4SLinus Torvalds kfree(sdbg_devinfo); 79371da177e4SLinus Torvalds } 79381da177e4SLinus Torvalds 79391da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 79401da177e4SLinus Torvalds } 79411da177e4SLinus Torvalds 79428dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 79438dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 79441da177e4SLinus Torvalds { 79458dea0d02SFUJITA Tomonori return 1; 79468dea0d02SFUJITA Tomonori } 79471da177e4SLinus Torvalds 79488dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 79498dea0d02SFUJITA Tomonori .name = "pseudo", 79508dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 79518dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 79528dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 795382069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 79548dea0d02SFUJITA Tomonori }; 7955