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> 194a5fc1c6SDamien Le Moal #include <linux/align.h> 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> 35cbf67842SDouglas Gilbert #include <linux/interrupt.h> 36cbf67842SDouglas Gilbert #include <linux/atomic.h> 37cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 3809ba24c1SDouglas Gilbert #include <linux/uuid.h> 396ebf105cSChristoph Hellwig #include <linux/t10-pi.h> 401442f76dSChristoph Hellwig #include <linux/msdos_partition.h> 410c4bc91dSDouglas Gilbert #include <linux/random.h> 4287c715dcSDouglas Gilbert #include <linux/xarray.h> 43ed9f3e25SDouglas Gilbert #include <linux/prefetch.h> 44c6a44287SMartin K. Petersen 45c6a44287SMartin K. Petersen #include <net/checksum.h> 469ff26eefSFUJITA Tomonori 4744d92694SMartin K. Petersen #include <asm/unaligned.h> 4844d92694SMartin K. Petersen 499ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 521da177e4SLinus Torvalds #include <scsi/scsi_host.h> 531da177e4SLinus Torvalds #include <scsi/scsicam.h> 54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 571da177e4SLinus Torvalds 58c6a44287SMartin K. Petersen #include "sd.h" 591da177e4SLinus Torvalds #include "scsi_logging.h" 601da177e4SLinus Torvalds 61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 62500d0d24SDouglas Gilbert #define SDEBUG_VERSION "0191" /* format to fit INQUIRY revision field */ 63500d0d24SDouglas Gilbert static const char *sdebug_version_date = "20210520"; 64cbf67842SDouglas Gilbert 65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 661da177e4SLinus Torvalds 676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 779447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27 78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 85500d0d24SDouglas Gilbert #define POWER_ON_OCCURRED_ASCQ 0x1 86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc 97f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4 98f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5 99f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6 100f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7 1014a5fc1c6SDamien Le Moal #define ATTEMPT_ACCESS_GAP 0x9 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 { 25535dbe2b9SDamien Le Moal ZBC_ZTYPE_CNV = 0x1, 25635dbe2b9SDamien Le Moal ZBC_ZTYPE_SWR = 0x2, 25735dbe2b9SDamien Le Moal ZBC_ZTYPE_SWP = 0x3, 2584a5fc1c6SDamien Le Moal /* ZBC_ZTYPE_SOBR = 0x4, */ 2594a5fc1c6SDamien Le Moal ZBC_ZTYPE_GAP = 0x5, 26064e14eceSDamien Le Moal }; 26164e14eceSDamien Le Moal 262f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 263f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 264f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 265f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 266f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 267f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 268f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 269f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 270f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 271f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 272f0d1cf93SDouglas Gilbert }; 273f0d1cf93SDouglas Gilbert 274f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 27564e14eceSDamien Le Moal enum sdebug_z_type z_type; 276f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 27764e14eceSDamien Le Moal bool z_non_seq_resource; 278f0d1cf93SDouglas Gilbert unsigned int z_size; 279f0d1cf93SDouglas Gilbert sector_t z_start; 280f0d1cf93SDouglas Gilbert sector_t z_wp; 281f0d1cf93SDouglas Gilbert }; 282fd32119bSDouglas Gilbert 283fd32119bSDouglas Gilbert struct sdebug_dev_info { 284fd32119bSDouglas Gilbert struct list_head dev_list; 285fd32119bSDouglas Gilbert unsigned int channel; 286fd32119bSDouglas Gilbert unsigned int target; 287fd32119bSDouglas Gilbert u64 lun; 288bf476433SChristoph Hellwig uuid_t lu_name; 289fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 290fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 291fd32119bSDouglas Gilbert atomic_t num_in_q; 292fc13638aSDouglas Gilbert atomic_t stopped; /* 1: by SSU, 2: device start */ 293fd32119bSDouglas Gilbert bool used; 294f0d1cf93SDouglas Gilbert 295f0d1cf93SDouglas Gilbert /* For ZBC devices */ 29664e14eceSDamien Le Moal enum blk_zoned_model zmodel; 2974a5fc1c6SDamien Le Moal unsigned int zcap; 298f0d1cf93SDouglas Gilbert unsigned int zsize; 299f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 300f0d1cf93SDouglas Gilbert unsigned int nr_zones; 301aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 3024a5fc1c6SDamien Le Moal unsigned int nr_seq_zones; 303f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 304f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 305f0d1cf93SDouglas Gilbert unsigned int nr_closed; 306f0d1cf93SDouglas Gilbert unsigned int max_open; 307fc13638aSDouglas Gilbert ktime_t create_ts; /* time since bootup that this device was created */ 308f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 309fd32119bSDouglas Gilbert }; 310fd32119bSDouglas Gilbert 311fd32119bSDouglas Gilbert struct sdebug_host_info { 312fd32119bSDouglas Gilbert struct list_head host_list; 31387c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 314fd32119bSDouglas Gilbert struct Scsi_Host *shost; 315fd32119bSDouglas Gilbert struct device dev; 316fd32119bSDouglas Gilbert struct list_head dev_info_list; 317fd32119bSDouglas Gilbert }; 318fd32119bSDouglas Gilbert 31987c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 32087c715dcSDouglas Gilbert struct sdeb_store_info { 32187c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 32287c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 32387c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 32487c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 32587c715dcSDouglas Gilbert }; 32687c715dcSDouglas Gilbert 327fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 328fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 329fd32119bSDouglas Gilbert 33010bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 3314a0c6f43SDouglas Gilbert SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3}; 33210bde980SDouglas Gilbert 333fd32119bSDouglas Gilbert struct sdebug_defer { 334fd32119bSDouglas Gilbert struct hrtimer hrt; 335fd32119bSDouglas Gilbert struct execute_work ew; 3364a0c6f43SDouglas Gilbert ktime_t cmpl_ts;/* time since boot to complete this cmd */ 337c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 338c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 339c10fa55fSJohn Garry int hc_idx; /* hostwide tag index */ 340c4837394SDouglas Gilbert int issuing_cpu; 34110bde980SDouglas Gilbert bool init_hrt; 34210bde980SDouglas Gilbert bool init_wq; 3434a0c6f43SDouglas Gilbert bool init_poll; 3447382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 34510bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 346fd32119bSDouglas Gilbert }; 347fd32119bSDouglas Gilbert 348fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 349c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 350c4837394SDouglas Gilbert * instance indicates this slot is in use. 351c4837394SDouglas Gilbert */ 352fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 353fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 354fd32119bSDouglas Gilbert }; 355fd32119bSDouglas Gilbert 356c4837394SDouglas Gilbert struct sdebug_queue { 357c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 358c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 359c4837394SDouglas Gilbert spinlock_t qc_lock; 360c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 361fd32119bSDouglas Gilbert }; 362fd32119bSDouglas Gilbert 363c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 364c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 365c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 366c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 3673a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending; 3684a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */ 369c4837394SDouglas Gilbert 370fd32119bSDouglas Gilbert struct opcode_info_t { 371b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 372b01f6f83SDouglas Gilbert /* for terminating element */ 373fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 374fd32119bSDouglas Gilbert u16 sa; /* service action */ 375fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 376fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 377fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3789a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3799a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 380fd32119bSDouglas Gilbert }; 381fd32119bSDouglas Gilbert 382fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 383c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 384c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 385c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 386c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 387c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 388c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 389c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 390c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 391c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 392c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 393c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 394c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 395c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 39646f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 39746f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 398c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 399c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 400c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 401481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 402c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 403c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 404c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 405c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 406c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 407c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 408c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 409c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 410c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 411c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 412c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 413ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 414f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 415f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 416f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 417c2248fc9SDouglas Gilbert }; 418c2248fc9SDouglas Gilbert 419c4837394SDouglas Gilbert 420c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 421c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 422c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 423c2248fc9SDouglas Gilbert 0, 0, 0, 0, 424c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 425c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 426c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 427c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 428c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 429c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 430c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 431c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 432ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 433c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 434c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 435c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 436c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 437c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 438c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 439c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 440fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 441c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 442c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 443c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 444c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 445c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 446c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 447c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 448f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 449f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 45046f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 451c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 452c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 453c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 45446f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 45546f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 456c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 457c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 458c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 459c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 460c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 461c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 462c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 463c2248fc9SDouglas Gilbert }; 464c2248fc9SDouglas Gilbert 46580c49563SDouglas Gilbert /* 46680c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 46780c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 46880c49563SDouglas Gilbert * command completion, they can mask their return value with 46980c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 47080c49563SDouglas Gilbert */ 47180c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 47280c49563SDouglas Gilbert 473c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 474c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 475c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 476c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 477c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 478c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 479c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 482481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 483c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 484c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 485c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 486c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 487c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 48838d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 48938d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 490c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 491c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 492c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 49338d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 494acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 49580c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 496ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 497f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 498f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 499f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 500f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 501f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 502c2248fc9SDouglas Gilbert 50387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 50487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 50587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 50687c715dcSDouglas Gilbert static int sdebug_add_store(void); 50787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 50887c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 50987c715dcSDouglas Gilbert 51046f64e70SDouglas Gilbert /* 51146f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 51246f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 51346f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 51446f64e70SDouglas Gilbert */ 51546f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 516c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 517c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 518c2248fc9SDouglas Gilbert }; 519c2248fc9SDouglas Gilbert 52046f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 521c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 522c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 523c2248fc9SDouglas Gilbert }; 524c2248fc9SDouglas Gilbert 52546f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 52646f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 527b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 528c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 52946f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 530c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 53146f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 532b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 533c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 534c2248fc9SDouglas Gilbert }; 535c2248fc9SDouglas Gilbert 53646f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 53746f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 53846f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 53946f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 54046f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 54146f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 54246f64e70SDouglas Gilbert 0, 0, 0} }, 54346f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 54446f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54546f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 546c2248fc9SDouglas Gilbert }; 547c2248fc9SDouglas Gilbert 548c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 549c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 550c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 551c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 552c3e2fe92SDouglas Gilbert }; 553c3e2fe92SDouglas Gilbert 55446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 555c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 556c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55746f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 558c2248fc9SDouglas Gilbert }; 559c2248fc9SDouglas Gilbert 56046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 56146f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 562b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 563c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 564481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 565481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 566481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 567c2248fc9SDouglas Gilbert }; 568c2248fc9SDouglas Gilbert 56946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 57038d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 571c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 57246f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 57338d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 574c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 57546f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 576c2248fc9SDouglas Gilbert }; 577c2248fc9SDouglas Gilbert 57846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 57946f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 580c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 58146f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 582c2248fc9SDouglas Gilbert }; 583c2248fc9SDouglas Gilbert 58446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 585c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 586c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 587c2248fc9SDouglas Gilbert }; 588c2248fc9SDouglas Gilbert 58946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 590c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 591c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 592c2248fc9SDouglas Gilbert }; 593c2248fc9SDouglas Gilbert 59480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5954f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 59680c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59780c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 59880c49563SDouglas Gilbert }; 59980c49563SDouglas Gilbert 600ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 601b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 602ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 603ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 604ed9f3e25SDouglas Gilbert }; 605ed9f3e25SDouglas Gilbert 606f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 607b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 608f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 609f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 610b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 611f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 612f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 613b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 614f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 615f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 616f0d1cf93SDouglas Gilbert }; 617f0d1cf93SDouglas Gilbert 618f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 619b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 620f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 621f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 622f0d1cf93SDouglas Gilbert }; 623f0d1cf93SDouglas Gilbert 624c2248fc9SDouglas Gilbert 625c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 626c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 627c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 628ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 629c2248fc9SDouglas Gilbert /* 0 */ 63046f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 631c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63246f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 633c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 634c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 635c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 63646f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 637c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 638c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 639c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 640c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 64146f64e70SDouglas Gilbert /* 5 */ 64246f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 64346f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 64446f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64546f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 64646f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 64746f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64846f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 649c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 650c2248fc9SDouglas Gilbert 0, 0, 0} }, 65146f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 652c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 653c2248fc9SDouglas Gilbert 0, 0} }, 65446f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 65546f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 65646f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 657c2248fc9SDouglas Gilbert /* 10 */ 65846f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 65946f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 66046f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66180c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6624f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 663c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 66446f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 66546f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 66646f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66746f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 668481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 669481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 670481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 67146f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 67246f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 67346f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 67446f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 67546f64e70SDouglas Gilbert /* 15 */ 676c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 677c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 678c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 679c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 680c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 681c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 68246f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 68346f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 68446f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 68546f64e70SDouglas Gilbert 0xff, 0xff} }, 68646f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 68746f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 688c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 689c2248fc9SDouglas Gilbert 0} }, 69046f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 69146f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 692c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 693c2248fc9SDouglas Gilbert 0} }, 694c2248fc9SDouglas Gilbert /* 20 */ 695f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 696f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 697c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 698c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 699c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 700c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 701c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 702c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 70346f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 704b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 70546f64e70SDouglas Gilbert /* 25 */ 706acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 707acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 708acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 70946f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 71046f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 71146f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 71246f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7134f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 71480c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 715b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 71680c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 71746f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 718c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 719b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 720b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 721ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 722ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 723ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 724c2248fc9SDouglas Gilbert 725ed9f3e25SDouglas Gilbert /* 30 */ 726b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 727f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 728f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 729f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 730b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 731f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 732f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 733f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 734f0d1cf93SDouglas Gilbert /* sentinel */ 735c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 736c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 737c2248fc9SDouglas Gilbert }; 738c2248fc9SDouglas Gilbert 739f19fe8f3SBart Van Assche static int sdebug_num_hosts; 74087c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 741773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7429b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 743c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7449267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 745773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 746773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 747773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 748773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 749773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 750773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 751c10fa55fSJohn Garry static int sdebug_host_max_queue; /* per host */ 752773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 753773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 754c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 755d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 756d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 757cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 758c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 759773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 760773642d9SDouglas Gilbert static int sdebug_no_uld; 761773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 762773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 763773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 764773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 765773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 76686e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 767b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 768773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 769773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 770fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY; 771773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 772773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 773773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 774773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 775773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 776773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 778773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 779773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 780773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 781773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 78209ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7830c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 78487c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 785773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 786773642d9SDouglas Gilbert static bool sdebug_clustering; 787773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 788773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 789817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 7907109f370SDouglas Gilbert static bool sdebug_no_rwlock; 791773642d9SDouglas Gilbert static bool sdebug_verbose; 792f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7934f2c8bf6SDouglas Gilbert static bool write_since_sync; 794c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7959447b6ceSMartin K. Petersen static bool sdebug_wp; 7969267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 7979267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 7989267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 7991da177e4SLinus Torvalds 800ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0, 801ad0c7775SDouglas Gilbert SAM_LUN_AM_FLAT = 0x1, 802ad0c7775SDouglas Gilbert SAM_LUN_AM_LOGICAL_UNIT = 0x2, 803ad0c7775SDouglas Gilbert SAM_LUN_AM_EXTENDED = 0x3}; 804ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 805ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL; 806ad0c7775SDouglas Gilbert 807c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8081da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8091da177e4SLinus Torvalds 8101da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8111da177e4SLinus Torvalds may still need them */ 8121da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8131da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8141da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8151da177e4SLinus Torvalds 8161da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8171da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8181da177e4SLinus Torvalds 81987c715dcSDouglas Gilbert static struct xarray per_store_arr; 82087c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 82187c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 82287c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 82387c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8241da177e4SLinus Torvalds 82544d92694SMartin K. Petersen static unsigned long map_size; 826cbf67842SDouglas Gilbert static int num_aborts; 827cbf67842SDouglas Gilbert static int num_dev_resets; 828cbf67842SDouglas Gilbert static int num_target_resets; 829cbf67842SDouglas Gilbert static int num_bus_resets; 830cbf67842SDouglas Gilbert static int num_host_resets; 831c6a44287SMartin K. Petersen static int dix_writes; 832c6a44287SMartin K. Petersen static int dix_reads; 833c6a44287SMartin K. Petersen static int dif_errors; 8341da177e4SLinus Torvalds 835f0d1cf93SDouglas Gilbert /* ZBC global data */ 83664e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 8374a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb; 83898e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 839380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 840aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 841f0d1cf93SDouglas Gilbert 842c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 843c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/ 844c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 845fd32119bSDouglas Gilbert 8461da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 84787c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 84887c715dcSDouglas Gilbert 84987c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8501da177e4SLinus Torvalds 851cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 852cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8531da177e4SLinus Torvalds 8541da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8551da177e4SLinus Torvalds 8561da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8571da177e4SLinus Torvalds .name = sdebug_proc_name, 8581da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8591da177e4SLinus Torvalds }; 8601da177e4SLinus Torvalds 8611da177e4SLinus Torvalds static const int check_condition_result = 862464a00c9SHannes Reinecke SAM_STAT_CHECK_CONDITION; 8631da177e4SLinus Torvalds 864c6a44287SMartin K. Petersen static const int illegal_condition_result = 865464a00c9SHannes Reinecke (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 866c6a44287SMartin K. Petersen 867cbf67842SDouglas Gilbert static const int device_qfull_result = 8687d5a129bSDouglas Gilbert (DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL; 869cbf67842SDouglas Gilbert 870ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 871ed9f3e25SDouglas Gilbert 872fd32119bSDouglas Gilbert 873760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 874760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 875760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 876760f3b03SDouglas Gilbert */ 877760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 878fd32119bSDouglas Gilbert { 879fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 880fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 881fd32119bSDouglas Gilbert } 882c65b1445SDouglas Gilbert 88387c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 88487c715dcSDouglas Gilbert unsigned long long lba) 88514faa944SAkinobu Mita { 88687c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 88714faa944SAkinobu Mita 88887c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 88987c715dcSDouglas Gilbert if (!sip || !sip->storep) { 89087c715dcSDouglas Gilbert WARN_ON_ONCE(true); 89187c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 89287c715dcSDouglas Gilbert } 89387c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 89414faa944SAkinobu Mita } 89514faa944SAkinobu Mita 89687c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 89787c715dcSDouglas Gilbert sector_t sector) 89814faa944SAkinobu Mita { 89949413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 90014faa944SAkinobu Mita 90187c715dcSDouglas Gilbert return sip->dif_storep + sector; 90214faa944SAkinobu Mita } 90314faa944SAkinobu Mita 9048dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 9058dea0d02SFUJITA Tomonori { 9068dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 9078dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9088dea0d02SFUJITA Tomonori 9098dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 9108dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9118dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9128dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 913773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 914773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9158dea0d02SFUJITA Tomonori else 916773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 917773642d9SDouglas Gilbert /* sdebug_max_luns; */ 918f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9198dea0d02SFUJITA Tomonori } 9208dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9218dea0d02SFUJITA Tomonori } 9228dea0d02SFUJITA Tomonori 92322017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 92422017ed2SDouglas Gilbert 92522017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 926fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 927fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 92822017ed2SDouglas Gilbert int in_byte, int in_bit) 92922017ed2SDouglas Gilbert { 93022017ed2SDouglas Gilbert unsigned char *sbuff; 93122017ed2SDouglas Gilbert u8 sks[4]; 93222017ed2SDouglas Gilbert int sl, asc; 93322017ed2SDouglas Gilbert 93422017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 93522017ed2SDouglas Gilbert if (!sbuff) { 93622017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 93722017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 93822017ed2SDouglas Gilbert return; 93922017ed2SDouglas Gilbert } 94022017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 94122017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 942f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0); 94322017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 94422017ed2SDouglas Gilbert sks[0] = 0x80; 94522017ed2SDouglas Gilbert if (c_d) 94622017ed2SDouglas Gilbert sks[0] |= 0x40; 94722017ed2SDouglas Gilbert if (in_bit >= 0) { 94822017ed2SDouglas Gilbert sks[0] |= 0x8; 94922017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 95022017ed2SDouglas Gilbert } 95122017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 952773642d9SDouglas Gilbert if (sdebug_dsense) { 95322017ed2SDouglas Gilbert sl = sbuff[7] + 8; 95422017ed2SDouglas Gilbert sbuff[7] = sl; 95522017ed2SDouglas Gilbert sbuff[sl] = 0x2; 95622017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 95722017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 95822017ed2SDouglas Gilbert } else 95922017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 960773642d9SDouglas Gilbert if (sdebug_verbose) 96122017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 96222017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 96322017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 96422017ed2SDouglas Gilbert } 96522017ed2SDouglas Gilbert 966cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9678dea0d02SFUJITA Tomonori { 968f2b1e9c6SHannes Reinecke if (!scp->sense_buffer) { 969cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 970cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 971cbf67842SDouglas Gilbert return; 972cbf67842SDouglas Gilbert } 973f2b1e9c6SHannes Reinecke memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 9748dea0d02SFUJITA Tomonori 975f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, key, asc, asq); 9768dea0d02SFUJITA Tomonori 977773642d9SDouglas Gilbert if (sdebug_verbose) 978cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 979cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 980cbf67842SDouglas Gilbert my_name, key, asc, asq); 9818dea0d02SFUJITA Tomonori } 9821da177e4SLinus Torvalds 983fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 98422017ed2SDouglas Gilbert { 98522017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 98622017ed2SDouglas Gilbert } 98722017ed2SDouglas Gilbert 9886f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9896f4e626fSNathan Chancellor void __user *arg) 9901da177e4SLinus Torvalds { 991773642d9SDouglas Gilbert if (sdebug_verbose) { 992cbf67842SDouglas Gilbert if (0x1261 == cmd) 993cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 994cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 995cbf67842SDouglas Gilbert else if (0x5331 == cmd) 996cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 997cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 998cbf67842SDouglas Gilbert __func__); 999cbf67842SDouglas Gilbert else 1000cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 1001cbf67842SDouglas Gilbert __func__, cmd); 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds return -EINVAL; 10041da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 10051da177e4SLinus Torvalds } 10061da177e4SLinus Torvalds 10079b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10089b760fd8SDouglas Gilbert { 10099b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10109b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10119b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10129b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10139b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10149b760fd8SDouglas Gilbert break; 10159b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10169b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10179b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10189b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10199b760fd8SDouglas Gilbert break; 10209b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10219b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10229b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10239b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10249b760fd8SDouglas Gilbert break; 10259b760fd8SDouglas Gilbert case 16: 10269b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10279b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10289b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10299b760fd8SDouglas Gilbert break; 10309b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10319b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10329b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10339b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10349b760fd8SDouglas Gilbert break; 10359b760fd8SDouglas Gilbert default: 10369b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10379b760fd8SDouglas Gilbert sdebug_cdb_len); 10389b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10399b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10409b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10419b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10429b760fd8SDouglas Gilbert break; 10439b760fd8SDouglas Gilbert } 10449b760fd8SDouglas Gilbert } 10459b760fd8SDouglas Gilbert 10469b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10479b760fd8SDouglas Gilbert { 10489b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10499b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10509b760fd8SDouglas Gilbert struct scsi_device *sdev; 10519b760fd8SDouglas Gilbert 10529b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10539b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10549b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10559b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10569b760fd8SDouglas Gilbert config_cdb_len(sdev); 10579b760fd8SDouglas Gilbert } 10589b760fd8SDouglas Gilbert } 10599b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10609b760fd8SDouglas Gilbert } 10619b760fd8SDouglas Gilbert 106219c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 106319c8ead7SEwan D. Milne { 106419c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 106519c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 106619c8ead7SEwan D. Milne 106719c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 106819c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 106919c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 107019c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 107119c8ead7SEwan D. Milne (devip->target == dp->target)) 107219c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 107319c8ead7SEwan D. Milne } 107419c8ead7SEwan D. Milne } 107519c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 107619c8ead7SEwan D. Milne } 107719c8ead7SEwan D. Milne 1078f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10791da177e4SLinus Torvalds { 1080cbf67842SDouglas Gilbert int k; 1081cbf67842SDouglas Gilbert 1082cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1083cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1084cbf67842SDouglas Gilbert const char *cp = NULL; 1085cbf67842SDouglas Gilbert 1086cbf67842SDouglas Gilbert switch (k) { 1087cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1088f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1089f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1090773642d9SDouglas Gilbert if (sdebug_verbose) 1091cbf67842SDouglas Gilbert cp = "power on reset"; 1092cbf67842SDouglas Gilbert break; 1093500d0d24SDouglas Gilbert case SDEBUG_UA_POOCCUR: 1094500d0d24SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1095500d0d24SDouglas Gilbert POWER_ON_OCCURRED_ASCQ); 1096500d0d24SDouglas Gilbert if (sdebug_verbose) 1097500d0d24SDouglas Gilbert cp = "power on occurred"; 1098500d0d24SDouglas Gilbert break; 1099cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1100f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1101f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1102773642d9SDouglas Gilbert if (sdebug_verbose) 1103cbf67842SDouglas Gilbert cp = "bus reset"; 1104cbf67842SDouglas Gilbert break; 1105cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1106f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1107f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1108773642d9SDouglas Gilbert if (sdebug_verbose) 1109cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1110cbf67842SDouglas Gilbert break; 11110d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1112f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1113f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1114773642d9SDouglas Gilbert if (sdebug_verbose) 11150d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1116f49accf1SEwan D. Milne break; 1117acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1118f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1119b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1120b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1121773642d9SDouglas Gilbert if (sdebug_verbose) 1122acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1123acafd0b9SEwan D. Milne break; 1124acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1125f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1126acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1127acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1128773642d9SDouglas Gilbert if (sdebug_verbose) 1129acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1130acafd0b9SEwan D. Milne break; 113119c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 113219c8ead7SEwan D. Milne /* 113319c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 113419c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 113519c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 113619c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1137773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 113819c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 113919c8ead7SEwan D. Milne */ 1140773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 114119c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1142f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 114319c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 114419c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1145773642d9SDouglas Gilbert if (sdebug_verbose) 114619c8ead7SEwan D. Milne cp = "reported luns data has changed"; 114719c8ead7SEwan D. Milne break; 1148cbf67842SDouglas Gilbert default: 1149773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1150773642d9SDouglas Gilbert if (sdebug_verbose) 1151cbf67842SDouglas Gilbert cp = "unknown"; 1152cbf67842SDouglas Gilbert break; 1153cbf67842SDouglas Gilbert } 1154cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1155773642d9SDouglas Gilbert if (sdebug_verbose) 1156f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1157cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1158cbf67842SDouglas Gilbert my_name, cp); 11591da177e4SLinus Torvalds return check_condition_result; 11601da177e4SLinus Torvalds } 11611da177e4SLinus Torvalds return 0; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 1164fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11651da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11661da177e4SLinus Torvalds int arr_len) 11671da177e4SLinus Torvalds { 116821a61829SFUJITA Tomonori int act_len; 1169ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11701da177e4SLinus Torvalds 1171072d0bb3SFUJITA Tomonori if (!sdb->length) 11721da177e4SLinus Torvalds return 0; 1173ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1174773642d9SDouglas Gilbert return DID_ERROR << 16; 117521a61829SFUJITA Tomonori 117621a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 117721a61829SFUJITA Tomonori arr, arr_len); 117842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 117921a61829SFUJITA Tomonori 11801da177e4SLinus Torvalds return 0; 11811da177e4SLinus Torvalds } 11821da177e4SLinus Torvalds 1183fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1184fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1185fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1186fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1187fb0cc8d1SDouglas Gilbert */ 1188fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1189fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1190fb0cc8d1SDouglas Gilbert { 11919237f04eSDamien Le Moal unsigned int act_len, n; 1192ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1193fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1194fb0cc8d1SDouglas Gilbert 1195fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1196fb0cc8d1SDouglas Gilbert return 0; 1197ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1198fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1199fb0cc8d1SDouglas Gilbert 1200fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1201fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1202fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 120342d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 120442d387beSBart Van Assche scsi_get_resid(scp)); 12059237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 120636e07d7eSGeorge Kennedy scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); 1207fb0cc8d1SDouglas Gilbert return 0; 1208fb0cc8d1SDouglas Gilbert } 1209fb0cc8d1SDouglas Gilbert 1210fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1211fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1212fb0cc8d1SDouglas Gilbert */ 12131da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 121421a61829SFUJITA Tomonori int arr_len) 12151da177e4SLinus Torvalds { 121621a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12171da177e4SLinus Torvalds return 0; 1218ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12191da177e4SLinus Torvalds return -1; 122021a61829SFUJITA Tomonori 122121a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12221da177e4SLinus Torvalds } 12231da177e4SLinus Torvalds 12241da177e4SLinus Torvalds 1225e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1226e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12279b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12281b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12291b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12301b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12311b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12321da177e4SLinus Torvalds 1233cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1234760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12355a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 123609ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1237bf476433SChristoph Hellwig const uuid_t *lu_name) 12381da177e4SLinus Torvalds { 1239c65b1445SDouglas Gilbert int num, port_a; 1240c65b1445SDouglas Gilbert char b[32]; 12411da177e4SLinus Torvalds 1242c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12431da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12441da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12451da177e4SLinus Torvalds arr[1] = 0x1; 12461da177e4SLinus Torvalds arr[2] = 0x0; 1247e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1248e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12491da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12501da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12511da177e4SLinus Torvalds arr[3] = num; 12521da177e4SLinus Torvalds num += 4; 1253c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 125409ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 125509ba24c1SDouglas Gilbert /* Locally assigned UUID */ 125609ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 125709ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 125809ba24c1SDouglas Gilbert arr[num++] = 0x0; 125909ba24c1SDouglas Gilbert arr[num++] = 0x12; 126009ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 126109ba24c1SDouglas Gilbert arr[num++] = 0x0; 126209ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 126309ba24c1SDouglas Gilbert num += 16; 126409ba24c1SDouglas Gilbert } else { 12651b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1266c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1267c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1268c65b1445SDouglas Gilbert arr[num++] = 0x0; 1269c65b1445SDouglas Gilbert arr[num++] = 0x8; 12701b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1271773642d9SDouglas Gilbert num += 8; 127209ba24c1SDouglas Gilbert } 1273c65b1445SDouglas Gilbert /* Target relative port number */ 1274c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1275c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1276c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1277c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1278c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1279c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1280c65b1445SDouglas Gilbert arr[num++] = 0x0; 1281c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1282c65b1445SDouglas Gilbert } 12831b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1284c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1285c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1286c65b1445SDouglas Gilbert arr[num++] = 0x0; 1287c65b1445SDouglas Gilbert arr[num++] = 0x8; 12881b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1289773642d9SDouglas Gilbert num += 8; 12901b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12915a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12925a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12935a09e398SHannes Reinecke arr[num++] = 0x0; 12945a09e398SHannes Reinecke arr[num++] = 0x4; 12955a09e398SHannes Reinecke arr[num++] = 0; 12965a09e398SHannes Reinecke arr[num++] = 0; 1297773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1298773642d9SDouglas Gilbert num += 2; 12991b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1300c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1301c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1302c65b1445SDouglas Gilbert arr[num++] = 0x0; 1303c65b1445SDouglas Gilbert arr[num++] = 0x8; 13041b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1305773642d9SDouglas Gilbert num += 8; 1306c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1307c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1308c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1309c65b1445SDouglas Gilbert arr[num++] = 0x0; 1310c65b1445SDouglas Gilbert arr[num++] = 24; 13111b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1312c65b1445SDouglas Gilbert num += 12; 1313c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1314c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1315c65b1445SDouglas Gilbert num += 8; 1316c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1317c65b1445SDouglas Gilbert num += 4; 1318c65b1445SDouglas Gilbert return num; 1319c65b1445SDouglas Gilbert } 1320c65b1445SDouglas Gilbert 1321c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1322c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1323c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1324c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1325c65b1445SDouglas Gilbert }; 1326c65b1445SDouglas Gilbert 1327cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1328760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1329c65b1445SDouglas Gilbert { 1330c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1331c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1332c65b1445SDouglas Gilbert } 1333c65b1445SDouglas Gilbert 1334cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1335760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1336c65b1445SDouglas Gilbert { 1337c65b1445SDouglas Gilbert int num = 0; 1338c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1339c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1340c65b1445SDouglas Gilbert int plen, olen; 1341c65b1445SDouglas Gilbert 1342c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1343c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1344c65b1445SDouglas Gilbert arr[num++] = 0x0; 1345c65b1445SDouglas Gilbert olen = strlen(na1); 1346c65b1445SDouglas Gilbert plen = olen + 1; 1347c65b1445SDouglas Gilbert if (plen % 4) 1348c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1349c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1350c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1351c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1352c65b1445SDouglas Gilbert num += plen; 1353c65b1445SDouglas Gilbert 1354c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1355c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1356c65b1445SDouglas Gilbert arr[num++] = 0x0; 1357c65b1445SDouglas Gilbert olen = strlen(na2); 1358c65b1445SDouglas Gilbert plen = olen + 1; 1359c65b1445SDouglas Gilbert if (plen % 4) 1360c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1361c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1362c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1363c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1364c65b1445SDouglas Gilbert num += plen; 1365c65b1445SDouglas Gilbert 1366c65b1445SDouglas Gilbert return num; 1367c65b1445SDouglas Gilbert } 1368c65b1445SDouglas Gilbert 1369c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1370760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1371c65b1445SDouglas Gilbert { 1372c65b1445SDouglas Gilbert int num = 0; 1373c65b1445SDouglas Gilbert int port_a, port_b; 1374c65b1445SDouglas Gilbert 1375c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1376c65b1445SDouglas Gilbert port_b = port_a + 1; 1377c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1378c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1379c65b1445SDouglas Gilbert arr[num++] = 0x0; 1380c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1381c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1382c65b1445SDouglas Gilbert num += 6; 1383c65b1445SDouglas Gilbert arr[num++] = 0x0; 1384c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1385c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1386c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1387c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1388c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1389c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13901b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1391773642d9SDouglas Gilbert num += 8; 1392c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1393c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1394c65b1445SDouglas Gilbert arr[num++] = 0x0; 1395c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1396c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1397c65b1445SDouglas Gilbert num += 6; 1398c65b1445SDouglas Gilbert arr[num++] = 0x0; 1399c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1400c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1401c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1402c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1403c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1404c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 14051b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1406773642d9SDouglas Gilbert num += 8; 1407c65b1445SDouglas Gilbert 1408c65b1445SDouglas Gilbert return num; 1409c65b1445SDouglas Gilbert } 1410c65b1445SDouglas Gilbert 1411c65b1445SDouglas Gilbert 1412c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1413c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1414c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1415c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1416c65b1445SDouglas Gilbert '1','2','3','4', 1417c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1418c65b1445SDouglas Gilbert 0xec,0,0,0, 1419c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1420c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1421c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1422c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1423c65b1445SDouglas Gilbert 0x53,0x41, 1424c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1425c65b1445SDouglas Gilbert 0x20,0x20, 1426c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1427c65b1445SDouglas Gilbert 0x10,0x80, 1428c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1429c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1430c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1431c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1432c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1433c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1438c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1439c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1440c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1441c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0, 1452c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1453c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1454c65b1445SDouglas Gilbert }; 1455c65b1445SDouglas Gilbert 1456cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1457760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1458c65b1445SDouglas Gilbert { 1459c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1460c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1461c65b1445SDouglas Gilbert } 1462c65b1445SDouglas Gilbert 1463c65b1445SDouglas Gilbert 1464c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14651e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14661e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14671e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14681e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1469c65b1445SDouglas Gilbert }; 1470c65b1445SDouglas Gilbert 1471cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1472760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1473c65b1445SDouglas Gilbert { 1474ea61fca5SMartin K. Petersen unsigned int gran; 1475ea61fca5SMartin K. Petersen 1476c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1477e308b3d1SMartin K. Petersen 1478e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 147986e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 148086e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 148186e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 148286e6828aSLukas Herbolt else 1483773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1484773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1485e308b3d1SMartin K. Petersen 1486e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1487773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1488773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 148944d92694SMartin K. Petersen 1490e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1491773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1492e308b3d1SMartin K. Petersen 1493773642d9SDouglas Gilbert if (sdebug_lbpu) { 1494e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1495773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1496e308b3d1SMartin K. Petersen 1497e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1498773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 149944d92694SMartin K. Petersen } 150044d92694SMartin K. Petersen 1501e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1502773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1503773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 150444d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 150544d92694SMartin K. Petersen } 150644d92694SMartin K. Petersen 1507e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1508773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 15096014759cSMartin K. Petersen 15105b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1511773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 15125b94e232SMartin K. Petersen 15135b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 151444d92694SMartin K. Petersen 1515c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 15161da177e4SLinus Torvalds } 15171da177e4SLinus Torvalds 15181e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 151964e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1520eac6e8e4SMatthew Wilcox { 1521eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1522eac6e8e4SMatthew Wilcox arr[0] = 0; 15231e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15241e49f785SDouglas Gilbert arr[2] = 0; 15251e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 152664e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 152764e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1528eac6e8e4SMatthew Wilcox 1529eac6e8e4SMatthew Wilcox return 0x3c; 1530eac6e8e4SMatthew Wilcox } 15311da177e4SLinus Torvalds 1532760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1533760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15346014759cSMartin K. Petersen { 15353f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15366014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1537773642d9SDouglas Gilbert if (sdebug_lbpu) 15386014759cSMartin K. Petersen arr[1] = 1 << 7; 1539773642d9SDouglas Gilbert if (sdebug_lbpws) 15406014759cSMartin K. Petersen arr[1] |= 1 << 6; 1541773642d9SDouglas Gilbert if (sdebug_lbpws10) 15425b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1543760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1544760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1545760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1546760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1547760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15483f0bc3b3SMartin K. Petersen return 0x4; 15496014759cSMartin K. Petersen } 15506014759cSMartin K. Petersen 1551d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1552f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1553d36da305SDouglas Gilbert { 1554d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1555d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1556d36da305SDouglas Gilbert /* 1557d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1558d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1559f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1560f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1561d36da305SDouglas Gilbert */ 1562d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1563d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 156464e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1565f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1566f0d1cf93SDouglas Gilbert else 1567d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 15684a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) { 15694a5fc1c6SDamien Le Moal arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET; 15704a5fc1c6SDamien Le Moal put_unaligned_be64(devip->zsize, &arr[20]); 15714a5fc1c6SDamien Le Moal } else { 15724a5fc1c6SDamien Le Moal arr[19] = 0; 15734a5fc1c6SDamien Le Moal } 1574d36da305SDouglas Gilbert return 0x3c; 1575d36da305SDouglas Gilbert } 1576d36da305SDouglas Gilbert 15771da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1578c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15791da177e4SLinus Torvalds 1580c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15811da177e4SLinus Torvalds { 15821da177e4SLinus Torvalds unsigned char pq_pdt; 15835a09e398SHannes Reinecke unsigned char *arr; 158401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 158536e07d7eSGeorge Kennedy u32 alloc_len, n; 158636e07d7eSGeorge Kennedy int ret; 1587d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15881da177e4SLinus Torvalds 1589773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15906f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15916f3cbf55SDouglas Gilbert if (! arr) 15926f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1593760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 159464e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1595d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1596b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1597c2248fc9SDouglas Gilbert if (have_wlun) 1598b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1599b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1600b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1601c65b1445SDouglas Gilbert else 1602773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 16031da177e4SLinus Torvalds arr[0] = pq_pdt; 16041da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 160522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 16065a09e398SHannes Reinecke kfree(arr); 16071da177e4SLinus Torvalds return check_condition_result; 16081da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 160936e07d7eSGeorge Kennedy int lu_id_num, port_group_id, target_dev_id; 161036e07d7eSGeorge Kennedy u32 len; 1611c65b1445SDouglas Gilbert char lu_id_str[6]; 1612c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 16131da177e4SLinus Torvalds 16145a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 16155a09e398SHannes Reinecke (devip->channel & 0x7f); 1616b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 161723183910SDouglas Gilbert host_no = 0; 1618c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1619c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1620c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1621c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1622c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16231da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1624c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1625c65b1445SDouglas Gilbert n = 4; 1626c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1627c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1628c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1629c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1630c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1631c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1632c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1633c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1634d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1635c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1636760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1637760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1638d36da305SDouglas Gilbert if (is_disk) 1639d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 164064e14eceSDamien Le Moal if (is_zbc) 1641d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1642760f3b03SDouglas Gilbert } 1643c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16441da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1645c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16461da177e4SLinus Torvalds arr[3] = len; 1647c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16481da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1649c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1650760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16515a09e398SHannes Reinecke target_dev_id, lu_id_num, 165209ba24c1SDouglas Gilbert lu_id_str, len, 165309ba24c1SDouglas Gilbert &devip->lu_name); 1654c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1655c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1656760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1657c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1658c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1659760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1660c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1661c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1662c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16638475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1664c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1665760f3b03SDouglas Gilbert else if (have_dif_prot) 1666c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1667c6a44287SMartin K. Petersen else 1668c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1669c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1670c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1671c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1672c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1673c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1674c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1675c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1676c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1677c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1678c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1679760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1680d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1681c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1682760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1683773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1684d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1685c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1686760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1687d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1688eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 168964e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1690760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16916014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1692760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1693d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1694d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1695f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16961da177e4SLinus Torvalds } else { 169722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16985a09e398SHannes Reinecke kfree(arr); 16991da177e4SLinus Torvalds return check_condition_result; 17001da177e4SLinus Torvalds } 170136e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 17025a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 170336e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 17045a09e398SHannes Reinecke kfree(arr); 17055a09e398SHannes Reinecke return ret; 17061da177e4SLinus Torvalds } 17071da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1708773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1709773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 17101da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 17111da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1712f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1713b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 171470bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1715c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 17161da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1717c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1718e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1719e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1720e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 17219b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17229b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17231da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1724760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1725760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1726c65b1445SDouglas Gilbert n = 62; 1727760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1728760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1729760f3b03SDouglas Gilbert n += 2; 1730760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1731760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1732760f3b03SDouglas Gilbert n += 2; 1733d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1734d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1735d36da305SDouglas Gilbert n += 2; 17361da177e4SLinus Torvalds } 1737760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17385a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 173936e07d7eSGeorge Kennedy min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ)); 17405a09e398SHannes Reinecke kfree(arr); 17415a09e398SHannes Reinecke return ret; 17421da177e4SLinus Torvalds } 17431da177e4SLinus Torvalds 174484905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */ 1745fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1746fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1747fd32119bSDouglas Gilbert 17481da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17491da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17501da177e4SLinus Torvalds { 175101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 175284905d34SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ 175384905d34SDouglas Gilbert bool dsense = !!(cmd[1] & 1); 175436e07d7eSGeorge Kennedy u32 alloc_len = cmd[4]; 175536e07d7eSGeorge Kennedy u32 len = 18; 175684905d34SDouglas Gilbert int stopped_state = atomic_read(&devip->stopped); 17571da177e4SLinus Torvalds 1758c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 175984905d34SDouglas Gilbert if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ 176084905d34SDouglas Gilbert if (dsense) { 176184905d34SDouglas Gilbert arr[0] = 0x72; 176284905d34SDouglas Gilbert arr[1] = NOT_READY; 176384905d34SDouglas Gilbert arr[2] = LOGICAL_UNIT_NOT_READY; 176484905d34SDouglas Gilbert arr[3] = (stopped_state == 2) ? 0x1 : 0x2; 176584905d34SDouglas Gilbert len = 8; 176684905d34SDouglas Gilbert } else { 176784905d34SDouglas Gilbert arr[0] = 0x70; 176884905d34SDouglas Gilbert arr[2] = NOT_READY; /* NO_SENSE in sense_key */ 176984905d34SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 177084905d34SDouglas Gilbert arr[12] = LOGICAL_UNIT_NOT_READY; 177184905d34SDouglas Gilbert arr[13] = (stopped_state == 2) ? 0x1 : 0x2; 177284905d34SDouglas Gilbert } 177384905d34SDouglas Gilbert } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 177484905d34SDouglas Gilbert /* Information exceptions control mode page: TEST=1, MRIE=6 */ 1775c2248fc9SDouglas Gilbert if (dsense) { 1776c65b1445SDouglas Gilbert arr[0] = 0x72; 1777c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1778c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 177984905d34SDouglas Gilbert arr[3] = 0xff; /* Failure prediction(false) */ 1780c2248fc9SDouglas Gilbert len = 8; 1781c65b1445SDouglas Gilbert } else { 1782c65b1445SDouglas Gilbert arr[0] = 0x70; 1783c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1784c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1785c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 178684905d34SDouglas Gilbert arr[13] = 0xff; /* Failure prediction(false) */ 1787c65b1445SDouglas Gilbert } 178884905d34SDouglas Gilbert } else { /* nothing to report */ 1789c2248fc9SDouglas Gilbert if (dsense) { 1790c2248fc9SDouglas Gilbert len = 8; 179184905d34SDouglas Gilbert memset(arr, 0, len); 179284905d34SDouglas Gilbert arr[0] = 0x72; 1793c2248fc9SDouglas Gilbert } else { 179484905d34SDouglas Gilbert memset(arr, 0, len); 1795c2248fc9SDouglas Gilbert arr[0] = 0x70; 1796c2248fc9SDouglas Gilbert arr[7] = 0xa; 1797c2248fc9SDouglas Gilbert } 1798c65b1445SDouglas Gilbert } 179936e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len)); 18001da177e4SLinus Torvalds } 18011da177e4SLinus Torvalds 1802fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 1803c65b1445SDouglas Gilbert { 180401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1805fc13638aSDouglas Gilbert int power_cond, want_stop, stopped_state; 18064f2c8bf6SDouglas Gilbert bool changing; 1807c65b1445SDouglas Gilbert 1808c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1809c65b1445SDouglas Gilbert if (power_cond) { 181022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1811c65b1445SDouglas Gilbert return check_condition_result; 1812c65b1445SDouglas Gilbert } 1813fc13638aSDouglas Gilbert want_stop = !(cmd[4] & 1); 1814fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 1815fc13638aSDouglas Gilbert if (stopped_state == 2) { 1816fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 1817fc13638aSDouglas Gilbert 1818fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 1819fc13638aSDouglas Gilbert u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 1820fc13638aSDouglas Gilbert 1821fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 1822fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 1823fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 1824fc13638aSDouglas Gilbert stopped_state = 0; 1825fc13638aSDouglas Gilbert } 1826fc13638aSDouglas Gilbert } 1827fc13638aSDouglas Gilbert if (stopped_state == 2) { 1828fc13638aSDouglas Gilbert if (want_stop) { 1829fc13638aSDouglas Gilbert stopped_state = 1; /* dummy up success */ 1830fc13638aSDouglas Gilbert } else { /* Disallow tur_ms_to_ready delay to be overridden */ 1831fc13638aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */); 1832fc13638aSDouglas Gilbert return check_condition_result; 1833fc13638aSDouglas Gilbert } 1834fc13638aSDouglas Gilbert } 1835fc13638aSDouglas Gilbert } 1836fc13638aSDouglas Gilbert changing = (stopped_state != want_stop); 1837fc13638aSDouglas Gilbert if (changing) 1838fc13638aSDouglas Gilbert atomic_xchg(&devip->stopped, want_stop); 1839fc13638aSDouglas Gilbert if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ 18404f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18414f2c8bf6SDouglas Gilbert else 18424f2c8bf6SDouglas Gilbert return 0; 1843c65b1445SDouglas Gilbert } 1844c65b1445SDouglas Gilbert 184528898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 184628898873SFUJITA Tomonori { 1847773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1848773642d9SDouglas Gilbert 1849773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1850773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1851773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 185228898873SFUJITA Tomonori else 185328898873SFUJITA Tomonori return sdebug_store_sectors; 185428898873SFUJITA Tomonori } 185528898873SFUJITA Tomonori 18561da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18571da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18581da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18591da177e4SLinus Torvalds { 18601da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1861c65b1445SDouglas Gilbert unsigned int capac; 18621da177e4SLinus Torvalds 1863c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 186428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18651da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1866c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1867c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1868773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1869773642d9SDouglas Gilbert } else 1870773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1871773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18721da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18731da177e4SLinus Torvalds } 18741da177e4SLinus Torvalds 1875c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1876c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1877c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1878c65b1445SDouglas Gilbert { 187901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1880c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 18814e3ace00SYe Bin u32 alloc_len; 1882c65b1445SDouglas Gilbert 1883773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1884c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 188528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1886c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1887773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1888773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1889773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1890773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 189144d92694SMartin K. Petersen 1892be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18935b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1894760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1895760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1896760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1897760f3b03SDouglas Gilbert */ 1898760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1899760f3b03SDouglas Gilbert arr[14] |= 0x40; 1900be1dd78dSEric Sandeen } 190144d92694SMartin K. Petersen 1902ecb8c258SBart Van Assche /* 1903ecb8c258SBart Van Assche * Since the scsi_debug READ CAPACITY implementation always reports the 1904ecb8c258SBart Van Assche * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices. 1905ecb8c258SBart Van Assche */ 1906ecb8c258SBart Van Assche if (devip->zmodel == BLK_ZONED_HM) 1907ecb8c258SBart Van Assche arr[12] |= 1 << 4; 1908ecb8c258SBart Van Assche 1909773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1910c6a44287SMartin K. Petersen 1911760f3b03SDouglas Gilbert if (have_dif_prot) { 1912773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1913c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1914c6a44287SMartin K. Petersen } 1915c6a44287SMartin K. Petersen 1916c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 19174e3ace00SYe Bin min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1918c65b1445SDouglas Gilbert } 1919c65b1445SDouglas Gilbert 19205a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 19215a09e398SHannes Reinecke 19225a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 19235a09e398SHannes Reinecke struct sdebug_dev_info *devip) 19245a09e398SHannes Reinecke { 192501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19265a09e398SHannes Reinecke unsigned char *arr; 19275a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 19285a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 1929f347c268SYe Bin u32 alen, n, rlen; 1930f347c268SYe Bin int ret; 19315a09e398SHannes Reinecke 1932773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19336f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19346f3cbf55SDouglas Gilbert if (! arr) 19356f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19365a09e398SHannes Reinecke /* 19375a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19385a09e398SHannes Reinecke * real and a fake port with no device connected. 19395a09e398SHannes Reinecke * So we create two port groups with one port each 19405a09e398SHannes Reinecke * and set the group with port B to unavailable. 19415a09e398SHannes Reinecke */ 19425a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19435a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19445a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19455a09e398SHannes Reinecke (devip->channel & 0x7f); 19465a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19475a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19485a09e398SHannes Reinecke 19495a09e398SHannes Reinecke /* 19505a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19515a09e398SHannes Reinecke */ 19525a09e398SHannes Reinecke n = 4; 1953b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19545a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19555a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19565a09e398SHannes Reinecke } else { 19575a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1958773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19595a09e398SHannes Reinecke } 1960773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1961773642d9SDouglas Gilbert n += 2; 19625a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19635a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19645a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19655a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19665a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19675a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1968773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1969773642d9SDouglas Gilbert n += 2; 19705a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19715a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1972773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1973773642d9SDouglas Gilbert n += 2; 19745a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19755a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19765a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19775a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19785a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19795a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1980773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1981773642d9SDouglas Gilbert n += 2; 19825a09e398SHannes Reinecke 19835a09e398SHannes Reinecke rlen = n - 4; 1984773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19855a09e398SHannes Reinecke 19865a09e398SHannes Reinecke /* 19875a09e398SHannes Reinecke * Return the smallest value of either 19885a09e398SHannes Reinecke * - The allocated length 19895a09e398SHannes Reinecke * - The constructed command length 19905a09e398SHannes Reinecke * - The maximum array size 19915a09e398SHannes Reinecke */ 1992f347c268SYe Bin rlen = min(alen, n); 19935a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1994f347c268SYe Bin min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19955a09e398SHannes Reinecke kfree(arr); 19965a09e398SHannes Reinecke return ret; 19975a09e398SHannes Reinecke } 19985a09e398SHannes Reinecke 1999fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 2000fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 200138d5c833SDouglas Gilbert { 200238d5c833SDouglas Gilbert bool rctd; 200338d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 200438d5c833SDouglas Gilbert u16 req_sa, u; 200538d5c833SDouglas Gilbert u32 alloc_len, a_len; 200638d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 200738d5c833SDouglas Gilbert const struct opcode_info_t *oip; 200838d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 200938d5c833SDouglas Gilbert u8 *arr; 201038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 201138d5c833SDouglas Gilbert 201238d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 201338d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 201438d5c833SDouglas Gilbert req_opcode = cmd[3]; 201538d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 201638d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 20176d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 201838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 201938d5c833SDouglas Gilbert return check_condition_result; 202038d5c833SDouglas Gilbert } 202138d5c833SDouglas Gilbert if (alloc_len > 8192) 202238d5c833SDouglas Gilbert a_len = 8192; 202338d5c833SDouglas Gilbert else 202438d5c833SDouglas Gilbert a_len = alloc_len; 202599531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 202638d5c833SDouglas Gilbert if (NULL == arr) { 202738d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 202838d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 202938d5c833SDouglas Gilbert return check_condition_result; 203038d5c833SDouglas Gilbert } 203138d5c833SDouglas Gilbert switch (reporting_opts) { 203238d5c833SDouglas Gilbert case 0: /* all commands */ 203338d5c833SDouglas Gilbert /* count number of commands */ 203438d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 203538d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 203638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 203738d5c833SDouglas Gilbert continue; 203838d5c833SDouglas Gilbert count += (oip->num_attached + 1); 203938d5c833SDouglas Gilbert } 204038d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 204138d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 204238d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 204338d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 204438d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 204538d5c833SDouglas Gilbert continue; 204638d5c833SDouglas Gilbert na = oip->num_attached; 204738d5c833SDouglas Gilbert arr[offset] = oip->opcode; 204838d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 204938d5c833SDouglas Gilbert if (rctd) 205038d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 205138d5c833SDouglas Gilbert if (FF_SA & oip->flags) 205238d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 205338d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 205438d5c833SDouglas Gilbert if (rctd) 205538d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 205638d5c833SDouglas Gilbert r_oip = oip; 205738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 205838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 205938d5c833SDouglas Gilbert continue; 206038d5c833SDouglas Gilbert offset += bump; 206138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 206238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 206338d5c833SDouglas Gilbert if (rctd) 206438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 206538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 206638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 206738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 206838d5c833SDouglas Gilbert arr + offset + 6); 206938d5c833SDouglas Gilbert if (rctd) 207038d5c833SDouglas Gilbert put_unaligned_be16(0xa, 207138d5c833SDouglas Gilbert arr + offset + 8); 207238d5c833SDouglas Gilbert } 207338d5c833SDouglas Gilbert oip = r_oip; 207438d5c833SDouglas Gilbert offset += bump; 207538d5c833SDouglas Gilbert } 207638d5c833SDouglas Gilbert break; 207738d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 207838d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 207938d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 208038d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 208138d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 208238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 208338d5c833SDouglas Gilbert supp = 1; 208438d5c833SDouglas Gilbert offset = 4; 208538d5c833SDouglas Gilbert } else { 208638d5c833SDouglas Gilbert if (1 == reporting_opts) { 208738d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 208838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 208938d5c833SDouglas Gilbert 2, 2); 209038d5c833SDouglas Gilbert kfree(arr); 209138d5c833SDouglas Gilbert return check_condition_result; 209238d5c833SDouglas Gilbert } 209338d5c833SDouglas Gilbert req_sa = 0; 209438d5c833SDouglas Gilbert } else if (2 == reporting_opts && 209538d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 209638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 209738d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 209838d5c833SDouglas Gilbert return check_condition_result; 209938d5c833SDouglas Gilbert } 210038d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 210138d5c833SDouglas Gilbert req_opcode == oip->opcode) 210238d5c833SDouglas Gilbert supp = 3; 210338d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 210438d5c833SDouglas Gilbert na = oip->num_attached; 210538d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 210638d5c833SDouglas Gilbert ++k, ++oip) { 210738d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 210838d5c833SDouglas Gilbert break; 210938d5c833SDouglas Gilbert } 211038d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 211138d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 211238d5c833SDouglas Gilbert na = oip->num_attached; 211338d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 211438d5c833SDouglas Gilbert ++k, ++oip) { 211538d5c833SDouglas Gilbert if (req_sa == oip->sa) 211638d5c833SDouglas Gilbert break; 211738d5c833SDouglas Gilbert } 211838d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 211938d5c833SDouglas Gilbert } else 212038d5c833SDouglas Gilbert supp = 3; 212138d5c833SDouglas Gilbert if (3 == supp) { 212238d5c833SDouglas Gilbert u = oip->len_mask[0]; 212338d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 212438d5c833SDouglas Gilbert arr[4] = oip->opcode; 212538d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 212638d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 212738d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 212838d5c833SDouglas Gilbert offset = 4 + u; 212938d5c833SDouglas Gilbert } else 213038d5c833SDouglas Gilbert offset = 4; 213138d5c833SDouglas Gilbert } 213238d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 213338d5c833SDouglas Gilbert if (rctd) { 213438d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 213538d5c833SDouglas Gilbert offset += 12; 213638d5c833SDouglas Gilbert } 213738d5c833SDouglas Gilbert break; 213838d5c833SDouglas Gilbert default: 213938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 214038d5c833SDouglas Gilbert kfree(arr); 214138d5c833SDouglas Gilbert return check_condition_result; 214238d5c833SDouglas Gilbert } 214338d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 214438d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 214538d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 214638d5c833SDouglas Gilbert kfree(arr); 214738d5c833SDouglas Gilbert return errsts; 214838d5c833SDouglas Gilbert } 214938d5c833SDouglas Gilbert 2150fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2151fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 215238d5c833SDouglas Gilbert { 215338d5c833SDouglas Gilbert bool repd; 215438d5c833SDouglas Gilbert u32 alloc_len, len; 215538d5c833SDouglas Gilbert u8 arr[16]; 215638d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 215738d5c833SDouglas Gilbert 215838d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 215938d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 216038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 216138d5c833SDouglas Gilbert if (alloc_len < 4) { 216238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 216338d5c833SDouglas Gilbert return check_condition_result; 216438d5c833SDouglas Gilbert } 216538d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 216638d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 216738d5c833SDouglas Gilbert if (repd) { 216838d5c833SDouglas Gilbert arr[3] = 0xc; 216938d5c833SDouglas Gilbert len = 16; 217038d5c833SDouglas Gilbert } else 217138d5c833SDouglas Gilbert len = 4; 217238d5c833SDouglas Gilbert 217338d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 217438d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 217538d5c833SDouglas Gilbert } 217638d5c833SDouglas Gilbert 21771da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21781da177e4SLinus Torvalds 21791da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21801da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21811da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21821da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21851da177e4SLinus Torvalds if (1 == pcontrol) 21861da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21871da177e4SLinus Torvalds return sizeof(err_recov_pg); 21881da177e4SLinus Torvalds } 21891da177e4SLinus Torvalds 21901da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21911da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21921da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21931da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21941da177e4SLinus Torvalds 21951da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21961da177e4SLinus Torvalds if (1 == pcontrol) 21971da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21981da177e4SLinus Torvalds return sizeof(disconnect_pg); 21991da177e4SLinus Torvalds } 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 22021da177e4SLinus Torvalds { /* Format device page for mode_sense */ 22031da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 22041da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 22051da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 22061da177e4SLinus Torvalds 22071da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2208773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2209773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2210773642d9SDouglas Gilbert if (sdebug_removable) 22111da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 22121da177e4SLinus Torvalds if (1 == pcontrol) 22131da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 22141da177e4SLinus Torvalds return sizeof(format_pg); 22151da177e4SLinus Torvalds } 22161da177e4SLinus Torvalds 2217fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2218fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2219fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2220fd32119bSDouglas Gilbert 22211da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 22221da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2223cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2224cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2225cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 22261da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 22271da177e4SLinus Torvalds 2228773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2229cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22301da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22311da177e4SLinus Torvalds if (1 == pcontrol) 2232cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2233cbf67842SDouglas Gilbert else if (2 == pcontrol) 2234cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22351da177e4SLinus Torvalds return sizeof(caching_pg); 22361da177e4SLinus Torvalds } 22371da177e4SLinus Torvalds 2238fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2239fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2240fd32119bSDouglas Gilbert 22411da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22421da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2243c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2244c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2245c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22461da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22471da177e4SLinus Torvalds 2248773642d9SDouglas Gilbert if (sdebug_dsense) 22491da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2250c65b1445SDouglas Gilbert else 2251c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2252c6a44287SMartin K. Petersen 2253773642d9SDouglas Gilbert if (sdebug_ato) 2254c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2255c6a44287SMartin K. Petersen 22561da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22571da177e4SLinus Torvalds if (1 == pcontrol) 2258c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2259c65b1445SDouglas Gilbert else if (2 == pcontrol) 2260c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22611da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 2264c65b1445SDouglas Gilbert 22651da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22661da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2267c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22681da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2269c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2270c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2271c65b1445SDouglas Gilbert 22721da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22731da177e4SLinus Torvalds if (1 == pcontrol) 2274c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2275c65b1445SDouglas Gilbert else if (2 == pcontrol) 2276c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22771da177e4SLinus Torvalds return sizeof(iec_m_pg); 22781da177e4SLinus Torvalds } 22791da177e4SLinus Torvalds 2280c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2281c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2282c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2283c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2284c65b1445SDouglas Gilbert 2285c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2286c65b1445SDouglas Gilbert if (1 == pcontrol) 2287c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2288c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2289c65b1445SDouglas Gilbert } 2290c65b1445SDouglas Gilbert 2291c65b1445SDouglas Gilbert 2292c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2293c65b1445SDouglas Gilbert int target_dev_id) 2294c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2295c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2296c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2297773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2298773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2299c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2300c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2301c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2302c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2303773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2304773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2305c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2306c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2307c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2308c65b1445SDouglas Gilbert }; 2309c65b1445SDouglas Gilbert int port_a, port_b; 2310c65b1445SDouglas Gilbert 23111b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 23121b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 23131b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 23141b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2315c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2316c65b1445SDouglas Gilbert port_b = port_a + 1; 2317c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2318773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2319773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2320c65b1445SDouglas Gilbert if (1 == pcontrol) 2321c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2322c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2323c65b1445SDouglas Gilbert } 2324c65b1445SDouglas Gilbert 2325c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2326c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2327c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2328c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2329c65b1445SDouglas Gilbert }; 2330c65b1445SDouglas Gilbert 2331c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2332c65b1445SDouglas Gilbert if (1 == pcontrol) 2333c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2334c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2335c65b1445SDouglas Gilbert } 2336c65b1445SDouglas Gilbert 23371da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23381da177e4SLinus Torvalds 2339fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2340fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23411da177e4SLinus Torvalds { 234223183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23431da177e4SLinus Torvalds unsigned char dev_spec; 234436e07d7eSGeorge Kennedy u32 alloc_len, offset, len; 234536e07d7eSGeorge Kennedy int target_dev_id; 2346c2248fc9SDouglas Gilbert int target = scp->device->id; 23471da177e4SLinus Torvalds unsigned char *ap; 23481da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 234901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2350d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23511da177e4SLinus Torvalds 2352760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23531da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23541da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23551da177e4SLinus Torvalds subpcode = cmd[3]; 23561da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2357760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2358760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 235964e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2360d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 236123183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 236223183910SDouglas Gilbert else 236323183910SDouglas Gilbert bd_len = 0; 2364773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23651da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23661da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2367cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23681da177e4SLinus Torvalds return check_condition_result; 23691da177e4SLinus Torvalds } 2370c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2371c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2372d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2373d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2374b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23759447b6ceSMartin K. Petersen if (sdebug_wp) 23769447b6ceSMartin K. Petersen dev_spec |= 0x80; 23779447b6ceSMartin K. Petersen } else 237823183910SDouglas Gilbert dev_spec = 0x0; 23791da177e4SLinus Torvalds if (msense_6) { 23801da177e4SLinus Torvalds arr[2] = dev_spec; 238123183910SDouglas Gilbert arr[3] = bd_len; 23821da177e4SLinus Torvalds offset = 4; 23831da177e4SLinus Torvalds } else { 23841da177e4SLinus Torvalds arr[3] = dev_spec; 238523183910SDouglas Gilbert if (16 == bd_len) 238623183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 238723183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23881da177e4SLinus Torvalds offset = 8; 23891da177e4SLinus Torvalds } 23901da177e4SLinus Torvalds ap = arr + offset; 239128898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 239228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 239328898873SFUJITA Tomonori 239423183910SDouglas Gilbert if (8 == bd_len) { 2395773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2396773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2397773642d9SDouglas Gilbert else 2398773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2399773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 240023183910SDouglas Gilbert offset += bd_len; 240123183910SDouglas Gilbert ap = arr + offset; 240223183910SDouglas Gilbert } else if (16 == bd_len) { 2403773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2404773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 240523183910SDouglas Gilbert offset += bd_len; 240623183910SDouglas Gilbert ap = arr + offset; 240723183910SDouglas Gilbert } 24081da177e4SLinus Torvalds 2409c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2410c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 241122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 24121da177e4SLinus Torvalds return check_condition_result; 24131da177e4SLinus Torvalds } 2414760f3b03SDouglas Gilbert bad_pcode = false; 2415760f3b03SDouglas Gilbert 24161da177e4SLinus Torvalds switch (pcode) { 24171da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 24181da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24191da177e4SLinus Torvalds offset += len; 24201da177e4SLinus Torvalds break; 24211da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 24221da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 24231da177e4SLinus Torvalds offset += len; 24241da177e4SLinus Torvalds break; 24251da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2426760f3b03SDouglas Gilbert if (is_disk) { 24271da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 24281da177e4SLinus Torvalds offset += len; 2429760f3b03SDouglas Gilbert } else 2430760f3b03SDouglas Gilbert bad_pcode = true; 24311da177e4SLinus Torvalds break; 24321da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2433d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24341da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24351da177e4SLinus Torvalds offset += len; 2436760f3b03SDouglas Gilbert } else 2437760f3b03SDouglas Gilbert bad_pcode = true; 24381da177e4SLinus Torvalds break; 24391da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24401da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24411da177e4SLinus Torvalds offset += len; 24421da177e4SLinus Torvalds break; 2443c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2444c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 244522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2446c65b1445SDouglas Gilbert return check_condition_result; 2447c65b1445SDouglas Gilbert } 2448c65b1445SDouglas Gilbert len = 0; 2449c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2450c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2451c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2452c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2453c65b1445SDouglas Gilbert target_dev_id); 2454c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2455c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2456c65b1445SDouglas Gilbert offset += len; 2457c65b1445SDouglas Gilbert break; 24581da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24591da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24601da177e4SLinus Torvalds offset += len; 24611da177e4SLinus Torvalds break; 24621da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2463c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24641da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24651da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2466760f3b03SDouglas Gilbert if (is_disk) { 2467760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2468760f3b03SDouglas Gilbert target); 2469760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2470760f3b03SDouglas Gilbert target); 2471d36da305SDouglas Gilbert } else if (is_zbc) { 2472d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2473d36da305SDouglas Gilbert target); 2474760f3b03SDouglas Gilbert } 24751da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2476c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2477c65b1445SDouglas Gilbert if (0xff == subpcode) { 2478c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2479c65b1445SDouglas Gilbert target, target_dev_id); 2480c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2481c65b1445SDouglas Gilbert } 24821da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2483760f3b03SDouglas Gilbert offset += len; 2484c65b1445SDouglas Gilbert } else { 248522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2486c65b1445SDouglas Gilbert return check_condition_result; 2487c65b1445SDouglas Gilbert } 24881da177e4SLinus Torvalds break; 24891da177e4SLinus Torvalds default: 2490760f3b03SDouglas Gilbert bad_pcode = true; 2491760f3b03SDouglas Gilbert break; 2492760f3b03SDouglas Gilbert } 2493760f3b03SDouglas Gilbert if (bad_pcode) { 249422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24951da177e4SLinus Torvalds return check_condition_result; 24961da177e4SLinus Torvalds } 24971da177e4SLinus Torvalds if (msense_6) 24981da177e4SLinus Torvalds arr[0] = offset - 1; 2499773642d9SDouglas Gilbert else 2500773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 250136e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 25021da177e4SLinus Torvalds } 25031da177e4SLinus Torvalds 2504c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2505c65b1445SDouglas Gilbert 2506fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2507fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2508c65b1445SDouglas Gilbert { 2509c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2510c2248fc9SDouglas Gilbert int param_len, res, mpage; 2511c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 251201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2513c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2514c65b1445SDouglas Gilbert 2515c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2516c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2517c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2518773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2519c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 252022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2521c65b1445SDouglas Gilbert return check_condition_result; 2522c65b1445SDouglas Gilbert } 2523c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2524c65b1445SDouglas Gilbert if (-1 == res) 2525773642d9SDouglas Gilbert return DID_ERROR << 16; 2526773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2527cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2528cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2529cbf67842SDouglas Gilbert __func__, param_len, res); 2530773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2531773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 2532e0a2c28dSGeorge Kennedy off = bd_len + (mselect6 ? 4 : 8); 2533e0a2c28dSGeorge Kennedy if (md_len > 2 || off >= res) { 253422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2535c65b1445SDouglas Gilbert return check_condition_result; 2536c65b1445SDouglas Gilbert } 2537c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2538c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2539c65b1445SDouglas Gilbert if (ps) { 254022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2541c65b1445SDouglas Gilbert return check_condition_result; 2542c65b1445SDouglas Gilbert } 2543c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2544773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2545c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2546c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2547cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2548c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2549c65b1445SDouglas Gilbert return check_condition_result; 2550c65b1445SDouglas Gilbert } 2551c65b1445SDouglas Gilbert switch (mpage) { 2552cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2553cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2554cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2555cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2556cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2557cbf67842SDouglas Gilbert } 2558cbf67842SDouglas Gilbert break; 2559c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2560c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2561c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2562c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25639447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25649447b6ceSMartin K. Petersen sdebug_wp = true; 25659447b6ceSMartin K. Petersen else 25669447b6ceSMartin K. Petersen sdebug_wp = false; 2567773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2568cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2569c65b1445SDouglas Gilbert } 2570c65b1445SDouglas Gilbert break; 2571c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2572c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2573c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2574c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2575cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2576c65b1445SDouglas Gilbert } 2577c65b1445SDouglas Gilbert break; 2578c65b1445SDouglas Gilbert default: 2579c65b1445SDouglas Gilbert break; 2580c65b1445SDouglas Gilbert } 258122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2582c65b1445SDouglas Gilbert return check_condition_result; 2583cbf67842SDouglas Gilbert set_mode_changed_ua: 2584cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2585cbf67842SDouglas Gilbert return 0; 2586c65b1445SDouglas Gilbert } 2587c65b1445SDouglas Gilbert 2588c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2589c65b1445SDouglas Gilbert { 2590c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2591c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2592c65b1445SDouglas Gilbert }; 2593c65b1445SDouglas Gilbert 2594c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2595c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2596c65b1445SDouglas Gilbert } 2597c65b1445SDouglas Gilbert 2598c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2599c65b1445SDouglas Gilbert { 2600c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2601c65b1445SDouglas Gilbert }; 2602c65b1445SDouglas Gilbert 2603c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2604c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2605c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2606c65b1445SDouglas Gilbert arr[5] = 0xff; 2607c65b1445SDouglas Gilbert } 2608c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2609c65b1445SDouglas Gilbert } 2610c65b1445SDouglas Gilbert 26110790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr) 26120790797aSDouglas Gilbert { 26130790797aSDouglas Gilbert unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8, 26140790797aSDouglas Gilbert 0x0, 40, 72, 0xff, 45, 18, 0, 0, 26150790797aSDouglas Gilbert 0x1, 0x0, 0x23, 0x8, 26160790797aSDouglas Gilbert 0x0, 55, 72, 35, 55, 45, 0, 0, 26170790797aSDouglas Gilbert }; 26180790797aSDouglas Gilbert 26190790797aSDouglas Gilbert memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg)); 26200790797aSDouglas Gilbert return sizeof(env_rep_l_spg); 26210790797aSDouglas Gilbert } 26220790797aSDouglas Gilbert 2623c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2624c65b1445SDouglas Gilbert 2625c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2626c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2627c65b1445SDouglas Gilbert { 262836e07d7eSGeorge Kennedy int ppc, sp, pcode, subpcode; 262936e07d7eSGeorge Kennedy u32 alloc_len, len, n; 2630c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 263101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2632c65b1445SDouglas Gilbert 2633c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2634c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2635c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2636c65b1445SDouglas Gilbert if (ppc || sp) { 263722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2638c65b1445SDouglas Gilbert return check_condition_result; 2639c65b1445SDouglas Gilbert } 2640c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 264123183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2642773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2643c65b1445SDouglas Gilbert arr[0] = pcode; 264423183910SDouglas Gilbert if (0 == subpcode) { 2645c65b1445SDouglas Gilbert switch (pcode) { 2646c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2647c65b1445SDouglas Gilbert n = 4; 2648c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2649c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2650c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2651c65b1445SDouglas Gilbert arr[3] = n - 4; 2652c65b1445SDouglas Gilbert break; 2653c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2654c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2655c65b1445SDouglas Gilbert break; 2656c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2657c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2658c65b1445SDouglas Gilbert break; 2659c65b1445SDouglas Gilbert default: 266022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2661c65b1445SDouglas Gilbert return check_condition_result; 2662c65b1445SDouglas Gilbert } 266323183910SDouglas Gilbert } else if (0xff == subpcode) { 266423183910SDouglas Gilbert arr[0] |= 0x40; 266523183910SDouglas Gilbert arr[1] = subpcode; 266623183910SDouglas Gilbert switch (pcode) { 266723183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 266823183910SDouglas Gilbert n = 4; 266923183910SDouglas Gilbert arr[n++] = 0x0; 267023183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 267123183910SDouglas Gilbert arr[n++] = 0x0; 267223183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 267323183910SDouglas Gilbert arr[n++] = 0xd; 267423183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26750790797aSDouglas Gilbert arr[n++] = 0xd; 26760790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26770790797aSDouglas Gilbert arr[n++] = 0xd; 26780790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0xd subpages */ 267923183910SDouglas Gilbert arr[n++] = 0x2f; 268023183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26810790797aSDouglas Gilbert arr[n++] = 0x2f; 26820790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0x2f subpages */ 268323183910SDouglas Gilbert arr[3] = n - 4; 268423183910SDouglas Gilbert break; 268523183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 268623183910SDouglas Gilbert n = 4; 268723183910SDouglas Gilbert arr[n++] = 0xd; 268823183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26890790797aSDouglas Gilbert arr[n++] = 0xd; 26900790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26910790797aSDouglas Gilbert arr[n++] = 0xd; 26920790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 269323183910SDouglas Gilbert arr[3] = n - 4; 269423183910SDouglas Gilbert break; 269523183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 269623183910SDouglas Gilbert n = 4; 269723183910SDouglas Gilbert arr[n++] = 0x2f; 269823183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26990790797aSDouglas Gilbert arr[n++] = 0x2f; 27000790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 270123183910SDouglas Gilbert arr[3] = n - 4; 270223183910SDouglas Gilbert break; 270323183910SDouglas Gilbert default: 270422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 270523183910SDouglas Gilbert return check_condition_result; 270623183910SDouglas Gilbert } 27070790797aSDouglas Gilbert } else if (subpcode > 0) { 27080790797aSDouglas Gilbert arr[0] |= 0x40; 27090790797aSDouglas Gilbert arr[1] = subpcode; 27100790797aSDouglas Gilbert if (pcode == 0xd && subpcode == 1) 27110790797aSDouglas Gilbert arr[3] = resp_env_rep_l_spg(arr + 4); 27120790797aSDouglas Gilbert else { 27130790797aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 27140790797aSDouglas Gilbert return check_condition_result; 27150790797aSDouglas Gilbert } 271623183910SDouglas Gilbert } else { 271722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 271823183910SDouglas Gilbert return check_condition_result; 271923183910SDouglas Gilbert } 272036e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 2721c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 272236e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 2723c65b1445SDouglas Gilbert } 2724c65b1445SDouglas Gilbert 2725f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2726f0d1cf93SDouglas Gilbert { 2727f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2728f0d1cf93SDouglas Gilbert } 2729f0d1cf93SDouglas Gilbert 2730f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2731f0d1cf93SDouglas Gilbert unsigned long long lba) 2732f0d1cf93SDouglas Gilbert { 27334a5fc1c6SDamien Le Moal u32 zno = lba >> devip->zsize_shift; 27344a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp; 27354a5fc1c6SDamien Le Moal 27364a5fc1c6SDamien Le Moal if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones) 27374a5fc1c6SDamien Le Moal return &devip->zstate[zno]; 27384a5fc1c6SDamien Le Moal 27394a5fc1c6SDamien Le Moal /* 27404a5fc1c6SDamien Le Moal * If the zone capacity is less than the zone size, adjust for gap 27414a5fc1c6SDamien Le Moal * zones. 27424a5fc1c6SDamien Le Moal */ 27434a5fc1c6SDamien Le Moal zno = 2 * zno - devip->nr_conv_zones; 27444a5fc1c6SDamien Le Moal WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones); 27454a5fc1c6SDamien Le Moal zsp = &devip->zstate[zno]; 27464a5fc1c6SDamien Le Moal if (lba >= zsp->z_start + zsp->z_size) 27474a5fc1c6SDamien Le Moal zsp++; 27484a5fc1c6SDamien Le Moal WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size); 27494a5fc1c6SDamien Le Moal return zsp; 2750f0d1cf93SDouglas Gilbert } 2751f0d1cf93SDouglas Gilbert 2752f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2753f0d1cf93SDouglas Gilbert { 275435dbe2b9SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_CNV; 2755f0d1cf93SDouglas Gilbert } 2756f0d1cf93SDouglas Gilbert 27574a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp) 27584a5fc1c6SDamien Le Moal { 27594a5fc1c6SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_GAP; 27604a5fc1c6SDamien Le Moal } 27614a5fc1c6SDamien Le Moal 27624a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp) 27634a5fc1c6SDamien Le Moal { 27644a5fc1c6SDamien Le Moal return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp); 27654a5fc1c6SDamien Le Moal } 27664a5fc1c6SDamien Le Moal 2767f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2768f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2769f0d1cf93SDouglas Gilbert { 2770f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2771f0d1cf93SDouglas Gilbert 27724a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2773f0d1cf93SDouglas Gilbert return; 2774f0d1cf93SDouglas Gilbert 2775f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2776f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2777f0d1cf93SDouglas Gilbert return; 2778f0d1cf93SDouglas Gilbert 2779f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2780f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2781f0d1cf93SDouglas Gilbert else 2782f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2783f0d1cf93SDouglas Gilbert 2784f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2785f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2786f0d1cf93SDouglas Gilbert } else { 2787f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2788f0d1cf93SDouglas Gilbert devip->nr_closed++; 2789f0d1cf93SDouglas Gilbert } 2790f0d1cf93SDouglas Gilbert } 2791f0d1cf93SDouglas Gilbert 2792f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2793f0d1cf93SDouglas Gilbert { 2794f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2795f0d1cf93SDouglas Gilbert unsigned int i; 2796f0d1cf93SDouglas Gilbert 2797f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2798f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2799f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2800f0d1cf93SDouglas Gilbert return; 2801f0d1cf93SDouglas Gilbert } 2802f0d1cf93SDouglas Gilbert } 2803f0d1cf93SDouglas Gilbert } 2804f0d1cf93SDouglas Gilbert 2805f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2806f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2807f0d1cf93SDouglas Gilbert { 2808f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2809f0d1cf93SDouglas Gilbert 28104a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2811f0d1cf93SDouglas Gilbert return; 2812f0d1cf93SDouglas Gilbert 2813f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2814f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2815f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2816f0d1cf93SDouglas Gilbert return; 2817f0d1cf93SDouglas Gilbert 2818f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2819f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2820f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2821f0d1cf93SDouglas Gilbert else if (devip->max_open && 2822f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2823f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2824f0d1cf93SDouglas Gilbert 2825f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2826f0d1cf93SDouglas Gilbert devip->nr_closed--; 2827f0d1cf93SDouglas Gilbert if (explicit) { 2828f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2829f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2830f0d1cf93SDouglas Gilbert } else { 2831f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2832f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2833f0d1cf93SDouglas Gilbert } 2834f0d1cf93SDouglas Gilbert } 2835f0d1cf93SDouglas Gilbert 2836566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip, 2837566d3c57SDamien Le Moal struct sdeb_zone_state *zsp) 2838566d3c57SDamien Le Moal { 2839566d3c57SDamien Le Moal switch (zsp->z_cond) { 2840566d3c57SDamien Le Moal case ZC2_IMPLICIT_OPEN: 2841566d3c57SDamien Le Moal devip->nr_imp_open--; 2842566d3c57SDamien Le Moal break; 2843566d3c57SDamien Le Moal case ZC3_EXPLICIT_OPEN: 2844566d3c57SDamien Le Moal devip->nr_exp_open--; 2845566d3c57SDamien Le Moal break; 2846566d3c57SDamien Le Moal default: 2847566d3c57SDamien Le Moal WARN_ONCE(true, "Invalid zone %llu condition %x\n", 2848566d3c57SDamien Le Moal zsp->z_start, zsp->z_cond); 2849566d3c57SDamien Le Moal break; 2850566d3c57SDamien Le Moal } 2851566d3c57SDamien Le Moal zsp->z_cond = ZC5_FULL; 2852566d3c57SDamien Le Moal } 2853566d3c57SDamien Le Moal 2854f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2855f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2856f0d1cf93SDouglas Gilbert { 2857f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 285864e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2859f0d1cf93SDouglas Gilbert 28604a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2861f0d1cf93SDouglas Gilbert return; 2862f0d1cf93SDouglas Gilbert 286335dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2864f0d1cf93SDouglas Gilbert zsp->z_wp += num; 286564e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2866566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 286764e14eceSDamien Le Moal return; 286864e14eceSDamien Le Moal } 286964e14eceSDamien Le Moal 287064e14eceSDamien Le Moal while (num) { 287164e14eceSDamien Le Moal if (lba != zsp->z_wp) 287264e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 287364e14eceSDamien Le Moal 287464e14eceSDamien Le Moal end = lba + num; 287564e14eceSDamien Le Moal if (end >= zend) { 287664e14eceSDamien Le Moal n = zend - lba; 287764e14eceSDamien Le Moal zsp->z_wp = zend; 287864e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 287964e14eceSDamien Le Moal n = num; 288064e14eceSDamien Le Moal zsp->z_wp = end; 288164e14eceSDamien Le Moal } else { 288264e14eceSDamien Le Moal n = num; 288364e14eceSDamien Le Moal } 288464e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2885566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 288664e14eceSDamien Le Moal 288764e14eceSDamien Le Moal num -= n; 288864e14eceSDamien Le Moal lba += n; 288964e14eceSDamien Le Moal if (num) { 289064e14eceSDamien Le Moal zsp++; 289164e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 289264e14eceSDamien Le Moal } 289364e14eceSDamien Le Moal } 2894f0d1cf93SDouglas Gilbert } 2895f0d1cf93SDouglas Gilbert 2896f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 28979447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 28981da177e4SLinus Torvalds { 2899f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2900f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2901f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2902f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2903f0d1cf93SDouglas Gilbert 2904f0d1cf93SDouglas Gilbert if (!write) { 290564e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 290664e14eceSDamien Le Moal return 0; 290764e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 29084a5fc1c6SDamien Le Moal if (zsp->z_type != zsp_end->z_type) { 2909f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2910f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2911f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2912f0d1cf93SDouglas Gilbert return check_condition_result; 2913f0d1cf93SDouglas Gilbert } 2914f0d1cf93SDouglas Gilbert return 0; 2915f0d1cf93SDouglas Gilbert } 2916f0d1cf93SDouglas Gilbert 29174a5fc1c6SDamien Le Moal /* Writing into a gap zone is not allowed */ 29184a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) { 29194a5fc1c6SDamien Le Moal mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 29204a5fc1c6SDamien Le Moal ATTEMPT_ACCESS_GAP); 29214a5fc1c6SDamien Le Moal return check_condition_result; 29224a5fc1c6SDamien Le Moal } 29234a5fc1c6SDamien Le Moal 2924f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2925f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2926f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2927f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2928f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2929f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2930f0d1cf93SDouglas Gilbert return check_condition_result; 2931f0d1cf93SDouglas Gilbert } 2932f0d1cf93SDouglas Gilbert return 0; 2933f0d1cf93SDouglas Gilbert } 2934f0d1cf93SDouglas Gilbert 293535dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2936f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2937f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2938f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2939f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2940f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2941f0d1cf93SDouglas Gilbert return check_condition_result; 2942f0d1cf93SDouglas Gilbert } 2943f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2944f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2945f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2946f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2947f0d1cf93SDouglas Gilbert return check_condition_result; 2948f0d1cf93SDouglas Gilbert } 2949f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2950f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2951f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2952f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2953f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2954f0d1cf93SDouglas Gilbert return check_condition_result; 2955f0d1cf93SDouglas Gilbert } 295664e14eceSDamien Le Moal } 2957f0d1cf93SDouglas Gilbert 2958f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2959f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2960f0d1cf93SDouglas Gilbert if (devip->max_open && 2961f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2962f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2963f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2964f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2965f0d1cf93SDouglas Gilbert return check_condition_result; 2966f0d1cf93SDouglas Gilbert } 2967f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2968f0d1cf93SDouglas Gilbert } 2969f0d1cf93SDouglas Gilbert 2970f0d1cf93SDouglas Gilbert return 0; 2971f0d1cf93SDouglas Gilbert } 2972f0d1cf93SDouglas Gilbert 2973f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2974f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2975f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2976f0d1cf93SDouglas Gilbert { 2977f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2978f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2979f0d1cf93SDouglas Gilbert 2980c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 298122017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 29821da177e4SLinus Torvalds return check_condition_result; 29831da177e4SLinus Torvalds } 2984c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2985c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 298622017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2987cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2988c65b1445SDouglas Gilbert return check_condition_result; 2989c65b1445SDouglas Gilbert } 29909447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 29919447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 29929447b6ceSMartin K. Petersen return check_condition_result; 29939447b6ceSMartin K. Petersen } 2994f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2995f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2996f0d1cf93SDouglas Gilbert 299719789100SFUJITA Tomonori return 0; 299819789100SFUJITA Tomonori } 299919789100SFUJITA Tomonori 3000b6ff8ca7SDouglas Gilbert /* 3001b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 3002b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 3003b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 3004b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 3005b6ff8ca7SDouglas Gilbert */ 3006b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 3007b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 300887c715dcSDouglas Gilbert { 3009b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 3010b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 3011b6ff8ca7SDouglas Gilbert return NULL; 3012b6ff8ca7SDouglas Gilbert } 3013b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 301487c715dcSDouglas Gilbert } 301587c715dcSDouglas Gilbert 3016a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 301787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 301887c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 301919789100SFUJITA Tomonori { 302019789100SFUJITA Tomonori int ret; 3021c2248fc9SDouglas Gilbert u64 block, rest = 0; 3022a4517511SAkinobu Mita enum dma_data_direction dir; 302387c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 302487c715dcSDouglas Gilbert u8 *fsp; 302519789100SFUJITA Tomonori 3026c2248fc9SDouglas Gilbert if (do_write) { 3027a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 30284f2c8bf6SDouglas Gilbert write_since_sync = true; 3029a4517511SAkinobu Mita } else { 3030a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 3031a4517511SAkinobu Mita } 3032a4517511SAkinobu Mita 303387c715dcSDouglas Gilbert if (!sdb->length || !sip) 3034a4517511SAkinobu Mita return 0; 303587c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 3036a4517511SAkinobu Mita return -1; 303787c715dcSDouglas Gilbert fsp = sip->storep; 303819789100SFUJITA Tomonori 303919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 304019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 304119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 304219789100SFUJITA Tomonori 3043386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 304487c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 30450a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 3046773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 3047a4517511SAkinobu Mita return ret; 3048a4517511SAkinobu Mita 3049a4517511SAkinobu Mita if (rest) { 3050386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 305187c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 30520a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 30530a7e69c7SDouglas Gilbert do_write); 3054a4517511SAkinobu Mita } 305519789100SFUJITA Tomonori 305619789100SFUJITA Tomonori return ret; 305719789100SFUJITA Tomonori } 305819789100SFUJITA Tomonori 305987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 306087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 306187c715dcSDouglas Gilbert { 306287c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 306387c715dcSDouglas Gilbert 306487c715dcSDouglas Gilbert if (!sdb->length) 306587c715dcSDouglas Gilbert return 0; 306687c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 306787c715dcSDouglas Gilbert return -1; 306887c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 306987c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 307087c715dcSDouglas Gilbert } 307187c715dcSDouglas Gilbert 307287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 307387c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 307438d5c833SDouglas Gilbert * return false. */ 307587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 3076c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 307738d5c833SDouglas Gilbert { 307838d5c833SDouglas Gilbert bool res; 307938d5c833SDouglas Gilbert u64 block, rest = 0; 308038d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 3081773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 308287c715dcSDouglas Gilbert u8 *fsp = sip->storep; 308338d5c833SDouglas Gilbert 308438d5c833SDouglas Gilbert block = do_div(lba, store_blks); 308538d5c833SDouglas Gilbert if (block + num > store_blks) 308638d5c833SDouglas Gilbert rest = block + num - store_blks; 308738d5c833SDouglas Gilbert 308887c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 308938d5c833SDouglas Gilbert if (!res) 309038d5c833SDouglas Gilbert return res; 309138d5c833SDouglas Gilbert if (rest) 309287c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 309338d5c833SDouglas Gilbert rest * lb_size); 309438d5c833SDouglas Gilbert if (!res) 309538d5c833SDouglas Gilbert return res; 3096c3e2fe92SDouglas Gilbert if (compare_only) 3097c3e2fe92SDouglas Gilbert return true; 309838d5c833SDouglas Gilbert arr += num * lb_size; 309987c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 310038d5c833SDouglas Gilbert if (rest) 310187c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 310238d5c833SDouglas Gilbert return res; 310338d5c833SDouglas Gilbert } 310438d5c833SDouglas Gilbert 310551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 3106beb40ea4SAkinobu Mita { 310751d648afSAkinobu Mita __be16 csum; 3108beb40ea4SAkinobu Mita 3109773642d9SDouglas Gilbert if (sdebug_guard) 311051d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 311151d648afSAkinobu Mita else 3112beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 311351d648afSAkinobu Mita 3114beb40ea4SAkinobu Mita return csum; 3115beb40ea4SAkinobu Mita } 3116beb40ea4SAkinobu Mita 31176ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3118beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3119beb40ea4SAkinobu Mita { 3120773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3121beb40ea4SAkinobu Mita 3122beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3123c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3124beb40ea4SAkinobu Mita (unsigned long)sector, 3125beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3126beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3127beb40ea4SAkinobu Mita return 0x01; 3128beb40ea4SAkinobu Mita } 31298475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3130beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3131c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3132c1287970STomas Winkler (unsigned long)sector); 3133beb40ea4SAkinobu Mita return 0x03; 3134beb40ea4SAkinobu Mita } 31358475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3136beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3137c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3138c1287970STomas Winkler (unsigned long)sector); 3139beb40ea4SAkinobu Mita return 0x03; 3140beb40ea4SAkinobu Mita } 3141beb40ea4SAkinobu Mita return 0; 3142beb40ea4SAkinobu Mita } 3143beb40ea4SAkinobu Mita 314487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 314565f72f2aSAkinobu Mita unsigned int sectors, bool read) 3146c6a44287SMartin K. Petersen { 3147be4e11beSAkinobu Mita size_t resid; 3148c6a44287SMartin K. Petersen void *paddr; 314987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3150b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 315187c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 315214faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3153be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3154c6a44287SMartin K. Petersen 3155e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3156e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3157c6a44287SMartin K. Petersen 315887c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 315987c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3160be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3161be4e11beSAkinobu Mita 3162be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 316387c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 316487c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3165be4e11beSAkinobu Mita size_t rest = 0; 316614faa944SAkinobu Mita 316714faa944SAkinobu Mita if (dif_store_end < start + len) 316814faa944SAkinobu Mita rest = start + len - dif_store_end; 3169c6a44287SMartin K. Petersen 3170be4e11beSAkinobu Mita paddr = miter.addr; 317114faa944SAkinobu Mita 317265f72f2aSAkinobu Mita if (read) 317365f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 317465f72f2aSAkinobu Mita else 317565f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 317665f72f2aSAkinobu Mita 317765f72f2aSAkinobu Mita if (rest) { 317865f72f2aSAkinobu Mita if (read) 317914faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 318065f72f2aSAkinobu Mita else 318165f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 318265f72f2aSAkinobu Mita } 3183c6a44287SMartin K. Petersen 3184e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3185c6a44287SMartin K. Petersen resid -= len; 3186c6a44287SMartin K. Petersen } 3187be4e11beSAkinobu Mita sg_miter_stop(&miter); 3188bb8c063cSAkinobu Mita } 3189c6a44287SMartin K. Petersen 319087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3191bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3192bb8c063cSAkinobu Mita { 3193f7be6772SMartin K. Petersen int ret = 0; 3194bb8c063cSAkinobu Mita unsigned int i; 3195bb8c063cSAkinobu Mita sector_t sector; 319687c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3197b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 319887c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3199bb8c063cSAkinobu Mita 3200c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3201bb8c063cSAkinobu Mita sector = start_sec + i; 320287c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3203bb8c063cSAkinobu Mita 320451d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3205bb8c063cSAkinobu Mita continue; 3206bb8c063cSAkinobu Mita 3207f7be6772SMartin K. Petersen /* 3208f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3209f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3210f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3211f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3212f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3213f7be6772SMartin K. Petersen */ 3214f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3215f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3216f7be6772SMartin K. Petersen sector, ei_lba); 3217bb8c063cSAkinobu Mita if (ret) { 3218bb8c063cSAkinobu Mita dif_errors++; 3219f7be6772SMartin K. Petersen break; 3220f7be6772SMartin K. Petersen } 3221bb8c063cSAkinobu Mita } 3222bb8c063cSAkinobu Mita } 3223bb8c063cSAkinobu Mita 322487c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3225c6a44287SMartin K. Petersen dix_reads++; 3226c6a44287SMartin K. Petersen 3227f7be6772SMartin K. Petersen return ret; 3228c6a44287SMartin K. Petersen } 3229c6a44287SMartin K. Petersen 32307109f370SDouglas Gilbert static inline void 32317109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip) 32327109f370SDouglas Gilbert { 3233e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3234e9c47801SDamien Le Moal if (sip) 3235e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3236e9c47801SDamien Le Moal else 3237e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3238e9c47801SDamien Le Moal } else { 32397109f370SDouglas Gilbert if (sip) 32407109f370SDouglas Gilbert read_lock(&sip->macc_lck); 32417109f370SDouglas Gilbert else 32427109f370SDouglas Gilbert read_lock(&sdeb_fake_rw_lck); 32437109f370SDouglas Gilbert } 3244e9c47801SDamien Le Moal } 32457109f370SDouglas Gilbert 32467109f370SDouglas Gilbert static inline void 32477109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip) 32487109f370SDouglas Gilbert { 3249e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3250e9c47801SDamien Le Moal if (sip) 3251e9c47801SDamien Le Moal __release(&sip->macc_lck); 3252e9c47801SDamien Le Moal else 3253e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3254e9c47801SDamien Le Moal } else { 32557109f370SDouglas Gilbert if (sip) 32567109f370SDouglas Gilbert read_unlock(&sip->macc_lck); 32577109f370SDouglas Gilbert else 32587109f370SDouglas Gilbert read_unlock(&sdeb_fake_rw_lck); 32597109f370SDouglas Gilbert } 3260e9c47801SDamien Le Moal } 32617109f370SDouglas Gilbert 32627109f370SDouglas Gilbert static inline void 32637109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip) 32647109f370SDouglas Gilbert { 3265e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3266e9c47801SDamien Le Moal if (sip) 3267e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3268e9c47801SDamien Le Moal else 3269e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3270e9c47801SDamien Le Moal } else { 32717109f370SDouglas Gilbert if (sip) 32727109f370SDouglas Gilbert write_lock(&sip->macc_lck); 32737109f370SDouglas Gilbert else 32747109f370SDouglas Gilbert write_lock(&sdeb_fake_rw_lck); 32757109f370SDouglas Gilbert } 3276e9c47801SDamien Le Moal } 32777109f370SDouglas Gilbert 32787109f370SDouglas Gilbert static inline void 32797109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip) 32807109f370SDouglas Gilbert { 3281e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3282e9c47801SDamien Le Moal if (sip) 3283e9c47801SDamien Le Moal __release(&sip->macc_lck); 3284e9c47801SDamien Le Moal else 3285e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3286e9c47801SDamien Le Moal } else { 32877109f370SDouglas Gilbert if (sip) 32887109f370SDouglas Gilbert write_unlock(&sip->macc_lck); 32897109f370SDouglas Gilbert else 32907109f370SDouglas Gilbert write_unlock(&sdeb_fake_rw_lck); 32917109f370SDouglas Gilbert } 3292e9c47801SDamien Le Moal } 32937109f370SDouglas Gilbert 3294fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 329519789100SFUJITA Tomonori { 329687c715dcSDouglas Gilbert bool check_prot; 3297c2248fc9SDouglas Gilbert u32 num; 3298c2248fc9SDouglas Gilbert u32 ei_lba; 329919789100SFUJITA Tomonori int ret; 330087c715dcSDouglas Gilbert u64 lba; 3301b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 330287c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 330319789100SFUJITA Tomonori 3304c2248fc9SDouglas Gilbert switch (cmd[0]) { 3305c2248fc9SDouglas Gilbert case READ_16: 3306c2248fc9SDouglas Gilbert ei_lba = 0; 3307c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3308c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3309c2248fc9SDouglas Gilbert check_prot = true; 3310c2248fc9SDouglas Gilbert break; 3311c2248fc9SDouglas Gilbert case READ_10: 3312c2248fc9SDouglas Gilbert ei_lba = 0; 3313c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3314c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3315c2248fc9SDouglas Gilbert check_prot = true; 3316c2248fc9SDouglas Gilbert break; 3317c2248fc9SDouglas Gilbert case READ_6: 3318c2248fc9SDouglas Gilbert ei_lba = 0; 3319c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3320c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3321c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3322c2248fc9SDouglas Gilbert check_prot = true; 3323c2248fc9SDouglas Gilbert break; 3324c2248fc9SDouglas Gilbert case READ_12: 3325c2248fc9SDouglas Gilbert ei_lba = 0; 3326c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3327c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3328c2248fc9SDouglas Gilbert check_prot = true; 3329c2248fc9SDouglas Gilbert break; 3330c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3331c2248fc9SDouglas Gilbert ei_lba = 0; 3332c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3333c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3334c2248fc9SDouglas Gilbert check_prot = false; 3335c2248fc9SDouglas Gilbert break; 3336c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3337c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3338c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3339c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3340c2248fc9SDouglas Gilbert check_prot = false; 3341c2248fc9SDouglas Gilbert break; 3342c2248fc9SDouglas Gilbert } 3343f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 33448475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3345c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3346c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3347c2248fc9SDouglas Gilbert return check_condition_result; 3348c2248fc9SDouglas Gilbert } 33498475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 33508475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3351c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3352c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3353c2248fc9SDouglas Gilbert "to DIF device\n"); 3354c2248fc9SDouglas Gilbert } 33553a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 33563a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3357c2248fc9SDouglas Gilbert num /= 2; 33583a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3359c2248fc9SDouglas Gilbert } 3360c2248fc9SDouglas Gilbert 33619447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 33629447b6ceSMartin K. Petersen if (ret) 33639447b6ceSMartin K. Petersen return ret; 3364f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3365d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3366d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3367c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3368c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3369c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3370c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3371c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 337232f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 337332f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3374c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3375c65b1445SDouglas Gilbert } 3376c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 33771da177e4SLinus Torvalds return check_condition_result; 33781da177e4SLinus Torvalds } 3379c6a44287SMartin K. Petersen 33807109f370SDouglas Gilbert sdeb_read_lock(sip); 33816c78cc06SAkinobu Mita 3382c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3383f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3384f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3385f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3386f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33877109f370SDouglas Gilbert sdeb_read_unlock(sip); 3388f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3389f7be6772SMartin K. Petersen return check_condition_result; 3390f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 33917109f370SDouglas Gilbert sdeb_read_unlock(sip); 3392f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3393c6a44287SMartin K. Petersen return illegal_condition_result; 3394c6a44287SMartin K. Petersen } 3395f7be6772SMartin K. Petersen break; 3396f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3397f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33987109f370SDouglas Gilbert sdeb_read_unlock(sip); 3399f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3400f7be6772SMartin K. Petersen return check_condition_result; 3401f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 34027109f370SDouglas Gilbert sdeb_read_unlock(sip); 3403f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3404f7be6772SMartin K. Petersen return illegal_condition_result; 3405f7be6772SMartin K. Petersen } 3406f7be6772SMartin K. Petersen break; 3407f7be6772SMartin K. Petersen } 3408c6a44287SMartin K. Petersen } 3409c6a44287SMartin K. Petersen 341087c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 34117109f370SDouglas Gilbert sdeb_read_unlock(sip); 3412f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3413a4517511SAkinobu Mita return DID_ERROR << 16; 3414a4517511SAkinobu Mita 341542d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3416a4517511SAkinobu Mita 34173a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 34183a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 34193a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 34203a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 34213a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3422c2248fc9SDouglas Gilbert return check_condition_result; 34233a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3424c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3425c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 34263a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3427c2248fc9SDouglas Gilbert return illegal_condition_result; 34283a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3429c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 34303a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3431c2248fc9SDouglas Gilbert return illegal_condition_result; 3432c2248fc9SDouglas Gilbert } 3433c2248fc9SDouglas Gilbert } 3434a4517511SAkinobu Mita return 0; 34351da177e4SLinus Torvalds } 34361da177e4SLinus Torvalds 3437c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3438395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3439c6a44287SMartin K. Petersen { 3440be4e11beSAkinobu Mita int ret; 34416ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3442be4e11beSAkinobu Mita void *daddr; 344365f72f2aSAkinobu Mita sector_t sector = start_sec; 3444c6a44287SMartin K. Petersen int ppage_offset; 3445be4e11beSAkinobu Mita int dpage_offset; 3446be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3447be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3448c6a44287SMartin K. Petersen 3449c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3450c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3451c6a44287SMartin K. Petersen 3452be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3453be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3454be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3455be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3456be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3457c6a44287SMartin K. Petersen 3458be4e11beSAkinobu Mita /* For each protection page */ 3459be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3460be4e11beSAkinobu Mita dpage_offset = 0; 3461be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3462be4e11beSAkinobu Mita ret = 0x01; 3463be4e11beSAkinobu Mita goto out; 3464c6a44287SMartin K. Petersen } 3465c6a44287SMartin K. Petersen 3466be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 34676ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3468be4e11beSAkinobu Mita /* If we're at the end of the current 3469be4e11beSAkinobu Mita * data page advance to the next one 3470be4e11beSAkinobu Mita */ 3471be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3472be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3473be4e11beSAkinobu Mita ret = 0x01; 3474be4e11beSAkinobu Mita goto out; 3475be4e11beSAkinobu Mita } 3476be4e11beSAkinobu Mita dpage_offset = 0; 3477be4e11beSAkinobu Mita } 3478c6a44287SMartin K. Petersen 3479be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3480be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3481be4e11beSAkinobu Mita 3482f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3483be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3484c78be80dSMartin K. Petersen if (ret) 3485395cef03SMartin K. Petersen goto out; 3486395cef03SMartin K. Petersen } 3487395cef03SMartin K. Petersen 3488c6a44287SMartin K. Petersen sector++; 3489395cef03SMartin K. Petersen ei_lba++; 3490773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3491c6a44287SMartin K. Petersen } 3492be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3493be4e11beSAkinobu Mita sg_miter_stop(&diter); 3494c6a44287SMartin K. Petersen } 3495be4e11beSAkinobu Mita sg_miter_stop(&piter); 3496c6a44287SMartin K. Petersen 349765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3498c6a44287SMartin K. Petersen dix_writes++; 3499c6a44287SMartin K. Petersen 3500c6a44287SMartin K. Petersen return 0; 3501c6a44287SMartin K. Petersen 3502c6a44287SMartin K. Petersen out: 3503c6a44287SMartin K. Petersen dif_errors++; 3504be4e11beSAkinobu Mita sg_miter_stop(&diter); 3505be4e11beSAkinobu Mita sg_miter_stop(&piter); 3506c6a44287SMartin K. Petersen return ret; 3507c6a44287SMartin K. Petersen } 3508c6a44287SMartin K. Petersen 3509b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3510b90ebc3dSAkinobu Mita { 3511773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3512773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3513773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3514b90ebc3dSAkinobu Mita return lba; 3515b90ebc3dSAkinobu Mita } 3516b90ebc3dSAkinobu Mita 3517b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3518b90ebc3dSAkinobu Mita { 3519773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3520a027b5b9SAkinobu Mita 3521773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3522773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3523a027b5b9SAkinobu Mita return lba; 3524a027b5b9SAkinobu Mita } 3525a027b5b9SAkinobu Mita 352687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 352787c715dcSDouglas Gilbert unsigned int *num) 352844d92694SMartin K. Petersen { 3529b90ebc3dSAkinobu Mita sector_t end; 3530b90ebc3dSAkinobu Mita unsigned int mapped; 3531b90ebc3dSAkinobu Mita unsigned long index; 3532b90ebc3dSAkinobu Mita unsigned long next; 353344d92694SMartin K. Petersen 3534b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 353587c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 353644d92694SMartin K. Petersen 353744d92694SMartin K. Petersen if (mapped) 353887c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 353944d92694SMartin K. Petersen else 354087c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 354144d92694SMartin K. Petersen 3542b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 354344d92694SMartin K. Petersen *num = end - lba; 354444d92694SMartin K. Petersen return mapped; 354544d92694SMartin K. Petersen } 354644d92694SMartin K. Petersen 354787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 354887c715dcSDouglas Gilbert unsigned int len) 354944d92694SMartin K. Petersen { 355044d92694SMartin K. Petersen sector_t end = lba + len; 355144d92694SMartin K. Petersen 355244d92694SMartin K. Petersen while (lba < end) { 3553b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 355444d92694SMartin K. Petersen 3555b90ebc3dSAkinobu Mita if (index < map_size) 355687c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 355744d92694SMartin K. Petersen 3558b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 355944d92694SMartin K. Petersen } 356044d92694SMartin K. Petersen } 356144d92694SMartin K. Petersen 356287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 356387c715dcSDouglas Gilbert unsigned int len) 356444d92694SMartin K. Petersen { 356544d92694SMartin K. Petersen sector_t end = lba + len; 356687c715dcSDouglas Gilbert u8 *fsp = sip->storep; 356744d92694SMartin K. Petersen 356844d92694SMartin K. Petersen while (lba < end) { 3569b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 357044d92694SMartin K. Petersen 3571b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3572773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3573b90ebc3dSAkinobu Mita index < map_size) { 357487c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3575760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 357687c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3577760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3578773642d9SDouglas Gilbert sdebug_sector_size * 3579773642d9SDouglas Gilbert sdebug_unmap_granularity); 3580be1dd78dSEric Sandeen } 358187c715dcSDouglas Gilbert if (sip->dif_storep) { 358287c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 358387c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3584773642d9SDouglas Gilbert sdebug_unmap_granularity); 3585e9926b43SAkinobu Mita } 3586b90ebc3dSAkinobu Mita } 3587b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 358844d92694SMartin K. Petersen } 358944d92694SMartin K. Petersen } 359044d92694SMartin K. Petersen 3591fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 35921da177e4SLinus Torvalds { 359387c715dcSDouglas Gilbert bool check_prot; 3594c2248fc9SDouglas Gilbert u32 num; 3595c2248fc9SDouglas Gilbert u32 ei_lba; 359619789100SFUJITA Tomonori int ret; 359787c715dcSDouglas Gilbert u64 lba; 3598b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 359987c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 36001da177e4SLinus Torvalds 3601c2248fc9SDouglas Gilbert switch (cmd[0]) { 3602c2248fc9SDouglas Gilbert case WRITE_16: 3603c2248fc9SDouglas Gilbert ei_lba = 0; 3604c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3605c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3606c2248fc9SDouglas Gilbert check_prot = true; 3607c2248fc9SDouglas Gilbert break; 3608c2248fc9SDouglas Gilbert case WRITE_10: 3609c2248fc9SDouglas Gilbert ei_lba = 0; 3610c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3611c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3612c2248fc9SDouglas Gilbert check_prot = true; 3613c2248fc9SDouglas Gilbert break; 3614c2248fc9SDouglas Gilbert case WRITE_6: 3615c2248fc9SDouglas Gilbert ei_lba = 0; 3616c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3617c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3618c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3619c2248fc9SDouglas Gilbert check_prot = true; 3620c2248fc9SDouglas Gilbert break; 3621c2248fc9SDouglas Gilbert case WRITE_12: 3622c2248fc9SDouglas Gilbert ei_lba = 0; 3623c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3624c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3625c2248fc9SDouglas Gilbert check_prot = true; 3626c2248fc9SDouglas Gilbert break; 3627c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3628c2248fc9SDouglas Gilbert ei_lba = 0; 3629c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3630c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3631c2248fc9SDouglas Gilbert check_prot = false; 3632c2248fc9SDouglas Gilbert break; 3633c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3634c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3635c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3636c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3637c2248fc9SDouglas Gilbert check_prot = false; 3638c2248fc9SDouglas Gilbert break; 3639c2248fc9SDouglas Gilbert } 3640f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 36418475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3642c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3643c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3644c2248fc9SDouglas Gilbert return check_condition_result; 3645c2248fc9SDouglas Gilbert } 36468475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 36478475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3648c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3649c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3650c2248fc9SDouglas Gilbert "to DIF device\n"); 3651c2248fc9SDouglas Gilbert } 3652f0d1cf93SDouglas Gilbert 36537109f370SDouglas Gilbert sdeb_write_lock(sip); 3654f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3655f0d1cf93SDouglas Gilbert if (ret) { 36567109f370SDouglas Gilbert sdeb_write_unlock(sip); 3657f0d1cf93SDouglas Gilbert return ret; 3658f0d1cf93SDouglas Gilbert } 36596c78cc06SAkinobu Mita 3660c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3661f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3662f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3663f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3664f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 36657109f370SDouglas Gilbert sdeb_write_unlock(sip); 3666f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3667c6a44287SMartin K. Petersen return illegal_condition_result; 3668f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36697109f370SDouglas Gilbert sdeb_write_unlock(sip); 3670f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3671f7be6772SMartin K. Petersen return check_condition_result; 3672f7be6772SMartin K. Petersen } 3673f7be6772SMartin K. Petersen break; 3674f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3675f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 36767109f370SDouglas Gilbert sdeb_write_unlock(sip); 3677f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3678f7be6772SMartin K. Petersen return illegal_condition_result; 3679f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36807109f370SDouglas Gilbert sdeb_write_unlock(sip); 3681f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3682f7be6772SMartin K. Petersen return check_condition_result; 3683f7be6772SMartin K. Petersen } 3684f7be6772SMartin K. Petersen break; 3685c6a44287SMartin K. Petersen } 3686c6a44287SMartin K. Petersen } 3687c6a44287SMartin K. Petersen 368887c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3689f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 369087c715dcSDouglas Gilbert map_region(sip, lba, num); 3691f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3692f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3693f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 36947109f370SDouglas Gilbert sdeb_write_unlock(sip); 3695f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3696773642d9SDouglas Gilbert return DID_ERROR << 16; 3697c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3698c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3699c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3700cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3701773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 370244d92694SMartin K. Petersen 37033a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 37043a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 37053a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 37063a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 37073a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3708c2248fc9SDouglas Gilbert return check_condition_result; 37093a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3710c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3711c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 37123a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3713c2248fc9SDouglas Gilbert return illegal_condition_result; 37143a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3715c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 37163a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3717c2248fc9SDouglas Gilbert return illegal_condition_result; 3718c2248fc9SDouglas Gilbert } 3719c2248fc9SDouglas Gilbert } 37201da177e4SLinus Torvalds return 0; 37211da177e4SLinus Torvalds } 37221da177e4SLinus Torvalds 3723481b5e5cSDouglas Gilbert /* 3724481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3725481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3726481b5e5cSDouglas Gilbert */ 3727481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3728481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3729481b5e5cSDouglas Gilbert { 3730481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3731481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3732481b5e5cSDouglas Gilbert u8 *up; 3733b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3734481b5e5cSDouglas Gilbert u8 wrprotect; 3735481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3736481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3737481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3738481b5e5cSDouglas Gilbert u32 ei_lba; 3739481b5e5cSDouglas Gilbert u64 lba; 3740481b5e5cSDouglas Gilbert int ret, res; 3741481b5e5cSDouglas Gilbert bool is_16; 3742481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3743481b5e5cSDouglas Gilbert 3744481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3745481b5e5cSDouglas Gilbert is_16 = false; 3746481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3747481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3748481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3749481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3750481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3751481b5e5cSDouglas Gilbert is_16 = true; 3752481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3753481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3754481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3755481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3756481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3757481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3758481b5e5cSDouglas Gilbert wrprotect) { 3759481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3760481b5e5cSDouglas Gilbert return illegal_condition_result; 3761481b5e5cSDouglas Gilbert } 3762481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3763481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3764481b5e5cSDouglas Gilbert wrprotect == 0) 3765481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3766481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3767481b5e5cSDouglas Gilbert } 3768481b5e5cSDouglas Gilbert } 3769481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3770481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3771481b5e5cSDouglas Gilbert if (lbdof == 0) { 3772481b5e5cSDouglas Gilbert if (sdebug_verbose) 3773481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3774481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3775481b5e5cSDouglas Gilbert my_name, __func__); 3776481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3777481b5e5cSDouglas Gilbert return illegal_condition_result; 3778481b5e5cSDouglas Gilbert } 3779481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3780481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3781481b5e5cSDouglas Gilbert if (sdebug_verbose) 3782481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3783481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3784481b5e5cSDouglas Gilbert my_name, __func__); 3785481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3786481b5e5cSDouglas Gilbert return illegal_condition_result; 3787481b5e5cSDouglas Gilbert } 3788481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3789481b5e5cSDouglas Gilbert if (lrdp == NULL) 3790481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3791481b5e5cSDouglas Gilbert if (sdebug_verbose) 3792481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3793481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3794481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3795481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3796481b5e5cSDouglas Gilbert if (res == -1) { 3797481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3798481b5e5cSDouglas Gilbert goto err_out; 3799481b5e5cSDouglas Gilbert } 3800481b5e5cSDouglas Gilbert 38017109f370SDouglas Gilbert sdeb_write_lock(sip); 3802481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3803481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3804481b5e5cSDouglas Gilbert cum_lb = 0; 3805481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3806481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3807481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3808481b5e5cSDouglas Gilbert if (sdebug_verbose) 3809481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3810481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3811481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3812481b5e5cSDouglas Gilbert if (num == 0) 3813481b5e5cSDouglas Gilbert continue; 38149447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3815481b5e5cSDouglas Gilbert if (ret) 3816481b5e5cSDouglas Gilbert goto err_out_unlock; 3817481b5e5cSDouglas Gilbert num_by = num * lb_size; 3818481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3819481b5e5cSDouglas Gilbert 3820481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3821481b5e5cSDouglas Gilbert if (sdebug_verbose) 3822481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3823481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3824481b5e5cSDouglas Gilbert my_name, __func__); 3825481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3826481b5e5cSDouglas Gilbert 0); 3827481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3828481b5e5cSDouglas Gilbert goto err_out_unlock; 3829481b5e5cSDouglas Gilbert } 3830481b5e5cSDouglas Gilbert 3831481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3832481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3833481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3834481b5e5cSDouglas Gilbert ei_lba); 3835481b5e5cSDouglas Gilbert 3836481b5e5cSDouglas Gilbert if (prot_ret) { 3837481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3838481b5e5cSDouglas Gilbert prot_ret); 3839481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3840481b5e5cSDouglas Gilbert goto err_out_unlock; 3841481b5e5cSDouglas Gilbert } 3842481b5e5cSDouglas Gilbert } 3843481b5e5cSDouglas Gilbert 384487c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3845f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3846f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3847f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3848481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 384987c715dcSDouglas Gilbert map_region(sip, lba, num); 3850481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3851481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3852481b5e5cSDouglas Gilbert goto err_out_unlock; 3853481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3854481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3855481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3856481b5e5cSDouglas Gilbert my_name, num_by, ret); 3857481b5e5cSDouglas Gilbert 38583a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 38593a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 38603a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 38613a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 38623a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 38633a90a63dSDouglas Gilbert ret = check_condition_result; 3864481b5e5cSDouglas Gilbert goto err_out_unlock; 38653a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3866481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 38673a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 38683a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3869481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3870481b5e5cSDouglas Gilbert goto err_out_unlock; 38713a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 38723a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 38733a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3874481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3875481b5e5cSDouglas Gilbert goto err_out_unlock; 3876481b5e5cSDouglas Gilbert } 3877481b5e5cSDouglas Gilbert } 3878481b5e5cSDouglas Gilbert sg_off += num_by; 3879481b5e5cSDouglas Gilbert cum_lb += num; 3880481b5e5cSDouglas Gilbert } 3881481b5e5cSDouglas Gilbert ret = 0; 3882481b5e5cSDouglas Gilbert err_out_unlock: 38837109f370SDouglas Gilbert sdeb_write_unlock(sip); 3884481b5e5cSDouglas Gilbert err_out: 3885481b5e5cSDouglas Gilbert kfree(lrdp); 3886481b5e5cSDouglas Gilbert return ret; 3887481b5e5cSDouglas Gilbert } 3888481b5e5cSDouglas Gilbert 3889fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3890fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 389144d92694SMartin K. Petersen { 3892f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3893f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 389444d92694SMartin K. Petersen unsigned long long i; 389540d07b52SDouglas Gilbert u64 block, lbaa; 389687c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 389787c715dcSDouglas Gilbert int ret; 389887c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3899b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 390040d07b52SDouglas Gilbert u8 *fs1p; 390187c715dcSDouglas Gilbert u8 *fsp; 390244d92694SMartin K. Petersen 39037109f370SDouglas Gilbert sdeb_write_lock(sip); 390444d92694SMartin K. Petersen 3905f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3906f0d1cf93SDouglas Gilbert if (ret) { 39077109f370SDouglas Gilbert sdeb_write_unlock(sip); 3908f0d1cf93SDouglas Gilbert return ret; 3909f0d1cf93SDouglas Gilbert } 3910f0d1cf93SDouglas Gilbert 39119ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 391287c715dcSDouglas Gilbert unmap_region(sip, lba, num); 391344d92694SMartin K. Petersen goto out; 391444d92694SMartin K. Petersen } 391540d07b52SDouglas Gilbert lbaa = lba; 391640d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3917c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 391887c715dcSDouglas Gilbert fsp = sip->storep; 391987c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3920c2248fc9SDouglas Gilbert if (ndob) { 392140d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3922c2248fc9SDouglas Gilbert ret = 0; 3923c2248fc9SDouglas Gilbert } else 392440d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 392544d92694SMartin K. Petersen 392644d92694SMartin K. Petersen if (-1 == ret) { 39277109f370SDouglas Gilbert sdeb_write_unlock(sip); 3928773642d9SDouglas Gilbert return DID_ERROR << 16; 392940d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3930c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3931e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 393240d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 393344d92694SMartin K. Petersen 393444d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 393540d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 393640d07b52SDouglas Gilbert lbaa = lba + i; 393740d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 393887c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 393940d07b52SDouglas Gilbert } 39409ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 394187c715dcSDouglas Gilbert map_region(sip, lba, num); 3942f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3943f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3944f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 394544d92694SMartin K. Petersen out: 39467109f370SDouglas Gilbert sdeb_write_unlock(sip); 394744d92694SMartin K. Petersen 394844d92694SMartin K. Petersen return 0; 394944d92694SMartin K. Petersen } 395044d92694SMartin K. Petersen 3951fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3952fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3953c2248fc9SDouglas Gilbert { 3954c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3955c2248fc9SDouglas Gilbert u32 lba; 3956c2248fc9SDouglas Gilbert u16 num; 3957c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3958c2248fc9SDouglas Gilbert bool unmap = false; 3959c2248fc9SDouglas Gilbert 3960c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3961773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3962c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3963c2248fc9SDouglas Gilbert return check_condition_result; 3964c2248fc9SDouglas Gilbert } else 3965c2248fc9SDouglas Gilbert unmap = true; 3966c2248fc9SDouglas Gilbert } 3967c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3968c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3969773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3970c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3971c2248fc9SDouglas Gilbert return check_condition_result; 3972c2248fc9SDouglas Gilbert } 3973c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3974c2248fc9SDouglas Gilbert } 3975c2248fc9SDouglas Gilbert 3976fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3977fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3978c2248fc9SDouglas Gilbert { 3979c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3980c2248fc9SDouglas Gilbert u64 lba; 3981c2248fc9SDouglas Gilbert u32 num; 3982c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3983c2248fc9SDouglas Gilbert bool unmap = false; 3984c2248fc9SDouglas Gilbert bool ndob = false; 3985c2248fc9SDouglas Gilbert 3986c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3987773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3988c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3989c2248fc9SDouglas Gilbert return check_condition_result; 3990c2248fc9SDouglas Gilbert } else 3991c2248fc9SDouglas Gilbert unmap = true; 3992c2248fc9SDouglas Gilbert } 3993c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3994c2248fc9SDouglas Gilbert ndob = true; 3995c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3996c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3997773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3998c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3999c2248fc9SDouglas Gilbert return check_condition_result; 4000c2248fc9SDouglas Gilbert } 4001c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 4002c2248fc9SDouglas Gilbert } 4003c2248fc9SDouglas Gilbert 4004acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 4005acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 4006acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 4007fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 4008fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 4009acafd0b9SEwan D. Milne { 4010acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 4011acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 4012acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 4013acafd0b9SEwan D. Milne u8 mode; 4014acafd0b9SEwan D. Milne 4015acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 4016acafd0b9SEwan D. Milne switch (mode) { 4017acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 4018acafd0b9SEwan D. Milne /* set UAs on this device only */ 4019acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4020acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 4021acafd0b9SEwan D. Milne break; 4022acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 4023acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 4024acafd0b9SEwan D. Milne break; 4025acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 4026acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 4027acafd0b9SEwan D. Milne list_for_each_entry(dp, 4028acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4029acafd0b9SEwan D. Milne dev_list) 4030acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 4031acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 4032acafd0b9SEwan D. Milne if (devip != dp) 4033acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 4034acafd0b9SEwan D. Milne dp->uas_bm); 4035acafd0b9SEwan D. Milne } 4036acafd0b9SEwan D. Milne break; 4037acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 4038acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 4039acafd0b9SEwan D. Milne list_for_each_entry(dp, 4040acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4041acafd0b9SEwan D. Milne dev_list) 4042acafd0b9SEwan D. Milne if (dp->target == sdp->id) 4043acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 4044acafd0b9SEwan D. Milne dp->uas_bm); 4045acafd0b9SEwan D. Milne break; 4046acafd0b9SEwan D. Milne default: 4047acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 4048acafd0b9SEwan D. Milne break; 4049acafd0b9SEwan D. Milne } 4050acafd0b9SEwan D. Milne return 0; 4051acafd0b9SEwan D. Milne } 4052acafd0b9SEwan D. Milne 4053fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 4054fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 405538d5c833SDouglas Gilbert { 405638d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 405738d5c833SDouglas Gilbert u8 *arr; 4058b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 405938d5c833SDouglas Gilbert u64 lba; 406038d5c833SDouglas Gilbert u32 dnum; 4061773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 406238d5c833SDouglas Gilbert u8 num; 406338d5c833SDouglas Gilbert int ret; 4064d467d31fSDouglas Gilbert int retval = 0; 406538d5c833SDouglas Gilbert 4066d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 406738d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 406838d5c833SDouglas Gilbert if (0 == num) 406938d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 40708475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 407138d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 407238d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 407338d5c833SDouglas Gilbert return check_condition_result; 407438d5c833SDouglas Gilbert } 40758475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 40768475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 407738d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 407838d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 407938d5c833SDouglas Gilbert "to DIF device\n"); 40809447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 40819447b6ceSMartin K. Petersen if (ret) 40829447b6ceSMartin K. Petersen return ret; 4083d467d31fSDouglas Gilbert dnum = 2 * num; 40846396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 4085d467d31fSDouglas Gilbert if (NULL == arr) { 4086d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4087d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 4088d467d31fSDouglas Gilbert return check_condition_result; 4089d467d31fSDouglas Gilbert } 409038d5c833SDouglas Gilbert 40917109f370SDouglas Gilbert sdeb_write_lock(sip); 409238d5c833SDouglas Gilbert 409387c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 409438d5c833SDouglas Gilbert if (ret == -1) { 4095d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 4096d467d31fSDouglas Gilbert goto cleanup; 4097773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 409838d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 409938d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 410038d5c833SDouglas Gilbert dnum * lb_size, ret); 4101c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 410238d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4103d467d31fSDouglas Gilbert retval = check_condition_result; 4104d467d31fSDouglas Gilbert goto cleanup; 410538d5c833SDouglas Gilbert } 410638d5c833SDouglas Gilbert if (scsi_debug_lbp()) 410787c715dcSDouglas Gilbert map_region(sip, lba, num); 4108d467d31fSDouglas Gilbert cleanup: 41097109f370SDouglas Gilbert sdeb_write_unlock(sip); 4110d467d31fSDouglas Gilbert kfree(arr); 4111d467d31fSDouglas Gilbert return retval; 411238d5c833SDouglas Gilbert } 411338d5c833SDouglas Gilbert 411444d92694SMartin K. Petersen struct unmap_block_desc { 411544d92694SMartin K. Petersen __be64 lba; 411644d92694SMartin K. Petersen __be32 blocks; 411744d92694SMartin K. Petersen __be32 __reserved; 411844d92694SMartin K. Petersen }; 411944d92694SMartin K. Petersen 4120fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 412144d92694SMartin K. Petersen { 412244d92694SMartin K. Petersen unsigned char *buf; 412344d92694SMartin K. Petersen struct unmap_block_desc *desc; 4124b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 412544d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 412644d92694SMartin K. Petersen int ret; 412744d92694SMartin K. Petersen 4128c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 4129c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 4130c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 4131c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 413244d92694SMartin K. Petersen 413344d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 4134773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 4135c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 413644d92694SMartin K. Petersen return check_condition_result; 4137c2248fc9SDouglas Gilbert } 413844d92694SMartin K. Petersen 4139b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 4140c2248fc9SDouglas Gilbert if (!buf) { 4141c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4142c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 4143c2248fc9SDouglas Gilbert return check_condition_result; 4144c2248fc9SDouglas Gilbert } 4145c2248fc9SDouglas Gilbert 4146c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 414744d92694SMartin K. Petersen 414844d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 414944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 415044d92694SMartin K. Petersen 415144d92694SMartin K. Petersen desc = (void *)&buf[8]; 415244d92694SMartin K. Petersen 41537109f370SDouglas Gilbert sdeb_write_lock(sip); 41546c78cc06SAkinobu Mita 415544d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 415644d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 415744d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 415844d92694SMartin K. Petersen 41599447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 416044d92694SMartin K. Petersen if (ret) 416144d92694SMartin K. Petersen goto out; 416244d92694SMartin K. Petersen 416387c715dcSDouglas Gilbert unmap_region(sip, lba, num); 416444d92694SMartin K. Petersen } 416544d92694SMartin K. Petersen 416644d92694SMartin K. Petersen ret = 0; 416744d92694SMartin K. Petersen 416844d92694SMartin K. Petersen out: 41697109f370SDouglas Gilbert sdeb_write_unlock(sip); 417044d92694SMartin K. Petersen kfree(buf); 417144d92694SMartin K. Petersen 417244d92694SMartin K. Petersen return ret; 417344d92694SMartin K. Petersen } 417444d92694SMartin K. Petersen 417544d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 417644d92694SMartin K. Petersen 4177fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4178fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 417944d92694SMartin K. Petersen { 4180c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4181c2248fc9SDouglas Gilbert u64 lba; 4182c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 418344d92694SMartin K. Petersen int ret; 418487c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 418544d92694SMartin K. Petersen 4186c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4187c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 418844d92694SMartin K. Petersen 418944d92694SMartin K. Petersen if (alloc_len < 24) 419044d92694SMartin K. Petersen return 0; 419144d92694SMartin K. Petersen 41929447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 419344d92694SMartin K. Petersen if (ret) 419444d92694SMartin K. Petersen return ret; 419544d92694SMartin K. Petersen 4196b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4197b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4198b6ff8ca7SDouglas Gilbert 419987c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4200b6ff8ca7SDouglas Gilbert } else { 4201c2248fc9SDouglas Gilbert mapped = 1; 4202c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4203c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4204c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4205c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4206c2248fc9SDouglas Gilbert else 4207c2248fc9SDouglas Gilbert num = 0xffffffff; 4208c2248fc9SDouglas Gilbert } 420944d92694SMartin K. Petersen 421044d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4211c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4212c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4213c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4214c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 421544d92694SMartin K. Petersen 4216c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 421744d92694SMartin K. Petersen } 421844d92694SMartin K. Petersen 421980c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 422080c49563SDouglas Gilbert struct sdebug_dev_info *devip) 422180c49563SDouglas Gilbert { 42224f2c8bf6SDouglas Gilbert int res = 0; 422380c49563SDouglas Gilbert u64 lba; 422480c49563SDouglas Gilbert u32 num_blocks; 422580c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 422680c49563SDouglas Gilbert 422780c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 422880c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 422980c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 423080c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 423180c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 423280c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 423380c49563SDouglas Gilbert } 423480c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 423580c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 423680c49563SDouglas Gilbert return check_condition_result; 423780c49563SDouglas Gilbert } 4238fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 42394f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 42404f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 42414f2c8bf6SDouglas Gilbert write_since_sync = false; 42424f2c8bf6SDouglas Gilbert return res; 424380c49563SDouglas Gilbert } 424480c49563SDouglas Gilbert 4245ed9f3e25SDouglas Gilbert /* 4246ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4247ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4248ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4249ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4250ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4251ed9f3e25SDouglas Gilbert */ 4252ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4253ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4254ed9f3e25SDouglas Gilbert { 4255ed9f3e25SDouglas Gilbert int res = 0; 4256ed9f3e25SDouglas Gilbert u64 lba; 4257ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4258ed9f3e25SDouglas Gilbert u32 nblks; 4259ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4260b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4261b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4262ed9f3e25SDouglas Gilbert 4263ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4264ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4265ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4266ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4267ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4268ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4269ed9f3e25SDouglas Gilbert } 4270ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4271ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4272ed9f3e25SDouglas Gilbert return check_condition_result; 4273ed9f3e25SDouglas Gilbert } 4274ed9f3e25SDouglas Gilbert if (!fsp) 4275ed9f3e25SDouglas Gilbert goto fini; 4276ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4277ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4278ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4279ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4280ed9f3e25SDouglas Gilbert 4281ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 42827109f370SDouglas Gilbert sdeb_read_lock(sip); 4283ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4284ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4285ed9f3e25SDouglas Gilbert if (rest) 4286ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 42877109f370SDouglas Gilbert sdeb_read_unlock(sip); 4288ed9f3e25SDouglas Gilbert fini: 4289ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4290ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4291ed9f3e25SDouglas Gilbert return res | condition_met_result; 4292ed9f3e25SDouglas Gilbert } 4293ed9f3e25SDouglas Gilbert 4294fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4295fb0cc8d1SDouglas Gilbert 42968d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 42978d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 42988d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 42998d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 43008d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 43018d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 43028d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 43038d039e22SDouglas Gilbert */ 43041da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 43051da177e4SLinus Torvalds struct sdebug_dev_info *devip) 43061da177e4SLinus Torvalds { 430701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 43088d039e22SDouglas Gilbert unsigned int alloc_len; 43098d039e22SDouglas Gilbert unsigned char select_report; 43108d039e22SDouglas Gilbert u64 lun; 43118d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4312fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 43138d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 43148d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 43158d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 43168d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4317fb0cc8d1SDouglas Gilbert int k, j, n, res; 4318fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4319fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 43201da177e4SLinus Torvalds 432119c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 43228d039e22SDouglas Gilbert 43238d039e22SDouglas Gilbert select_report = cmd[2]; 43248d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 43258d039e22SDouglas Gilbert 43268d039e22SDouglas Gilbert if (alloc_len < 4) { 43278d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 43288d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 43291da177e4SLinus Torvalds return check_condition_result; 43301da177e4SLinus Torvalds } 43318d039e22SDouglas Gilbert 43328d039e22SDouglas Gilbert switch (select_report) { 43338d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4334773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 43358d039e22SDouglas Gilbert wlun_cnt = 0; 43368d039e22SDouglas Gilbert break; 43378d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4338c65b1445SDouglas Gilbert lun_cnt = 0; 43398d039e22SDouglas Gilbert wlun_cnt = 1; 43408d039e22SDouglas Gilbert break; 43418d039e22SDouglas Gilbert case 2: /* all LUNs */ 43428d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 43438d039e22SDouglas Gilbert wlun_cnt = 1; 43448d039e22SDouglas Gilbert break; 43458d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 43468d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 43478d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 43488d039e22SDouglas Gilbert default: 43498d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 43508d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 43518d039e22SDouglas Gilbert return check_condition_result; 43528d039e22SDouglas Gilbert } 43538d039e22SDouglas Gilbert 43548d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4355c65b1445SDouglas Gilbert --lun_cnt; 43568d039e22SDouglas Gilbert 43578d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4358fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4359fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 43608d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 43618d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 43628d039e22SDouglas Gilbert 4363fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 43648d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4365fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4366fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4367fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4368fb0cc8d1SDouglas Gilbert if (k == 0) { 4369fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4370fb0cc8d1SDouglas Gilbert ++lun_p; 4371fb0cc8d1SDouglas Gilbert j = 1; 4372fb0cc8d1SDouglas Gilbert } 4373fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4374fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4375fb0cc8d1SDouglas Gilbert break; 4376fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4377ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4378ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4379fb0cc8d1SDouglas Gilbert } 4380fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4381fb0cc8d1SDouglas Gilbert break; 4382fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4383fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4384fb0cc8d1SDouglas Gilbert if (res) 4385fb0cc8d1SDouglas Gilbert return res; 4386fb0cc8d1SDouglas Gilbert off_rsp += n; 4387fb0cc8d1SDouglas Gilbert } 4388fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4389fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4390fb0cc8d1SDouglas Gilbert ++j; 4391fb0cc8d1SDouglas Gilbert } 4392fb0cc8d1SDouglas Gilbert if (j > 0) 4393fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 43948d039e22SDouglas Gilbert return res; 43951da177e4SLinus Torvalds } 43961da177e4SLinus Torvalds 4397c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4398c3e2fe92SDouglas Gilbert { 4399c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4400c3e2fe92SDouglas Gilbert u8 bytchk; 4401c3e2fe92SDouglas Gilbert int ret, j; 4402c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4403c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4404c3e2fe92SDouglas Gilbert u64 lba; 4405c3e2fe92SDouglas Gilbert u8 *arr; 4406c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4407b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4408c3e2fe92SDouglas Gilbert 4409c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4410c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4411c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4412c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4413c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4414c3e2fe92SDouglas Gilbert return check_condition_result; 4415c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4416c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4417c3e2fe92SDouglas Gilbert } 4418c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4419c3e2fe92SDouglas Gilbert case VERIFY_16: 4420c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4421c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4422c3e2fe92SDouglas Gilbert break; 4423c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4424c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4425c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4426c3e2fe92SDouglas Gilbert break; 4427c3e2fe92SDouglas Gilbert default: 4428c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4429c3e2fe92SDouglas Gilbert return check_condition_result; 4430c3e2fe92SDouglas Gilbert } 44313344b58bSGeorge Kennedy if (vnum == 0) 44323344b58bSGeorge Kennedy return 0; /* not an error */ 4433c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4434c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4435c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4436c3e2fe92SDouglas Gilbert if (ret) 4437c3e2fe92SDouglas Gilbert return ret; 4438c3e2fe92SDouglas Gilbert 4439c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4440c3e2fe92SDouglas Gilbert if (!arr) { 4441c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4442c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4443c3e2fe92SDouglas Gilbert return check_condition_result; 4444c3e2fe92SDouglas Gilbert } 4445c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 44467109f370SDouglas Gilbert sdeb_read_lock(sip); 4447c3e2fe92SDouglas Gilbert 4448c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4449c3e2fe92SDouglas Gilbert if (ret == -1) { 4450c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4451c3e2fe92SDouglas Gilbert goto cleanup; 4452c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4453c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4454c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4455c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4456c3e2fe92SDouglas Gilbert } 4457c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4458c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4459c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4460c3e2fe92SDouglas Gilbert } 4461c3e2fe92SDouglas Gilbert ret = 0; 4462c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4463c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4464c3e2fe92SDouglas Gilbert ret = check_condition_result; 4465c3e2fe92SDouglas Gilbert goto cleanup; 4466c3e2fe92SDouglas Gilbert } 4467c3e2fe92SDouglas Gilbert cleanup: 44687109f370SDouglas Gilbert sdeb_read_unlock(sip); 4469c3e2fe92SDouglas Gilbert kfree(arr); 4470c3e2fe92SDouglas Gilbert return ret; 4471c3e2fe92SDouglas Gilbert } 4472c3e2fe92SDouglas Gilbert 4473f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4474f0d1cf93SDouglas Gilbert 4475897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */ 4476f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4477f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4478f0d1cf93SDouglas Gilbert { 44794a5fc1c6SDamien Le Moal unsigned int rep_max_zones, nrz = 0; 4480f0d1cf93SDouglas Gilbert int ret = 0; 4481f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4482f0d1cf93SDouglas Gilbert bool partial; 4483f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4484f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4485f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 44864a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp = NULL; 4487b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4488f0d1cf93SDouglas Gilbert 4489f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4490f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4491f0d1cf93SDouglas Gilbert return check_condition_result; 4492f0d1cf93SDouglas Gilbert } 4493f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4494f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 44953344b58bSGeorge Kennedy if (alloc_len == 0) 44963344b58bSGeorge Kennedy return 0; /* not an error */ 4497f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4498f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4499f0d1cf93SDouglas Gilbert 4500f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4501f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4502f0d1cf93SDouglas Gilbert return check_condition_result; 4503f0d1cf93SDouglas Gilbert } 4504f0d1cf93SDouglas Gilbert 45054a5fc1c6SDamien Le Moal rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD); 4506f0d1cf93SDouglas Gilbert 45077db0e0c8SShin'ichiro Kawasaki arr = kzalloc(alloc_len, GFP_ATOMIC); 4508f0d1cf93SDouglas Gilbert if (!arr) { 4509f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4510f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4511f0d1cf93SDouglas Gilbert return check_condition_result; 4512f0d1cf93SDouglas Gilbert } 4513f0d1cf93SDouglas Gilbert 45147109f370SDouglas Gilbert sdeb_read_lock(sip); 4515f0d1cf93SDouglas Gilbert 4516f0d1cf93SDouglas Gilbert desc = arr + 64; 45174a5fc1c6SDamien Le Moal for (lba = zs_lba; lba < sdebug_capacity; 45184a5fc1c6SDamien Le Moal lba = zsp->z_start + zsp->z_size) { 45194a5fc1c6SDamien Le Moal if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba)) 4520f0d1cf93SDouglas Gilbert break; 4521f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4522f0d1cf93SDouglas Gilbert switch (rep_opts) { 4523f0d1cf93SDouglas Gilbert case 0x00: 4524f0d1cf93SDouglas Gilbert /* All zones */ 4525f0d1cf93SDouglas Gilbert break; 4526f0d1cf93SDouglas Gilbert case 0x01: 4527f0d1cf93SDouglas Gilbert /* Empty zones */ 4528f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4529f0d1cf93SDouglas Gilbert continue; 4530f0d1cf93SDouglas Gilbert break; 4531f0d1cf93SDouglas Gilbert case 0x02: 4532f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4533f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4534f0d1cf93SDouglas Gilbert continue; 4535f0d1cf93SDouglas Gilbert break; 4536f0d1cf93SDouglas Gilbert case 0x03: 4537f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4538f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4539f0d1cf93SDouglas Gilbert continue; 4540f0d1cf93SDouglas Gilbert break; 4541f0d1cf93SDouglas Gilbert case 0x04: 4542f0d1cf93SDouglas Gilbert /* Closed zones */ 4543f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4544f0d1cf93SDouglas Gilbert continue; 4545f0d1cf93SDouglas Gilbert break; 4546f0d1cf93SDouglas Gilbert case 0x05: 4547f0d1cf93SDouglas Gilbert /* Full zones */ 4548f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4549f0d1cf93SDouglas Gilbert continue; 4550f0d1cf93SDouglas Gilbert break; 4551f0d1cf93SDouglas Gilbert case 0x06: 4552f0d1cf93SDouglas Gilbert case 0x07: 4553f0d1cf93SDouglas Gilbert case 0x10: 4554f0d1cf93SDouglas Gilbert /* 455564e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 455664e14eceSDamien Le Moal * not emulated: no zones to report; 4557f0d1cf93SDouglas Gilbert */ 4558f0d1cf93SDouglas Gilbert continue; 455964e14eceSDamien Le Moal case 0x11: 456064e14eceSDamien Le Moal /* non-seq-resource set */ 456164e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 456264e14eceSDamien Le Moal continue; 456364e14eceSDamien Le Moal break; 45644a5fc1c6SDamien Le Moal case 0x3e: 45654a5fc1c6SDamien Le Moal /* All zones except gap zones. */ 45664a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) 45674a5fc1c6SDamien Le Moal continue; 45684a5fc1c6SDamien Le Moal break; 4569f0d1cf93SDouglas Gilbert case 0x3f: 4570f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 45714a5fc1c6SDamien Le Moal if (zbc_zone_is_seq(zsp)) 4572f0d1cf93SDouglas Gilbert continue; 4573f0d1cf93SDouglas Gilbert break; 4574f0d1cf93SDouglas Gilbert default: 4575f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4576f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4577f0d1cf93SDouglas Gilbert ret = check_condition_result; 4578f0d1cf93SDouglas Gilbert goto fini; 4579f0d1cf93SDouglas Gilbert } 4580f0d1cf93SDouglas Gilbert 4581f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4582f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 458364e14eceSDamien Le Moal desc[0] = zsp->z_type; 4584f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 458564e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 458664e14eceSDamien Le Moal desc[1] |= 1 << 1; 4587f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4588f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4589f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4590f0d1cf93SDouglas Gilbert desc += 64; 4591f0d1cf93SDouglas Gilbert } 4592f0d1cf93SDouglas Gilbert 4593f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4594f0d1cf93SDouglas Gilbert break; 4595f0d1cf93SDouglas Gilbert 4596f0d1cf93SDouglas Gilbert nrz++; 4597f0d1cf93SDouglas Gilbert } 4598f0d1cf93SDouglas Gilbert 4599f0d1cf93SDouglas Gilbert /* Report header */ 46004a5fc1c6SDamien Le Moal /* Zone list length. */ 4601f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 46024a5fc1c6SDamien Le Moal /* Maximum LBA */ 4603f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 46044a5fc1c6SDamien Le Moal /* Zone starting LBA granularity. */ 46054a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 46064a5fc1c6SDamien Le Moal put_unaligned_be64(devip->zsize, arr + 16); 4607f0d1cf93SDouglas Gilbert 4608f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 460936e07d7eSGeorge Kennedy ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)); 4610f0d1cf93SDouglas Gilbert 4611f0d1cf93SDouglas Gilbert fini: 46127109f370SDouglas Gilbert sdeb_read_unlock(sip); 4613f0d1cf93SDouglas Gilbert kfree(arr); 4614f0d1cf93SDouglas Gilbert return ret; 4615f0d1cf93SDouglas Gilbert } 4616f0d1cf93SDouglas Gilbert 4617f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4618f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4619f0d1cf93SDouglas Gilbert { 4620f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4621f0d1cf93SDouglas Gilbert unsigned int i; 4622f0d1cf93SDouglas Gilbert 4623f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4624f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4625f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4626f0d1cf93SDouglas Gilbert } 4627f0d1cf93SDouglas Gilbert } 4628f0d1cf93SDouglas Gilbert 4629f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4630f0d1cf93SDouglas Gilbert { 4631f0d1cf93SDouglas Gilbert int res = 0; 4632f0d1cf93SDouglas Gilbert u64 z_id; 4633f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4634f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4635f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4636f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4637b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4638f0d1cf93SDouglas Gilbert 4639f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4640f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4641f0d1cf93SDouglas Gilbert return check_condition_result; 4642f0d1cf93SDouglas Gilbert } 4643f0d1cf93SDouglas Gilbert 46447109f370SDouglas Gilbert sdeb_write_lock(sip); 4645f0d1cf93SDouglas Gilbert 4646f0d1cf93SDouglas Gilbert if (all) { 4647f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4648f0d1cf93SDouglas Gilbert if (devip->max_open && 4649f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4650f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4651f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4652f0d1cf93SDouglas Gilbert res = check_condition_result; 4653f0d1cf93SDouglas Gilbert goto fini; 4654f0d1cf93SDouglas Gilbert } 4655f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4656f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4657f0d1cf93SDouglas Gilbert goto fini; 4658f0d1cf93SDouglas Gilbert } 4659f0d1cf93SDouglas Gilbert 4660f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4661f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4662f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4663f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4664f0d1cf93SDouglas Gilbert res = check_condition_result; 4665f0d1cf93SDouglas Gilbert goto fini; 4666f0d1cf93SDouglas Gilbert } 4667f0d1cf93SDouglas Gilbert 4668f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4669f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 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 if (zbc_zone_is_conv(zsp)) { 4675f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4676f0d1cf93SDouglas Gilbert res = check_condition_result; 4677f0d1cf93SDouglas Gilbert goto fini; 4678f0d1cf93SDouglas Gilbert } 4679f0d1cf93SDouglas Gilbert 4680f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4681f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4682f0d1cf93SDouglas Gilbert goto fini; 4683f0d1cf93SDouglas Gilbert 4684f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4685f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4686f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4687f0d1cf93SDouglas Gilbert res = check_condition_result; 4688f0d1cf93SDouglas Gilbert goto fini; 4689f0d1cf93SDouglas Gilbert } 4690f0d1cf93SDouglas Gilbert 4691f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4692f0d1cf93SDouglas Gilbert fini: 46937109f370SDouglas Gilbert sdeb_write_unlock(sip); 4694f0d1cf93SDouglas Gilbert return res; 4695f0d1cf93SDouglas Gilbert } 4696f0d1cf93SDouglas Gilbert 4697f0d1cf93SDouglas Gilbert static void zbc_close_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_close_zone(devip, &devip->zstate[i]); 4703f0d1cf93SDouglas Gilbert } 4704f0d1cf93SDouglas Gilbert 4705f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4706f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4707f0d1cf93SDouglas Gilbert { 4708f0d1cf93SDouglas Gilbert int res = 0; 4709f0d1cf93SDouglas Gilbert u64 z_id; 4710f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4711f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 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_close_all(devip); 4724f0d1cf93SDouglas Gilbert goto fini; 4725f0d1cf93SDouglas Gilbert } 4726f0d1cf93SDouglas Gilbert 4727f0d1cf93SDouglas Gilbert /* Close 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_close_zone(devip, zsp); 4748f0d1cf93SDouglas Gilbert fini: 47497109f370SDouglas Gilbert sdeb_write_unlock(sip); 4750f0d1cf93SDouglas Gilbert return res; 4751f0d1cf93SDouglas Gilbert } 4752f0d1cf93SDouglas Gilbert 4753f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4754f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4755f0d1cf93SDouglas Gilbert { 4756f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4757f0d1cf93SDouglas Gilbert 4758f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4759f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4760f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4761f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4762f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4763f0d1cf93SDouglas Gilbert devip->nr_closed--; 4764f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4765f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4766f0d1cf93SDouglas Gilbert } 4767f0d1cf93SDouglas Gilbert } 4768f0d1cf93SDouglas Gilbert 4769f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4770f0d1cf93SDouglas Gilbert { 4771f0d1cf93SDouglas Gilbert unsigned int i; 4772f0d1cf93SDouglas Gilbert 4773f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4774f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4775f0d1cf93SDouglas Gilbert } 4776f0d1cf93SDouglas Gilbert 4777f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4778f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4779f0d1cf93SDouglas Gilbert { 4780f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4781f0d1cf93SDouglas Gilbert int res = 0; 4782f0d1cf93SDouglas Gilbert u64 z_id; 4783f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4784f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4785b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4786f0d1cf93SDouglas Gilbert 4787f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4788f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4789f0d1cf93SDouglas Gilbert return check_condition_result; 4790f0d1cf93SDouglas Gilbert } 4791f0d1cf93SDouglas Gilbert 47927109f370SDouglas Gilbert sdeb_write_lock(sip); 4793f0d1cf93SDouglas Gilbert 4794f0d1cf93SDouglas Gilbert if (all) { 4795f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4796f0d1cf93SDouglas Gilbert goto fini; 4797f0d1cf93SDouglas Gilbert } 4798f0d1cf93SDouglas Gilbert 4799f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4800f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4801f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4802f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4803f0d1cf93SDouglas Gilbert res = check_condition_result; 4804f0d1cf93SDouglas Gilbert goto fini; 4805f0d1cf93SDouglas Gilbert } 4806f0d1cf93SDouglas Gilbert 4807f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4808f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4809f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4810f0d1cf93SDouglas Gilbert res = check_condition_result; 4811f0d1cf93SDouglas Gilbert goto fini; 4812f0d1cf93SDouglas Gilbert } 4813f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4814f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4815f0d1cf93SDouglas Gilbert res = check_condition_result; 4816f0d1cf93SDouglas Gilbert goto fini; 4817f0d1cf93SDouglas Gilbert } 4818f0d1cf93SDouglas Gilbert 4819f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4820f0d1cf93SDouglas Gilbert fini: 48217109f370SDouglas Gilbert sdeb_write_unlock(sip); 4822f0d1cf93SDouglas Gilbert return res; 4823f0d1cf93SDouglas Gilbert } 4824f0d1cf93SDouglas Gilbert 4825f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4826f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4827f0d1cf93SDouglas Gilbert { 4828f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 48292d62253eSShin'ichiro Kawasaki struct sdeb_store_info *sip = devip2sip(devip, false); 4830f0d1cf93SDouglas Gilbert 48314a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 4832f0d1cf93SDouglas Gilbert return; 4833f0d1cf93SDouglas Gilbert 4834f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4835f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4836f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4837f0d1cf93SDouglas Gilbert 4838f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4839f0d1cf93SDouglas Gilbert devip->nr_closed--; 4840f0d1cf93SDouglas Gilbert 48412d62253eSShin'ichiro Kawasaki if (zsp->z_wp > zsp->z_start) 48422d62253eSShin'ichiro Kawasaki memset(sip->storep + zsp->z_start * sdebug_sector_size, 0, 48432d62253eSShin'ichiro Kawasaki (zsp->z_wp - zsp->z_start) * sdebug_sector_size); 48442d62253eSShin'ichiro Kawasaki 484564e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4846f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4847f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4848f0d1cf93SDouglas Gilbert } 4849f0d1cf93SDouglas Gilbert 4850f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4851f0d1cf93SDouglas Gilbert { 4852f0d1cf93SDouglas Gilbert unsigned int i; 4853f0d1cf93SDouglas Gilbert 4854f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4855f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4856f0d1cf93SDouglas Gilbert } 4857f0d1cf93SDouglas Gilbert 4858f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4859f0d1cf93SDouglas Gilbert { 4860f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4861f0d1cf93SDouglas Gilbert int res = 0; 4862f0d1cf93SDouglas Gilbert u64 z_id; 4863f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4864f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4865b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4866f0d1cf93SDouglas Gilbert 4867f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4868f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4869f0d1cf93SDouglas Gilbert return check_condition_result; 4870f0d1cf93SDouglas Gilbert } 4871f0d1cf93SDouglas Gilbert 48727109f370SDouglas Gilbert sdeb_write_lock(sip); 4873f0d1cf93SDouglas Gilbert 4874f0d1cf93SDouglas Gilbert if (all) { 4875f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4876f0d1cf93SDouglas Gilbert goto fini; 4877f0d1cf93SDouglas Gilbert } 4878f0d1cf93SDouglas Gilbert 4879f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4880f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4881f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4882f0d1cf93SDouglas Gilbert res = check_condition_result; 4883f0d1cf93SDouglas Gilbert goto fini; 4884f0d1cf93SDouglas Gilbert } 4885f0d1cf93SDouglas Gilbert 4886f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4887f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4888f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4889f0d1cf93SDouglas Gilbert res = check_condition_result; 4890f0d1cf93SDouglas Gilbert goto fini; 4891f0d1cf93SDouglas Gilbert } 4892f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4893f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4894f0d1cf93SDouglas Gilbert res = check_condition_result; 4895f0d1cf93SDouglas Gilbert goto fini; 4896f0d1cf93SDouglas Gilbert } 4897f0d1cf93SDouglas Gilbert 4898f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4899f0d1cf93SDouglas Gilbert fini: 49007109f370SDouglas Gilbert sdeb_write_unlock(sip); 4901f0d1cf93SDouglas Gilbert return res; 4902f0d1cf93SDouglas Gilbert } 4903f0d1cf93SDouglas Gilbert 4904c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4905c4837394SDouglas Gilbert { 4906c10fa55fSJohn Garry u16 hwq; 4907a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4908c10fa55fSJohn Garry 4909c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4910c4837394SDouglas Gilbert 4911458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4912458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4913458df78bSBart Van Assche hwq = 0; 4914f7c4cdc7SJohn Garry 4915458df78bSBart Van Assche return sdebug_q_arr + hwq; 4916c4837394SDouglas Gilbert } 4917c4837394SDouglas Gilbert 4918c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4919c10fa55fSJohn Garry { 4920a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4921c10fa55fSJohn Garry } 4922c10fa55fSJohn Garry 4923c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4924fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 49251da177e4SLinus Torvalds { 49267382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4927c4837394SDouglas Gilbert int qc_idx; 4928cbf67842SDouglas Gilbert int retiring = 0; 49291da177e4SLinus Torvalds unsigned long iflags; 4930c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4931cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4932cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4933cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 49341da177e4SLinus Torvalds 49357382f9d8SDouglas Gilbert if (unlikely(aborted)) 49367382f9d8SDouglas Gilbert sd_dp->aborted = false; 4937c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4938c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4939c4837394SDouglas Gilbert if (sdebug_statistics) { 4940cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4941c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4942c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4943c4837394SDouglas Gilbert } 4944c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4945c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 49461da177e4SLinus Torvalds return; 49471da177e4SLinus Torvalds } 4948c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4949d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 4950c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4951cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4952b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4953c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4954c10fa55fSJohn Garry pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n", 4955c10fa55fSJohn Garry sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx); 49561da177e4SLinus Torvalds return; 49571da177e4SLinus Torvalds } 4958cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4959f46eb0e9SDouglas Gilbert if (likely(devip)) 4960cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4961cbf67842SDouglas Gilbert else 4962c1287970STomas Winkler pr_err("devip=NULL\n"); 4963f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4964cbf67842SDouglas Gilbert retiring = 1; 4965cbf67842SDouglas Gilbert 4966cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4967c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4968c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4969c1287970STomas Winkler pr_err("Unexpected completion\n"); 4970cbf67842SDouglas Gilbert return; 49711da177e4SLinus Torvalds } 49721da177e4SLinus Torvalds 4973cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4974cbf67842SDouglas Gilbert int k, retval; 4975cbf67842SDouglas Gilbert 4976cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4977c4837394SDouglas Gilbert if (qc_idx >= retval) { 4978c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4979c1287970STomas Winkler pr_err("index %d too large\n", retval); 4980cbf67842SDouglas Gilbert return; 4981cbf67842SDouglas Gilbert } 4982c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4983773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4984cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4985cbf67842SDouglas Gilbert else 4986cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4987cbf67842SDouglas Gilbert } 4988c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 49897382f9d8SDouglas Gilbert if (unlikely(aborted)) { 49907382f9d8SDouglas Gilbert if (sdebug_verbose) 49917382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 49927382f9d8SDouglas Gilbert return; 49937382f9d8SDouglas Gilbert } 49946c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 4995cbf67842SDouglas Gilbert } 4996cbf67842SDouglas Gilbert 4997cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4998fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4999cbf67842SDouglas Gilbert { 5000a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 5001a10bc12aSDouglas Gilbert hrt); 5002a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 5003cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 5004cbf67842SDouglas Gilbert } 50051da177e4SLinus Torvalds 5006a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 5007fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 5008a10bc12aSDouglas Gilbert { 5009a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 5010a10bc12aSDouglas Gilbert ew.work); 5011a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 5012a10bc12aSDouglas Gilbert } 5013a10bc12aSDouglas Gilbert 501409ba24c1SDouglas Gilbert static bool got_shared_uuid; 5015bf476433SChristoph Hellwig static uuid_t shared_uuid; 501609ba24c1SDouglas Gilbert 5017f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 5018f0d1cf93SDouglas Gilbert { 5019f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 5020f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 50214a5fc1c6SDamien Le Moal sector_t conv_capacity; 5022f0d1cf93SDouglas Gilbert sector_t zstart = 0; 5023f0d1cf93SDouglas Gilbert unsigned int i; 5024f0d1cf93SDouglas Gilbert 5025f0d1cf93SDouglas Gilbert /* 502698e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 502798e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 5028f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 5029f0d1cf93SDouglas Gilbert * created for the device. 5030f0d1cf93SDouglas Gilbert */ 503198e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 5032f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 5033f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5034f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 5035f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 5036f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 5037f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 5038f0d1cf93SDouglas Gilbert return -EINVAL; 5039f0d1cf93SDouglas Gilbert } 5040f0d1cf93SDouglas Gilbert } else { 5041108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 5042108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 5043108e36f0SDamien Le Moal return -EINVAL; 5044108e36f0SDamien Le Moal } 504598e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 5046f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5047f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 5048f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 5049f0d1cf93SDouglas Gilbert return -EINVAL; 5050f0d1cf93SDouglas Gilbert } 5051f0d1cf93SDouglas Gilbert } 5052f0d1cf93SDouglas Gilbert 5053f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 5054f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 5055f0d1cf93SDouglas Gilbert 50564a5fc1c6SDamien Le Moal if (sdeb_zbc_zone_cap_mb == 0) { 50574a5fc1c6SDamien Le Moal devip->zcap = devip->zsize; 50584a5fc1c6SDamien Le Moal } else { 50594a5fc1c6SDamien Le Moal devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >> 50604a5fc1c6SDamien Le Moal ilog2(sdebug_sector_size); 50614a5fc1c6SDamien Le Moal if (devip->zcap > devip->zsize) { 50624a5fc1c6SDamien Le Moal pr_err("Zone capacity too large\n"); 50634a5fc1c6SDamien Le Moal return -EINVAL; 50644a5fc1c6SDamien Le Moal } 50654a5fc1c6SDamien Le Moal } 50664a5fc1c6SDamien Le Moal 50674a5fc1c6SDamien Le Moal conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift; 50684a5fc1c6SDamien Le Moal if (conv_capacity >= capacity) { 5069aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 5070aa8fecf9SDamien Le Moal return -EINVAL; 5071aa8fecf9SDamien Le Moal } 5072aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 50734a5fc1c6SDamien Le Moal devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >> 50744a5fc1c6SDamien Le Moal devip->zsize_shift; 50754a5fc1c6SDamien Le Moal devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones; 50764a5fc1c6SDamien Le Moal 50774a5fc1c6SDamien Le Moal /* Add gap zones if zone capacity is smaller than the zone size */ 50784a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 50794a5fc1c6SDamien Le Moal devip->nr_zones += devip->nr_seq_zones; 5080aa8fecf9SDamien Le Moal 508164e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 508264e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 5083380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 5084f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 5085f0d1cf93SDouglas Gilbert else 5086380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 508764e14eceSDamien Le Moal } 5088f0d1cf93SDouglas Gilbert 5089f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 5090f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 5091f0d1cf93SDouglas Gilbert if (!devip->zstate) 5092f0d1cf93SDouglas Gilbert return -ENOMEM; 5093f0d1cf93SDouglas Gilbert 5094f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 5095f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 5096f0d1cf93SDouglas Gilbert 5097f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 5098f0d1cf93SDouglas Gilbert 5099aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 510035dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_CNV; 5101f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 5102f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 51034a5fc1c6SDamien Le Moal zsp->z_size = 51044a5fc1c6SDamien Le Moal min_t(u64, devip->zsize, capacity - zstart); 51054a5fc1c6SDamien Le Moal } else if ((zstart & (devip->zsize - 1)) == 0) { 510664e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 510735dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWR; 510864e14eceSDamien Le Moal else 510935dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWP; 5110f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 5111f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 51124a5fc1c6SDamien Le Moal zsp->z_size = 51134a5fc1c6SDamien Le Moal min_t(u64, devip->zcap, capacity - zstart); 51144a5fc1c6SDamien Le Moal } else { 51154a5fc1c6SDamien Le Moal zsp->z_type = ZBC_ZTYPE_GAP; 51164a5fc1c6SDamien Le Moal zsp->z_cond = ZBC_NOT_WRITE_POINTER; 51174a5fc1c6SDamien Le Moal zsp->z_wp = (sector_t)-1; 51184a5fc1c6SDamien Le Moal zsp->z_size = min_t(u64, devip->zsize - devip->zcap, 51194a5fc1c6SDamien Le Moal capacity - zstart); 5120f0d1cf93SDouglas Gilbert } 5121f0d1cf93SDouglas Gilbert 51224a5fc1c6SDamien Le Moal WARN_ON_ONCE((int)zsp->z_size <= 0); 5123f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 5124f0d1cf93SDouglas Gilbert } 5125f0d1cf93SDouglas Gilbert 5126f0d1cf93SDouglas Gilbert return 0; 5127f0d1cf93SDouglas Gilbert } 5128f0d1cf93SDouglas Gilbert 5129fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 5130fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 51315cb2fc06SFUJITA Tomonori { 51325cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 51335cb2fc06SFUJITA Tomonori 51345cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 51355cb2fc06SFUJITA Tomonori if (devip) { 513609ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 5137bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 513809ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 513909ba24c1SDouglas Gilbert if (got_shared_uuid) 514009ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 514109ba24c1SDouglas Gilbert else { 5142bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 514309ba24c1SDouglas Gilbert got_shared_uuid = true; 514409ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 514509ba24c1SDouglas Gilbert } 514609ba24c1SDouglas Gilbert } 51475cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 5148f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 514964e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 5150f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 5151f0d1cf93SDouglas Gilbert kfree(devip); 5152f0d1cf93SDouglas Gilbert return NULL; 5153f0d1cf93SDouglas Gilbert } 515464e14eceSDamien Le Moal } else { 515564e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 5156f0d1cf93SDouglas Gilbert } 5157f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 5158fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 5159fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 51605cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 51615cb2fc06SFUJITA Tomonori } 51625cb2fc06SFUJITA Tomonori return devip; 51635cb2fc06SFUJITA Tomonori } 51645cb2fc06SFUJITA Tomonori 5165f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 51661da177e4SLinus Torvalds { 51671da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51681da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 5169f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 51701da177e4SLinus Torvalds 5171d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 51721da177e4SLinus Torvalds if (!sdbg_host) { 5173c1287970STomas Winkler pr_err("Host info NULL\n"); 51741da177e4SLinus Torvalds return NULL; 51751da177e4SLinus Torvalds } 5176ad0c7775SDouglas Gilbert 51771da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 51781da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 51791da177e4SLinus Torvalds (devip->target == sdev->id) && 51801da177e4SLinus Torvalds (devip->lun == sdev->lun)) 51811da177e4SLinus Torvalds return devip; 51821da177e4SLinus Torvalds else { 51831da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 51841da177e4SLinus Torvalds open_devip = devip; 51851da177e4SLinus Torvalds } 51861da177e4SLinus Torvalds } 51875cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 51885cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 51895cb2fc06SFUJITA Tomonori if (!open_devip) { 5190c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51911da177e4SLinus Torvalds return NULL; 51921da177e4SLinus Torvalds } 51931da177e4SLinus Torvalds } 5194a75869d1SFUJITA Tomonori 51951da177e4SLinus Torvalds open_devip->channel = sdev->channel; 51961da177e4SLinus Torvalds open_devip->target = sdev->id; 51971da177e4SLinus Torvalds open_devip->lun = sdev->lun; 51981da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 5199cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 5200500d0d24SDouglas Gilbert set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm); 5201c2248fc9SDouglas Gilbert open_devip->used = true; 52021da177e4SLinus Torvalds return open_devip; 52031da177e4SLinus Torvalds } 52041da177e4SLinus Torvalds 52058dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 52061da177e4SLinus Torvalds { 5207773642d9SDouglas Gilbert if (sdebug_verbose) 5208c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 52098dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52108dea0d02SFUJITA Tomonori return 0; 52118dea0d02SFUJITA Tomonori } 52121da177e4SLinus Torvalds 52138dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 52148dea0d02SFUJITA Tomonori { 5215f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5216f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5217a34c4e98SFUJITA Tomonori 5218773642d9SDouglas Gilbert if (sdebug_verbose) 5219c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 52208dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5221b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5222b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 5223b01f6f83SDouglas Gilbert if (devip == NULL) { 5224f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5225b01f6f83SDouglas Gilbert if (devip == NULL) 52268dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5227f46eb0e9SDouglas Gilbert } 5228c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5229773642d9SDouglas Gilbert if (sdebug_no_uld) 523078d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 52319b760fd8SDouglas Gilbert config_cdb_len(sdp); 52328dea0d02SFUJITA Tomonori return 0; 52338dea0d02SFUJITA Tomonori } 52348dea0d02SFUJITA Tomonori 52358dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 52368dea0d02SFUJITA Tomonori { 52378dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 52388dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 52398dea0d02SFUJITA Tomonori 5240773642d9SDouglas Gilbert if (sdebug_verbose) 5241c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 52428dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52438dea0d02SFUJITA Tomonori if (devip) { 524425985edcSLucas De Marchi /* make this slot available for re-use */ 5245c2248fc9SDouglas Gilbert devip->used = false; 52468dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 52478dea0d02SFUJITA Tomonori } 52488dea0d02SFUJITA Tomonori } 52498dea0d02SFUJITA Tomonori 525010bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 525110bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5252c4837394SDouglas Gilbert { 5253c4837394SDouglas Gilbert if (!sd_dp) 5254c4837394SDouglas Gilbert return; 525510bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5256c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 525710bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5258c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5259c4837394SDouglas Gilbert } 5260c4837394SDouglas Gilbert 5261a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5262a10bc12aSDouglas Gilbert returns false */ 5263a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 52648dea0d02SFUJITA Tomonori { 52658dea0d02SFUJITA Tomonori unsigned long iflags; 5266c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 526710bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5268c4837394SDouglas Gilbert struct sdebug_queue *sqp; 52698dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5270cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5271a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 52728dea0d02SFUJITA Tomonori 5273c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5274c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5275773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5276cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5277cbf67842SDouglas Gilbert if (r_qmax > qmax) 5278cbf67842SDouglas Gilbert qmax = r_qmax; 5279cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5280c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5281c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5282a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5283a10bc12aSDouglas Gilbert continue; 5284c4837394SDouglas Gilbert /* found */ 5285db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5286db525fceSDouglas Gilbert cmnd->device->hostdata; 5287db525fceSDouglas Gilbert if (devip) 5288db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5289db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5290a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 529110bde980SDouglas Gilbert if (sd_dp) { 5292d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5293d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 529410bde980SDouglas Gilbert } else 529510bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5296c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 529710bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5298c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5299a10bc12aSDouglas Gilbert return true; 53008dea0d02SFUJITA Tomonori } 5301cbf67842SDouglas Gilbert } 5302c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5303c4837394SDouglas Gilbert } 5304a10bc12aSDouglas Gilbert return false; 53058dea0d02SFUJITA Tomonori } 53068dea0d02SFUJITA Tomonori 5307a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 5308f19fe8f3SBart Van Assche static void stop_all_queued(void) 53098dea0d02SFUJITA Tomonori { 53108dea0d02SFUJITA Tomonori unsigned long iflags; 5311c4837394SDouglas Gilbert int j, k; 531210bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5313c4837394SDouglas Gilbert struct sdebug_queue *sqp; 53148dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5315cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5316a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 53178dea0d02SFUJITA Tomonori 5318c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5319c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5320c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5321c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5322c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5323f19fe8f3SBart Van Assche if (sqcp->a_cmnd == NULL) 5324a10bc12aSDouglas Gilbert continue; 5325db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5326db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5327db525fceSDouglas Gilbert if (devip) 5328db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5329db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5330a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 533110bde980SDouglas Gilbert if (sd_dp) { 5332d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5333d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 533410bde980SDouglas Gilbert } else 533510bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5336c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 533710bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5338c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5339c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 53408dea0d02SFUJITA Tomonori } 53418dea0d02SFUJITA Tomonori } 5342c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5343c4837394SDouglas Gilbert } 5344cbf67842SDouglas Gilbert } 5345cbf67842SDouglas Gilbert 5346cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5347cbf67842SDouglas Gilbert static void free_all_queued(void) 5348cbf67842SDouglas Gilbert { 5349c4837394SDouglas Gilbert int j, k; 5350c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5351cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5352cbf67842SDouglas Gilbert 5353c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5354c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5355c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5356a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5357a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5358cbf67842SDouglas Gilbert } 53591da177e4SLinus Torvalds } 5360c4837394SDouglas Gilbert } 53611da177e4SLinus Torvalds 53621da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 53631da177e4SLinus Torvalds { 5364a10bc12aSDouglas Gilbert bool ok; 5365a10bc12aSDouglas Gilbert 53661da177e4SLinus Torvalds ++num_aborts; 5367cbf67842SDouglas Gilbert if (SCpnt) { 5368a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5369a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5370a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5371a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5372a10bc12aSDouglas Gilbert ok ? "" : " not"); 5373cbf67842SDouglas Gilbert } 53741da177e4SLinus Torvalds return SUCCESS; 53751da177e4SLinus Torvalds } 53761da177e4SLinus Torvalds 53771da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 53781da177e4SLinus Torvalds { 53791da177e4SLinus Torvalds ++num_dev_resets; 5380cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5381cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5382f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5383f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5384cbf67842SDouglas Gilbert 5385773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5386cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 53871da177e4SLinus Torvalds if (devip) 5388cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 53891da177e4SLinus Torvalds } 53901da177e4SLinus Torvalds return SUCCESS; 53911da177e4SLinus Torvalds } 53921da177e4SLinus Torvalds 5393cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5394cbf67842SDouglas Gilbert { 5395cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5396cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5397cbf67842SDouglas Gilbert struct scsi_device *sdp; 5398cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5399cbf67842SDouglas Gilbert int k = 0; 5400cbf67842SDouglas Gilbert 5401cbf67842SDouglas Gilbert ++num_target_resets; 5402cbf67842SDouglas Gilbert if (!SCpnt) 5403cbf67842SDouglas Gilbert goto lie; 5404cbf67842SDouglas Gilbert sdp = SCpnt->device; 5405cbf67842SDouglas Gilbert if (!sdp) 5406cbf67842SDouglas Gilbert goto lie; 5407773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5408cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5409cbf67842SDouglas Gilbert hp = sdp->host; 5410cbf67842SDouglas Gilbert if (!hp) 5411cbf67842SDouglas Gilbert goto lie; 5412cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5413cbf67842SDouglas Gilbert if (sdbg_host) { 5414cbf67842SDouglas Gilbert list_for_each_entry(devip, 5415cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5416cbf67842SDouglas Gilbert dev_list) 5417cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5418cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5419cbf67842SDouglas Gilbert ++k; 5420cbf67842SDouglas Gilbert } 5421cbf67842SDouglas Gilbert } 5422773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5423cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5424cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5425cbf67842SDouglas Gilbert lie: 5426cbf67842SDouglas Gilbert return SUCCESS; 5427cbf67842SDouglas Gilbert } 5428cbf67842SDouglas Gilbert 54291da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 54301da177e4SLinus Torvalds { 54311da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5432cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 54331da177e4SLinus Torvalds struct scsi_device *sdp; 54341da177e4SLinus Torvalds struct Scsi_Host *hp; 5435cbf67842SDouglas Gilbert int k = 0; 54361da177e4SLinus Torvalds 54371da177e4SLinus Torvalds ++num_bus_resets; 5438cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5439cbf67842SDouglas Gilbert goto lie; 5440cbf67842SDouglas Gilbert sdp = SCpnt->device; 5441773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5442cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5443cbf67842SDouglas Gilbert hp = sdp->host; 5444cbf67842SDouglas Gilbert if (hp) { 5445d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 54461da177e4SLinus Torvalds if (sdbg_host) { 5447cbf67842SDouglas Gilbert list_for_each_entry(devip, 54481da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5449cbf67842SDouglas Gilbert dev_list) { 5450cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5451cbf67842SDouglas Gilbert ++k; 54521da177e4SLinus Torvalds } 54531da177e4SLinus Torvalds } 5454cbf67842SDouglas Gilbert } 5455773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5456cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5457cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5458cbf67842SDouglas Gilbert lie: 54591da177e4SLinus Torvalds return SUCCESS; 54601da177e4SLinus Torvalds } 54611da177e4SLinus Torvalds 54621da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 54631da177e4SLinus Torvalds { 54641da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5465cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5466cbf67842SDouglas Gilbert int k = 0; 54671da177e4SLinus Torvalds 54681da177e4SLinus Torvalds ++num_host_resets; 5469773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5470cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 54711da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 54721da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5473cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5474cbf67842SDouglas Gilbert dev_list) { 5475cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5476cbf67842SDouglas Gilbert ++k; 5477cbf67842SDouglas Gilbert } 54781da177e4SLinus Torvalds } 54791da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 5480f19fe8f3SBart Van Assche stop_all_queued(); 5481773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5482cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5483cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 54841da177e4SLinus Torvalds return SUCCESS; 54851da177e4SLinus Torvalds } 54861da177e4SLinus Torvalds 548787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 54881da177e4SLinus Torvalds { 54891442f76dSChristoph Hellwig struct msdos_partition *pp; 5490979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 54911da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 54921da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 54931da177e4SLinus Torvalds 54941da177e4SLinus Torvalds /* assume partition table already zeroed */ 5495773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 54961da177e4SLinus Torvalds return; 5497773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5498773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5499c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 55001da177e4SLinus Torvalds } 55018c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 55021da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5503773642d9SDouglas Gilbert / sdebug_num_parts; 55041da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 55051da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5506979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5507979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 55081da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 55091da177e4SLinus Torvalds * heads_by_sects; 5510979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5511979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5512979e0dc3SJohn Pittman } 5513773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5514773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 55151da177e4SLinus Torvalds 55161da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 55171da177e4SLinus Torvalds ramp[511] = 0xAA; 55181442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 55191da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 55201da177e4SLinus Torvalds start_sec = starts[k]; 5521979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 55221da177e4SLinus Torvalds pp->boot_ind = 0; 55231da177e4SLinus Torvalds 55241da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 55251da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 55261da177e4SLinus Torvalds / sdebug_sectors_per; 55271da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 55281da177e4SLinus Torvalds 55291da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 55301da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 55311da177e4SLinus Torvalds / sdebug_sectors_per; 55321da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 55331da177e4SLinus Torvalds 5534150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5535150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 55361da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 55371da177e4SLinus Torvalds } 55381da177e4SLinus Torvalds } 55391da177e4SLinus Torvalds 5540f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block) 5541c4837394SDouglas Gilbert { 5542c4837394SDouglas Gilbert int j; 5543c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5544c4837394SDouglas Gilbert 5545c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 5546f19fe8f3SBart Van Assche atomic_set(&sqp->blocked, (int)block); 5547c4837394SDouglas Gilbert } 5548c4837394SDouglas Gilbert 5549c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5550c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5551c4837394SDouglas Gilbert */ 5552c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5553c4837394SDouglas Gilbert { 5554c4837394SDouglas Gilbert int count, modulo; 5555c4837394SDouglas Gilbert 5556c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5557c4837394SDouglas Gilbert if (modulo < 2) 5558c4837394SDouglas Gilbert return; 5559f19fe8f3SBart Van Assche block_unblock_all_queues(true); 5560c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5561c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5562f19fe8f3SBart Van Assche block_unblock_all_queues(false); 5563c4837394SDouglas Gilbert } 5564c4837394SDouglas Gilbert 5565c4837394SDouglas Gilbert static void clear_queue_stats(void) 5566c4837394SDouglas Gilbert { 5567c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5568c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5569c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5570c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5571c4837394SDouglas Gilbert } 5572c4837394SDouglas Gilbert 55733a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5574c4837394SDouglas Gilbert { 55753a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 55763a90a63dSDouglas Gilbert return false; 55773a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5578c4837394SDouglas Gilbert } 5579c4837394SDouglas Gilbert 5580a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5581a2aede97SDouglas Gilbert 5582c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5583c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5584c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5585c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5586c4837394SDouglas Gilbert */ 5587fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5588f66b8517SMartin Wilck int scsi_result, 5589f19fe8f3SBart Van Assche int (*pfp)(struct scsi_cmnd *, 5590f19fe8f3SBart Van Assche struct sdebug_dev_info *), 5591f66b8517SMartin Wilck int delta_jiff, int ndelay) 55921da177e4SLinus Torvalds { 5593a2aede97SDouglas Gilbert bool new_sd_dp; 55943a90a63dSDouglas Gilbert bool inject = false; 55956ce913feSChristoph Hellwig bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED; 55963a90a63dSDouglas Gilbert int k, num_in_q, qdepth; 5597a2aede97SDouglas Gilbert unsigned long iflags; 5598a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5599c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5600c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5601299b6c07STomas Winkler struct scsi_device *sdp; 5602a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 56031da177e4SLinus Torvalds 5604b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5605b01f6f83SDouglas Gilbert if (scsi_result == 0) 5606f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5607f46eb0e9SDouglas Gilbert goto respond_in_thread; 56081da177e4SLinus Torvalds } 5609299b6c07STomas Winkler sdp = cmnd->device; 5610299b6c07STomas Winkler 5611f19fe8f3SBart Van Assche if (delta_jiff == 0) 5612cd62b7daSDouglas Gilbert goto respond_in_thread; 56131da177e4SLinus Torvalds 5614c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5615c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5616c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5617c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5618c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5619c4837394SDouglas Gilbert } 5620cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5621cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5622f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5623cd62b7daSDouglas Gilbert if (scsi_result) { 5624c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5625cd62b7daSDouglas Gilbert goto respond_in_thread; 5626cd62b7daSDouglas Gilbert } else 5627cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5628c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5629773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5630f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5631cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5632cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5633773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5634cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 56353a90a63dSDouglas Gilbert inject = true; 5636cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 56371da177e4SLinus Torvalds } 5638cbf67842SDouglas Gilbert } 5639cbf67842SDouglas Gilbert 5640c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5641f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5642c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5643cd62b7daSDouglas Gilbert if (scsi_result) 5644cd62b7daSDouglas Gilbert goto respond_in_thread; 5645cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5646773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 56477d5a129bSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n", 56487d5a129bSDouglas Gilbert __func__, sdebug_max_queue); 5649cd62b7daSDouglas Gilbert goto respond_in_thread; 56501da177e4SLinus Torvalds } 565174595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5652cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5653c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 56541da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5655c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5656a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5657c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5658c4b57d89SKashyap Desai 565974595c04SDouglas Gilbert if (!sd_dp) { 566010bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 566174595c04SDouglas Gilbert if (!sd_dp) { 566274595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 566374595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 566410bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 566574595c04SDouglas Gilbert } 5666a2aede97SDouglas Gilbert new_sd_dp = true; 5667a2aede97SDouglas Gilbert } else { 5668a2aede97SDouglas Gilbert new_sd_dp = false; 566910bde980SDouglas Gilbert } 5670f66b8517SMartin Wilck 5671c10fa55fSJohn Garry /* Set the hostwide tag */ 5672c10fa55fSJohn Garry if (sdebug_host_max_queue) 5673c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5674c10fa55fSJohn Garry 56756ce913feSChristoph Hellwig if (polled) 5676a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5677a2aede97SDouglas Gilbert 5678a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 56793a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5680f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5681f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5682f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5683f66b8517SMartin Wilck } 5684f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5685f66b8517SMartin Wilck cmnd->result = scsi_result; 56863a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 56873a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 56883a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 56893a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 56903a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 56913a90a63dSDouglas Gilbert } 56923a90a63dSDouglas Gilbert } 5693f66b8517SMartin Wilck 5694f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5695f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5696f66b8517SMartin Wilck __func__, cmnd->result); 5697f66b8517SMartin Wilck 569810bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5699b333a819SDouglas Gilbert ktime_t kt; 5700cbf67842SDouglas Gilbert 5701b333a819SDouglas Gilbert if (delta_jiff > 0) { 57020c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 57030c4bc91dSDouglas Gilbert 57040c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 57050c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 57060c4bc91dSDouglas Gilbert } else if (sdebug_random) { 57070c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 57080c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 57090c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 57100c4bc91dSDouglas Gilbert ns <<= 12; 57110c4bc91dSDouglas Gilbert } 57120c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 57130c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 57140c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 57150c4bc91dSDouglas Gilbert (u32)ndelay; 5716a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5717a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5718a2aede97SDouglas Gilbert 5719a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5720223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5721a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5722a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5723a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5724223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5725a2aede97SDouglas Gilbert if (new_sd_dp) 5726a2aede97SDouglas Gilbert kfree(sd_dp); 5727a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 57286c2c7d6aSBart Van Assche scsi_done(cmnd); 5729a2aede97SDouglas Gilbert return 0; 5730a2aede97SDouglas Gilbert } 5731a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5732a2aede97SDouglas Gilbert kt -= d; 5733a2aede97SDouglas Gilbert } 57340c4bc91dSDouglas Gilbert } 57356ce913feSChristoph Hellwig if (polled) { 57364a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 57374a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57384a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57394a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57404a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57414a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57424a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57434a0c6f43SDouglas Gilbert } 5744d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57454a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57464a0c6f43SDouglas Gilbert } else { 574710bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 574810bde980SDouglas Gilbert sd_dp->init_hrt = true; 5749a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5750a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5751c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5752a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5753c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5754c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5755cbf67842SDouglas Gilbert } 5756d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); 5757a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5758c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 57594a0c6f43SDouglas Gilbert } 57604a0c6f43SDouglas Gilbert if (sdebug_statistics) 57614a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 5762c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 57634a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 57644a0c6f43SDouglas Gilbert atomic_read(&sdeb_inject_pending))) 57654a0c6f43SDouglas Gilbert sd_dp->aborted = true; 57666ce913feSChristoph Hellwig if (polled) { 57674a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 57684a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57694a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57704a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57714a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57724a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57734a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57744a0c6f43SDouglas Gilbert } 5775d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57764a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57774a0c6f43SDouglas Gilbert } else { 577810bde980SDouglas Gilbert if (!sd_dp->init_wq) { 577910bde980SDouglas Gilbert sd_dp->init_wq = true; 5780a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5781c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5782c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5783a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5784cbf67842SDouglas Gilbert } 5785d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); 57864a0c6f43SDouglas Gilbert schedule_work(&sd_dp->ew.work); 57874a0c6f43SDouglas Gilbert } 5788c4837394SDouglas Gilbert if (sdebug_statistics) 5789c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 57904a0c6f43SDouglas Gilbert if (unlikely(sd_dp->aborted)) { 5791a6e76e6fSBart Van Assche sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 5792a6e76e6fSBart Van Assche scsi_cmd_to_rq(cmnd)->tag); 5793a6e76e6fSBart Van Assche blk_abort_request(scsi_cmd_to_rq(cmnd)); 57943a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 57954a0c6f43SDouglas Gilbert sd_dp->aborted = false; 57967382f9d8SDouglas Gilbert } 5797cbf67842SDouglas Gilbert } 57983a90a63dSDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result)) 57993a90a63dSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__, 58003a90a63dSDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL"); 58011da177e4SLinus Torvalds return 0; 5802cd62b7daSDouglas Gilbert 5803cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5804f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5805f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5806f19fe8f3SBart Van Assche if (cmnd->result == 0 && scsi_result != 0) 5807cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 58086c2c7d6aSBart Van Assche scsi_done(cmnd); 5809cd62b7daSDouglas Gilbert return 0; 58101da177e4SLinus Torvalds } 5811cbf67842SDouglas Gilbert 581223183910SDouglas Gilbert /* Note: The following macros create attribute files in the 581323183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 581423183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 581523183910SDouglas Gilbert as it can when the corresponding attribute in the 581623183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 581723183910SDouglas Gilbert */ 5818773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5819773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 58209b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5821773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5822c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5823773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5824773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5825773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5826773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5827773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5828773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5829773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5830773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5831c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5832e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5833e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5834e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5835e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 58365d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 58375d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 58385d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5839773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5840773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5841773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5842773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5843ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5844773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5845773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 58465d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 58475d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 58485d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 58495d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5850773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5851773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 58527109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR); 5853773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5854773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5855773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5856773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 58575d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5858773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 585987c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 586087c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5861773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5862773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 58630c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5864773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5865773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5866773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5867c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5868773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5869c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5870c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5871fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5872773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5873773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5874773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5875773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 587609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 58775d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5878773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 587923183910SDouglas Gilbert S_IRUGO | S_IWUSR); 58809447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5881773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 58825b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 58839267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 58844a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO); 5885380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5886aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 588798e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 58881da177e4SLinus Torvalds 58891da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 58901da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 58911da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5892b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 58931da177e4SLinus Torvalds 58945d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 58955b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 58969b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 58970759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5898cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5899c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 59005b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 59015b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5902c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5903beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 590423183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 59055b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5906185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5907c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5908c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5909e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 59109b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 59119b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 59125d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 59135d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 59145d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 59155b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 59165b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 59175b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 59185b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5919ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5920fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5921cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5922d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 59235d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5924cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5925c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 59267109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)"); 592778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 59281da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5929c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 593032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 593186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 59325d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 59335d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 59345d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5935fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 59361da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 59370c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5938d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5939760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5940ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5941c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5942c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5943c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5944fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 59455b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 59465b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 59476014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 59486014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 594909ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 595009ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5951c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 59525b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 59539447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 59545b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 59559267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 59564a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)"); 5957380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5958aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 595998e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 59601da177e4SLinus Torvalds 5961760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5962760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 59631da177e4SLinus Torvalds 59641da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 59651da177e4SLinus Torvalds { 5966c4837394SDouglas Gilbert int k; 5967c4837394SDouglas Gilbert 5968760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5969760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5970760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5971c4837394SDouglas Gilbert return sdebug_info; 5972760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5973760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5974760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5975760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 59761da177e4SLinus Torvalds return sdebug_info; 59771da177e4SLinus Torvalds } 59781da177e4SLinus Torvalds 5979cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5980fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5981fd32119bSDouglas Gilbert int length) 59821da177e4SLinus Torvalds { 59831da177e4SLinus Torvalds char arr[16]; 5984c8ed555aSAl Viro int opts; 59851da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 59861da177e4SLinus Torvalds 59871da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 59881da177e4SLinus Torvalds return -EACCES; 59891da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 59901da177e4SLinus Torvalds arr[minLen] = '\0'; 5991c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 59921da177e4SLinus Torvalds return -EINVAL; 5993773642d9SDouglas Gilbert sdebug_opts = opts; 5994773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5995773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5996773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5997c4837394SDouglas Gilbert tweak_cmnd_count(); 59981da177e4SLinus Torvalds return length; 59991da177e4SLinus Torvalds } 6000c8ed555aSAl Viro 6001cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 6002cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 6003cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 6004c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 6005c8ed555aSAl Viro { 6006c4837394SDouglas Gilbert int f, j, l; 6007c4837394SDouglas Gilbert struct sdebug_queue *sqp; 600887c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 6009cbf67842SDouglas Gilbert 6010c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 6011c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 6012c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 6013c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 6014c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 6015c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 6016c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 6017c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 6018c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 6019c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 6020c4837394SDouglas Gilbert num_aborts); 6021c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 6022c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 6023c4837394SDouglas Gilbert num_host_resets); 6024c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 6025c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 6026458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 6027458df78bSBart Van Assche sdebug_statistics); 60284a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 6029c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 6030c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 6031c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 60324a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 60334a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 6034cbf67842SDouglas Gilbert 6035c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 6036c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 6037c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 6038c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 6039773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 6040c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 6041c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 6042c4837394SDouglas Gilbert "first,last bits", f, l); 6043c4837394SDouglas Gilbert } 6044cbf67842SDouglas Gilbert } 604587c715dcSDouglas Gilbert 604687c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 604787c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 604887c715dcSDouglas Gilbert bool niu; 604987c715dcSDouglas Gilbert int idx; 605087c715dcSDouglas Gilbert unsigned long l_idx; 605187c715dcSDouglas Gilbert struct sdeb_store_info *sip; 605287c715dcSDouglas Gilbert 605387c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 605487c715dcSDouglas Gilbert j = 0; 605587c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 605687c715dcSDouglas Gilbert idx = sdhp->si_idx; 605787c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 605887c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 605987c715dcSDouglas Gilbert ++j; 606087c715dcSDouglas Gilbert } 606187c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 606287c715dcSDouglas Gilbert sdeb_most_recent_idx); 606387c715dcSDouglas Gilbert j = 0; 606487c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 606587c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 606687c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 606787c715dcSDouglas Gilbert idx = (int)l_idx; 606887c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 606987c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 607087c715dcSDouglas Gilbert ++j; 607187c715dcSDouglas Gilbert } 607287c715dcSDouglas Gilbert } 6073c8ed555aSAl Viro return 0; 60741da177e4SLinus Torvalds } 60751da177e4SLinus Torvalds 607682069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 60771da177e4SLinus Torvalds { 6078c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 60791da177e4SLinus Torvalds } 6080c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 6081c4837394SDouglas Gilbert * of delay is jiffies. 6082c4837394SDouglas Gilbert */ 608382069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 608482069379SAkinobu Mita size_t count) 60851da177e4SLinus Torvalds { 6086c2206098SDouglas Gilbert int jdelay, res; 60871da177e4SLinus Torvalds 6088b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 6089cbf67842SDouglas Gilbert res = count; 6090c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 6091c4837394SDouglas Gilbert int j, k; 6092c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6093cbf67842SDouglas Gilbert 6094f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6095c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6096c4837394SDouglas Gilbert ++j, ++sqp) { 6097c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6098c4837394SDouglas Gilbert sdebug_max_queue); 6099c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6100c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6101c4837394SDouglas Gilbert break; 6102c4837394SDouglas Gilbert } 6103c4837394SDouglas Gilbert } 6104c4837394SDouglas Gilbert if (res > 0) { 6105c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 6106773642d9SDouglas Gilbert sdebug_ndelay = 0; 61071da177e4SLinus Torvalds } 6108f19fe8f3SBart Van Assche block_unblock_all_queues(false); 6109cbf67842SDouglas Gilbert } 6110cbf67842SDouglas Gilbert return res; 61111da177e4SLinus Torvalds } 61121da177e4SLinus Torvalds return -EINVAL; 61131da177e4SLinus Torvalds } 611482069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 61151da177e4SLinus Torvalds 6116cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 6117cbf67842SDouglas Gilbert { 6118773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 6119cbf67842SDouglas Gilbert } 6120cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 6121c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 6122cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 6123cbf67842SDouglas Gilbert size_t count) 6124cbf67842SDouglas Gilbert { 6125c4837394SDouglas Gilbert int ndelay, res; 6126cbf67842SDouglas Gilbert 6127cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 6128c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 6129cbf67842SDouglas Gilbert res = count; 6130773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 6131c4837394SDouglas Gilbert int j, k; 6132c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6133c4837394SDouglas Gilbert 6134f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6135c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6136c4837394SDouglas Gilbert ++j, ++sqp) { 6137c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6138c4837394SDouglas Gilbert sdebug_max_queue); 6139c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6140c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6141c4837394SDouglas Gilbert break; 6142c4837394SDouglas Gilbert } 6143c4837394SDouglas Gilbert } 6144c4837394SDouglas Gilbert if (res > 0) { 6145773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 6146c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 6147c2206098SDouglas Gilbert : DEF_JDELAY; 6148cbf67842SDouglas Gilbert } 6149f19fe8f3SBart Van Assche block_unblock_all_queues(false); 6150cbf67842SDouglas Gilbert } 6151cbf67842SDouglas Gilbert return res; 6152cbf67842SDouglas Gilbert } 6153cbf67842SDouglas Gilbert return -EINVAL; 6154cbf67842SDouglas Gilbert } 6155cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 6156cbf67842SDouglas Gilbert 615782069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 61581da177e4SLinus Torvalds { 6159773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 61601da177e4SLinus Torvalds } 61611da177e4SLinus Torvalds 616282069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 616382069379SAkinobu Mita size_t count) 61641da177e4SLinus Torvalds { 61651da177e4SLinus Torvalds int opts; 61661da177e4SLinus Torvalds char work[20]; 61671da177e4SLinus Torvalds 61689a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 61699a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 61709a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 61711da177e4SLinus Torvalds goto opts_done; 61721da177e4SLinus Torvalds } else { 61739a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 61741da177e4SLinus Torvalds goto opts_done; 61751da177e4SLinus Torvalds } 61761da177e4SLinus Torvalds } 61771da177e4SLinus Torvalds return -EINVAL; 61781da177e4SLinus Torvalds opts_done: 6179773642d9SDouglas Gilbert sdebug_opts = opts; 6180773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 6181773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 6182c4837394SDouglas Gilbert tweak_cmnd_count(); 61831da177e4SLinus Torvalds return count; 61841da177e4SLinus Torvalds } 618582069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 61861da177e4SLinus Torvalds 618782069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 61881da177e4SLinus Torvalds { 6189773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 61901da177e4SLinus Torvalds } 619182069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 619282069379SAkinobu Mita size_t count) 61931da177e4SLinus Torvalds { 61941da177e4SLinus Torvalds int n; 61951da177e4SLinus Torvalds 6196f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 6197f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 6198f0d1cf93SDouglas Gilbert return -EINVAL; 6199f0d1cf93SDouglas Gilbert 62001da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6201f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 6202f0d1cf93SDouglas Gilbert return -EINVAL; 6203773642d9SDouglas Gilbert sdebug_ptype = n; 62041da177e4SLinus Torvalds return count; 62051da177e4SLinus Torvalds } 62061da177e4SLinus Torvalds return -EINVAL; 62071da177e4SLinus Torvalds } 620882069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 62091da177e4SLinus Torvalds 621082069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 62111da177e4SLinus Torvalds { 6212773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 62131da177e4SLinus Torvalds } 621482069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 621582069379SAkinobu Mita size_t count) 62161da177e4SLinus Torvalds { 62171da177e4SLinus Torvalds int n; 62181da177e4SLinus Torvalds 62191da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6220773642d9SDouglas Gilbert sdebug_dsense = n; 62211da177e4SLinus Torvalds return count; 62221da177e4SLinus Torvalds } 62231da177e4SLinus Torvalds return -EINVAL; 62241da177e4SLinus Torvalds } 622582069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 62261da177e4SLinus Torvalds 622782069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 622823183910SDouglas Gilbert { 6229773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 623023183910SDouglas Gilbert } 623182069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 623282069379SAkinobu Mita size_t count) 623323183910SDouglas Gilbert { 623487c715dcSDouglas Gilbert int n, idx; 623523183910SDouglas Gilbert 623623183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 623787c715dcSDouglas Gilbert bool want_store = (n == 0); 623887c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 623987c715dcSDouglas Gilbert 6240cbf67842SDouglas Gilbert n = (n > 0); 6241773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 624287c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 624387c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6244cbf67842SDouglas Gilbert 624587c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 624687c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 624787c715dcSDouglas Gilbert idx = sdebug_add_store(); 624887c715dcSDouglas Gilbert if (idx < 0) 624987c715dcSDouglas Gilbert return idx; 625087c715dcSDouglas Gilbert } else { 625187c715dcSDouglas Gilbert idx = sdeb_first_idx; 625287c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 625387c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6254cbf67842SDouglas Gilbert } 625587c715dcSDouglas Gilbert /* make all hosts use same store */ 625687c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 625787c715dcSDouglas Gilbert host_list) { 625887c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 625987c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 626087c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 626187c715dcSDouglas Gilbert sdhp->si_idx = idx; 626287c715dcSDouglas Gilbert } 626387c715dcSDouglas Gilbert } 626487c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 626587c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 626687c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6267cbf67842SDouglas Gilbert } 6268773642d9SDouglas Gilbert sdebug_fake_rw = n; 626923183910SDouglas Gilbert return count; 627023183910SDouglas Gilbert } 627123183910SDouglas Gilbert return -EINVAL; 627223183910SDouglas Gilbert } 627382069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 627423183910SDouglas Gilbert 627582069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6276c65b1445SDouglas Gilbert { 6277773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6278c65b1445SDouglas Gilbert } 627982069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 628082069379SAkinobu Mita size_t count) 6281c65b1445SDouglas Gilbert { 6282c65b1445SDouglas Gilbert int n; 6283c65b1445SDouglas Gilbert 6284c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6285773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6286c65b1445SDouglas Gilbert return count; 6287c65b1445SDouglas Gilbert } 6288c65b1445SDouglas Gilbert return -EINVAL; 6289c65b1445SDouglas Gilbert } 629082069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6291c65b1445SDouglas Gilbert 629282069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 62931da177e4SLinus Torvalds { 6294773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 62951da177e4SLinus Torvalds } 629682069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 629782069379SAkinobu Mita size_t count) 62981da177e4SLinus Torvalds { 62991da177e4SLinus Torvalds int n; 63001da177e4SLinus Torvalds 63011da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6302773642d9SDouglas Gilbert sdebug_num_tgts = n; 63031da177e4SLinus Torvalds sdebug_max_tgts_luns(); 63041da177e4SLinus Torvalds return count; 63051da177e4SLinus Torvalds } 63061da177e4SLinus Torvalds return -EINVAL; 63071da177e4SLinus Torvalds } 630882069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 63091da177e4SLinus Torvalds 631082069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 63111da177e4SLinus Torvalds { 6312773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 63131da177e4SLinus Torvalds } 631482069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 63151da177e4SLinus Torvalds 631687c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 631787c715dcSDouglas Gilbert { 631887c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 631987c715dcSDouglas Gilbert } 632087c715dcSDouglas Gilbert 632187c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 632287c715dcSDouglas Gilbert size_t count) 632387c715dcSDouglas Gilbert { 632487c715dcSDouglas Gilbert bool v; 632587c715dcSDouglas Gilbert 632687c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 632787c715dcSDouglas Gilbert return -EINVAL; 632887c715dcSDouglas Gilbert 632987c715dcSDouglas Gilbert sdebug_per_host_store = v; 633087c715dcSDouglas Gilbert return count; 633187c715dcSDouglas Gilbert } 633287c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 633387c715dcSDouglas Gilbert 633482069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 63351da177e4SLinus Torvalds { 6336773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 63371da177e4SLinus Torvalds } 633882069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 63391da177e4SLinus Torvalds 634082069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 63411da177e4SLinus Torvalds { 6342773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 63431da177e4SLinus Torvalds } 634482069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 634582069379SAkinobu Mita size_t count) 63461da177e4SLinus Torvalds { 63471da177e4SLinus Torvalds int nth; 63483a90a63dSDouglas Gilbert char work[20]; 63491da177e4SLinus Torvalds 63503a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 63513a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 63523a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 63533a90a63dSDouglas Gilbert goto every_nth_done; 63543a90a63dSDouglas Gilbert } else { 63553a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 63563a90a63dSDouglas Gilbert goto every_nth_done; 63573a90a63dSDouglas Gilbert } 63583a90a63dSDouglas Gilbert } 63593a90a63dSDouglas Gilbert return -EINVAL; 63603a90a63dSDouglas Gilbert 63613a90a63dSDouglas Gilbert every_nth_done: 6362773642d9SDouglas Gilbert sdebug_every_nth = nth; 6363c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6364c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6365c4837394SDouglas Gilbert sdebug_statistics = true; 6366c4837394SDouglas Gilbert } 6367c4837394SDouglas Gilbert tweak_cmnd_count(); 63681da177e4SLinus Torvalds return count; 63691da177e4SLinus Torvalds } 637082069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 63711da177e4SLinus Torvalds 6372ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6373ad0c7775SDouglas Gilbert { 6374ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6375ad0c7775SDouglas Gilbert } 6376ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6377ad0c7775SDouglas Gilbert size_t count) 6378ad0c7775SDouglas Gilbert { 6379ad0c7775SDouglas Gilbert int n; 6380ad0c7775SDouglas Gilbert bool changed; 6381ad0c7775SDouglas Gilbert 6382ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6383ad0c7775SDouglas Gilbert return -EINVAL; 6384ad0c7775SDouglas Gilbert if (n >= 0) { 6385ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6386ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6387ad0c7775SDouglas Gilbert return -EINVAL; 6388ad0c7775SDouglas Gilbert } 6389ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6390ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6391ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6392ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6393ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6394ad0c7775SDouglas Gilbert 6395ad0c7775SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 6396ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6397ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6398ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6399ad0c7775SDouglas Gilbert } 6400ad0c7775SDouglas Gilbert } 6401ad0c7775SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 6402ad0c7775SDouglas Gilbert } 6403ad0c7775SDouglas Gilbert return count; 6404ad0c7775SDouglas Gilbert } 6405ad0c7775SDouglas Gilbert return -EINVAL; 6406ad0c7775SDouglas Gilbert } 6407ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6408ad0c7775SDouglas Gilbert 640982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 64101da177e4SLinus Torvalds { 6411773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 64121da177e4SLinus Torvalds } 641382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 641482069379SAkinobu Mita size_t count) 64151da177e4SLinus Torvalds { 64161da177e4SLinus Torvalds int n; 641719c8ead7SEwan D. Milne bool changed; 64181da177e4SLinus Torvalds 64191da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 64208d039e22SDouglas Gilbert if (n > 256) { 64218d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 64228d039e22SDouglas Gilbert return -EINVAL; 64238d039e22SDouglas Gilbert } 6424773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6425773642d9SDouglas Gilbert sdebug_max_luns = n; 64261da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6427773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 642819c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 642919c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 643019c8ead7SEwan D. Milne 643119c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 643219c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 643319c8ead7SEwan D. Milne host_list) { 643419c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 643519c8ead7SEwan D. Milne dev_list) { 643619c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 643719c8ead7SEwan D. Milne dp->uas_bm); 643819c8ead7SEwan D. Milne } 643919c8ead7SEwan D. Milne } 644019c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 644119c8ead7SEwan D. Milne } 64421da177e4SLinus Torvalds return count; 64431da177e4SLinus Torvalds } 64441da177e4SLinus Torvalds return -EINVAL; 64451da177e4SLinus Torvalds } 644682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 64471da177e4SLinus Torvalds 644882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 644978d4e5a0SDouglas Gilbert { 6450773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 645178d4e5a0SDouglas Gilbert } 6452cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6453cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 645482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 645582069379SAkinobu Mita size_t count) 645678d4e5a0SDouglas Gilbert { 6457c4837394SDouglas Gilbert int j, n, k, a; 6458c4837394SDouglas Gilbert struct sdebug_queue *sqp; 645978d4e5a0SDouglas Gilbert 646078d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6461c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6462c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 6463f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6464c4837394SDouglas Gilbert k = 0; 6465c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6466c4837394SDouglas Gilbert ++j, ++sqp) { 6467c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6468c4837394SDouglas Gilbert if (a > k) 6469c4837394SDouglas Gilbert k = a; 6470c4837394SDouglas Gilbert } 6471773642d9SDouglas Gilbert sdebug_max_queue = n; 6472c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6473cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6474cbf67842SDouglas Gilbert else if (k >= n) 6475cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6476cbf67842SDouglas Gilbert else 6477cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6478f19fe8f3SBart Van Assche block_unblock_all_queues(false); 647978d4e5a0SDouglas Gilbert return count; 648078d4e5a0SDouglas Gilbert } 648178d4e5a0SDouglas Gilbert return -EINVAL; 648278d4e5a0SDouglas Gilbert } 648382069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 648478d4e5a0SDouglas Gilbert 6485c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6486c10fa55fSJohn Garry { 6487c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6488c10fa55fSJohn Garry } 6489c10fa55fSJohn Garry 64907109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf) 64917109f370SDouglas Gilbert { 64927109f370SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock); 64937109f370SDouglas Gilbert } 64947109f370SDouglas Gilbert 64957109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count) 64967109f370SDouglas Gilbert { 64977109f370SDouglas Gilbert bool v; 64987109f370SDouglas Gilbert 64997109f370SDouglas Gilbert if (kstrtobool(buf, &v)) 65007109f370SDouglas Gilbert return -EINVAL; 65017109f370SDouglas Gilbert 65027109f370SDouglas Gilbert sdebug_no_rwlock = v; 65037109f370SDouglas Gilbert return count; 65047109f370SDouglas Gilbert } 65057109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock); 65067109f370SDouglas Gilbert 6507c10fa55fSJohn Garry /* 6508c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6509c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6510c10fa55fSJohn Garry */ 6511c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6512c10fa55fSJohn Garry 651382069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 651478d4e5a0SDouglas Gilbert { 6515773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 651678d4e5a0SDouglas Gilbert } 651782069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 651878d4e5a0SDouglas Gilbert 651982069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 65201da177e4SLinus Torvalds { 6521773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 65221da177e4SLinus Torvalds } 652382069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 65241da177e4SLinus Torvalds 652582069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6526c65b1445SDouglas Gilbert { 6527773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6528c65b1445SDouglas Gilbert } 652982069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 653082069379SAkinobu Mita size_t count) 6531c65b1445SDouglas Gilbert { 6532c65b1445SDouglas Gilbert int n; 65330d01c5dfSDouglas Gilbert bool changed; 6534c65b1445SDouglas Gilbert 6535f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6536f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6537f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6538f0d1cf93SDouglas Gilbert 6539c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6540773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6541773642d9SDouglas Gilbert sdebug_virtual_gb = n; 654228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 65430d01c5dfSDouglas Gilbert if (changed) { 65440d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 65450d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 654628898873SFUJITA Tomonori 65474bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 65480d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 65490d01c5dfSDouglas Gilbert host_list) { 65500d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 65510d01c5dfSDouglas Gilbert dev_list) { 65520d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 65530d01c5dfSDouglas Gilbert dp->uas_bm); 65540d01c5dfSDouglas Gilbert } 65550d01c5dfSDouglas Gilbert } 65564bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 65570d01c5dfSDouglas Gilbert } 6558c65b1445SDouglas Gilbert return count; 6559c65b1445SDouglas Gilbert } 6560c65b1445SDouglas Gilbert return -EINVAL; 6561c65b1445SDouglas Gilbert } 656282069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6563c65b1445SDouglas Gilbert 656482069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 65651da177e4SLinus Torvalds { 656687c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 6567f19fe8f3SBart Van Assche return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 65681da177e4SLinus Torvalds } 65691da177e4SLinus Torvalds 657082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 657182069379SAkinobu Mita size_t count) 65721da177e4SLinus Torvalds { 6573f19fe8f3SBart Van Assche bool found; 6574f19fe8f3SBart Van Assche unsigned long idx; 6575f19fe8f3SBart Van Assche struct sdeb_store_info *sip; 6576f19fe8f3SBart Van Assche bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 65771da177e4SLinus Torvalds int delta_hosts; 65781da177e4SLinus Torvalds 6579f19fe8f3SBart Van Assche if (sscanf(buf, "%d", &delta_hosts) != 1) 65801da177e4SLinus Torvalds return -EINVAL; 65811da177e4SLinus Torvalds if (delta_hosts > 0) { 65821da177e4SLinus Torvalds do { 6583f19fe8f3SBart Van Assche found = false; 6584f19fe8f3SBart Van Assche if (want_phs) { 6585f19fe8f3SBart Van Assche xa_for_each_marked(per_store_ap, idx, sip, 6586f19fe8f3SBart Van Assche SDEB_XA_NOT_IN_USE) { 6587f19fe8f3SBart Van Assche sdeb_most_recent_idx = (int)idx; 6588f19fe8f3SBart Van Assche found = true; 658987c715dcSDouglas Gilbert break; 659087c715dcSDouglas Gilbert } 6591f19fe8f3SBart Van Assche if (found) /* re-use case */ 6592f19fe8f3SBart Van Assche sdebug_add_host_helper((int)idx); 6593f19fe8f3SBart Van Assche else 6594f19fe8f3SBart Van Assche sdebug_do_add_host(true); 6595f19fe8f3SBart Van Assche } else { 6596f19fe8f3SBart Van Assche sdebug_do_add_host(false); 6597f19fe8f3SBart Van Assche } 6598f19fe8f3SBart Van Assche } while (--delta_hosts); 6599f19fe8f3SBart Van Assche } else if (delta_hosts < 0) { 6600f19fe8f3SBart Van Assche do { 660187c715dcSDouglas Gilbert sdebug_do_remove_host(false); 66021da177e4SLinus Torvalds } while (++delta_hosts); 66031da177e4SLinus Torvalds } 66041da177e4SLinus Torvalds return count; 66051da177e4SLinus Torvalds } 660682069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 66071da177e4SLinus Torvalds 660882069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 660923183910SDouglas Gilbert { 6610773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 661123183910SDouglas Gilbert } 661282069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 661382069379SAkinobu Mita size_t count) 661423183910SDouglas Gilbert { 661523183910SDouglas Gilbert int n; 661623183910SDouglas Gilbert 661723183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6618773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 661923183910SDouglas Gilbert return count; 662023183910SDouglas Gilbert } 662123183910SDouglas Gilbert return -EINVAL; 662223183910SDouglas Gilbert } 662382069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 662423183910SDouglas Gilbert 6625c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6626c4837394SDouglas Gilbert { 6627c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6628c4837394SDouglas Gilbert } 6629c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6630c4837394SDouglas Gilbert size_t count) 6631c4837394SDouglas Gilbert { 6632c4837394SDouglas Gilbert int n; 6633c4837394SDouglas Gilbert 6634c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6635c4837394SDouglas Gilbert if (n > 0) 6636c4837394SDouglas Gilbert sdebug_statistics = true; 6637c4837394SDouglas Gilbert else { 6638c4837394SDouglas Gilbert clear_queue_stats(); 6639c4837394SDouglas Gilbert sdebug_statistics = false; 6640c4837394SDouglas Gilbert } 6641c4837394SDouglas Gilbert return count; 6642c4837394SDouglas Gilbert } 6643c4837394SDouglas Gilbert return -EINVAL; 6644c4837394SDouglas Gilbert } 6645c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6646c4837394SDouglas Gilbert 664782069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6648597136abSMartin K. Petersen { 6649773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6650597136abSMartin K. Petersen } 665182069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6652597136abSMartin K. Petersen 6653c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6654c4837394SDouglas Gilbert { 6655c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6656c4837394SDouglas Gilbert } 6657c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6658c4837394SDouglas Gilbert 665982069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6660c6a44287SMartin K. Petersen { 6661773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6662c6a44287SMartin K. Petersen } 666382069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6664c6a44287SMartin K. Petersen 666582069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6666c6a44287SMartin K. Petersen { 6667773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6668c6a44287SMartin K. Petersen } 666982069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6670c6a44287SMartin K. Petersen 667182069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6672c6a44287SMartin K. Petersen { 6673773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6674c6a44287SMartin K. Petersen } 667582069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6676c6a44287SMartin K. Petersen 667782069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6678c6a44287SMartin K. Petersen { 6679773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6680c6a44287SMartin K. Petersen } 668182069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6682c6a44287SMartin K. Petersen 668382069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 668444d92694SMartin K. Petersen { 668587c715dcSDouglas Gilbert ssize_t count = 0; 668644d92694SMartin K. Petersen 66875b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 668844d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 668944d92694SMartin K. Petersen sdebug_store_sectors); 669044d92694SMartin K. Petersen 669187c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 669287c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 669387c715dcSDouglas Gilbert 669487c715dcSDouglas Gilbert if (sip) 6695c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 669687c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 669787c715dcSDouglas Gilbert } 669844d92694SMartin K. Petersen buf[count++] = '\n'; 6699c7badc90STejun Heo buf[count] = '\0'; 670044d92694SMartin K. Petersen 670144d92694SMartin K. Petersen return count; 670244d92694SMartin K. Petersen } 670382069379SAkinobu Mita static DRIVER_ATTR_RO(map); 670444d92694SMartin K. Petersen 67050c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 67060c4bc91dSDouglas Gilbert { 67070c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 67080c4bc91dSDouglas Gilbert } 67090c4bc91dSDouglas Gilbert 67100c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 67110c4bc91dSDouglas Gilbert size_t count) 67120c4bc91dSDouglas Gilbert { 67130c4bc91dSDouglas Gilbert bool v; 67140c4bc91dSDouglas Gilbert 67150c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 67160c4bc91dSDouglas Gilbert return -EINVAL; 67170c4bc91dSDouglas Gilbert 67180c4bc91dSDouglas Gilbert sdebug_random = v; 67190c4bc91dSDouglas Gilbert return count; 67200c4bc91dSDouglas Gilbert } 67210c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 67220c4bc91dSDouglas Gilbert 672382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6724d986788bSMartin Pitt { 6725773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6726d986788bSMartin Pitt } 672782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 672882069379SAkinobu Mita size_t count) 6729d986788bSMartin Pitt { 6730d986788bSMartin Pitt int n; 6731d986788bSMartin Pitt 6732d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6733773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6734d986788bSMartin Pitt return count; 6735d986788bSMartin Pitt } 6736d986788bSMartin Pitt return -EINVAL; 6737d986788bSMartin Pitt } 673882069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6739d986788bSMartin Pitt 6740cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6741cbf67842SDouglas Gilbert { 6742773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6743cbf67842SDouglas Gilbert } 6744185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6745cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6746cbf67842SDouglas Gilbert size_t count) 6747cbf67842SDouglas Gilbert { 6748185dd232SDouglas Gilbert int n; 6749cbf67842SDouglas Gilbert 6750cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6751185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6752185dd232SDouglas Gilbert return count; 6753cbf67842SDouglas Gilbert } 6754cbf67842SDouglas Gilbert return -EINVAL; 6755cbf67842SDouglas Gilbert } 6756cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6757cbf67842SDouglas Gilbert 6758c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6759c2248fc9SDouglas Gilbert { 6760773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6761c2248fc9SDouglas Gilbert } 6762c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6763c2248fc9SDouglas Gilbert size_t count) 6764c2248fc9SDouglas Gilbert { 6765c2248fc9SDouglas Gilbert int n; 6766c2248fc9SDouglas Gilbert 6767c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6768773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6769c2248fc9SDouglas Gilbert return count; 6770c2248fc9SDouglas Gilbert } 6771c2248fc9SDouglas Gilbert return -EINVAL; 6772c2248fc9SDouglas Gilbert } 6773c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6774c2248fc9SDouglas Gilbert 677509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 677609ba24c1SDouglas Gilbert { 677709ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 677809ba24c1SDouglas Gilbert } 677909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 678009ba24c1SDouglas Gilbert 67819b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 67829b760fd8SDouglas Gilbert { 67839b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 67849b760fd8SDouglas Gilbert } 67859b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 67869b760fd8SDouglas Gilbert size_t count) 67879b760fd8SDouglas Gilbert { 67889b760fd8SDouglas Gilbert int ret, n; 67899b760fd8SDouglas Gilbert 67909b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 67919b760fd8SDouglas Gilbert if (ret) 67929b760fd8SDouglas Gilbert return ret; 67939b760fd8SDouglas Gilbert sdebug_cdb_len = n; 67949b760fd8SDouglas Gilbert all_config_cdb_len(); 67959b760fd8SDouglas Gilbert return count; 67969b760fd8SDouglas Gilbert } 67979b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 67989b760fd8SDouglas Gilbert 67999267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 68009267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 68019267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 68029267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 68039267e0ebSDouglas Gilbert }; 68049267e0ebSDouglas Gilbert 68059267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 68069267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 68079267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 68089267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 68099267e0ebSDouglas Gilbert }; 68109267e0ebSDouglas Gilbert 68119267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 68129267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 68139267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 68149267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 68159267e0ebSDouglas Gilbert }; 68169267e0ebSDouglas Gilbert 68179267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 68189267e0ebSDouglas Gilbert { 68199267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 68209267e0ebSDouglas Gilbert 68219267e0ebSDouglas Gilbert if (res < 0) { 68229267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 68239267e0ebSDouglas Gilbert if (res < 0) { 68249267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 682547742bdeSDan Carpenter if (res < 0) 68269267e0ebSDouglas Gilbert return -EINVAL; 68279267e0ebSDouglas Gilbert } 68289267e0ebSDouglas Gilbert } 68299267e0ebSDouglas Gilbert return res; 68309267e0ebSDouglas Gilbert } 68319267e0ebSDouglas Gilbert 68329267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 68339267e0ebSDouglas Gilbert { 68349267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 68359267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 68369267e0ebSDouglas Gilbert } 68379267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6838cbf67842SDouglas Gilbert 6839fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6840fc13638aSDouglas Gilbert { 6841fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6842fc13638aSDouglas Gilbert } 6843fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6844fc13638aSDouglas Gilbert 684582069379SAkinobu Mita /* Note: The following array creates attribute files in the 684623183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 684723183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 684823183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 684987c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 685023183910SDouglas Gilbert */ 68516ecaff7fSRandy Dunlap 685282069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 685382069379SAkinobu Mita &driver_attr_delay.attr, 685482069379SAkinobu Mita &driver_attr_opts.attr, 685582069379SAkinobu Mita &driver_attr_ptype.attr, 685682069379SAkinobu Mita &driver_attr_dsense.attr, 685782069379SAkinobu Mita &driver_attr_fake_rw.attr, 6858c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 685982069379SAkinobu Mita &driver_attr_no_lun_0.attr, 686082069379SAkinobu Mita &driver_attr_num_tgts.attr, 686182069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 686282069379SAkinobu Mita &driver_attr_num_parts.attr, 686382069379SAkinobu Mita &driver_attr_every_nth.attr, 6864ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 686582069379SAkinobu Mita &driver_attr_max_luns.attr, 686682069379SAkinobu Mita &driver_attr_max_queue.attr, 68677109f370SDouglas Gilbert &driver_attr_no_rwlock.attr, 686882069379SAkinobu Mita &driver_attr_no_uld.attr, 686982069379SAkinobu Mita &driver_attr_scsi_level.attr, 687082069379SAkinobu Mita &driver_attr_virtual_gb.attr, 687182069379SAkinobu Mita &driver_attr_add_host.attr, 687287c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 687382069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 687482069379SAkinobu Mita &driver_attr_sector_size.attr, 6875c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6876c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 687782069379SAkinobu Mita &driver_attr_dix.attr, 687882069379SAkinobu Mita &driver_attr_dif.attr, 687982069379SAkinobu Mita &driver_attr_guard.attr, 688082069379SAkinobu Mita &driver_attr_ato.attr, 688182069379SAkinobu Mita &driver_attr_map.attr, 68820c4bc91dSDouglas Gilbert &driver_attr_random.attr, 688382069379SAkinobu Mita &driver_attr_removable.attr, 6884cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6885cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6886c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 688709ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 68889b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6889fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 68909267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 689182069379SAkinobu Mita NULL, 689282069379SAkinobu Mita }; 689382069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 68941da177e4SLinus Torvalds 689511ddcecaSAkinobu Mita static struct device *pseudo_primary; 68968dea0d02SFUJITA Tomonori 68971da177e4SLinus Torvalds static int __init scsi_debug_init(void) 68981da177e4SLinus Torvalds { 689987c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 69005f2578e5SFUJITA Tomonori unsigned long sz; 690187c715dcSDouglas Gilbert int k, ret, hosts_to_add; 690287c715dcSDouglas Gilbert int idx = -1; 69031da177e4SLinus Torvalds 690487c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 690587c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6906cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6907cbf67842SDouglas Gilbert 6908773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6909c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6910773642d9SDouglas Gilbert sdebug_ndelay = 0; 6911773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6912c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6913cbf67842SDouglas Gilbert 6914773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6915597136abSMartin K. Petersen case 512: 6916597136abSMartin K. Petersen case 1024: 6917597136abSMartin K. Petersen case 2048: 6918597136abSMartin K. Petersen case 4096: 6919597136abSMartin K. Petersen break; 6920597136abSMartin K. Petersen default: 6921773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6922597136abSMartin K. Petersen return -EINVAL; 6923597136abSMartin K. Petersen } 6924597136abSMartin K. Petersen 6925773642d9SDouglas Gilbert switch (sdebug_dif) { 69268475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6927f46eb0e9SDouglas Gilbert break; 69288475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 69298475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 69308475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6931f46eb0e9SDouglas Gilbert have_dif_prot = true; 6932c6a44287SMartin K. Petersen break; 6933c6a44287SMartin K. Petersen 6934c6a44287SMartin K. Petersen default: 6935c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6936c6a44287SMartin K. Petersen return -EINVAL; 6937c6a44287SMartin K. Petersen } 6938c6a44287SMartin K. Petersen 6939aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6940aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6941aa5334c4SMaurizio Lombardi return -EINVAL; 6942aa5334c4SMaurizio Lombardi } 6943aa5334c4SMaurizio Lombardi 6944773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6945c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6946c6a44287SMartin K. Petersen return -EINVAL; 6947c6a44287SMartin K. Petersen } 6948c6a44287SMartin K. Petersen 6949773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6950c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6951c6a44287SMartin K. Petersen return -EINVAL; 6952c6a44287SMartin K. Petersen } 6953c6a44287SMartin K. Petersen 6954773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6955773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6956ea61fca5SMartin K. Petersen return -EINVAL; 6957ea61fca5SMartin K. Petersen } 6958ad0c7775SDouglas Gilbert 6959ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6960ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6961ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6962ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6963ad0c7775SDouglas Gilbert } 6964ad0c7775SDouglas Gilbert 69658d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6966ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6967ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 69688d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 69698d039e22SDouglas Gilbert } 6970ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6971ad0c7775SDouglas Gilbert } 6972ea61fca5SMartin K. Petersen 6973773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6974773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6975ea61fca5SMartin K. Petersen return -EINVAL; 6976ea61fca5SMartin K. Petersen } 6977ea61fca5SMartin K. Petersen 6978c4837394SDouglas Gilbert if (submit_queues < 1) { 6979c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6980c4837394SDouglas Gilbert return -EINVAL; 6981c4837394SDouglas Gilbert } 6982c87bf24cSJohn Garry 6983c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6984c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6985c87bf24cSJohn Garry return -EINVAL; 6986c87bf24cSJohn Garry } 6987c87bf24cSJohn Garry 6988c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6989c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6990c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6991c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6992c10fa55fSJohn Garry return -EINVAL; 6993c10fa55fSJohn Garry } 6994c10fa55fSJohn Garry 6995c10fa55fSJohn Garry if (sdebug_host_max_queue && 6996c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6997c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6998c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6999c10fa55fSJohn Garry sdebug_max_queue); 7000c10fa55fSJohn Garry } 7001c10fa55fSJohn Garry 7002c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 7003c4837394SDouglas Gilbert GFP_KERNEL); 7004c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 7005c4837394SDouglas Gilbert return -ENOMEM; 7006c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 7007c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 7008c4837394SDouglas Gilbert 7009f0d1cf93SDouglas Gilbert /* 70109267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 70119267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 7012f0d1cf93SDouglas Gilbert */ 70139267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 70149267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 70159267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 70169267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 70179267e0ebSDouglas Gilbert if (k < 0) { 70189267e0ebSDouglas Gilbert ret = k; 70193b01d7eaSDinghao Liu goto free_q_arr; 70209267e0ebSDouglas Gilbert } 70219267e0ebSDouglas Gilbert sdeb_zbc_model = k; 70229267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 70239267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 702464e14eceSDamien Le Moal case BLK_ZONED_HA: 70259267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 70269267e0ebSDouglas Gilbert break; 70279267e0ebSDouglas Gilbert case BLK_ZONED_HM: 70289267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 70299267e0ebSDouglas Gilbert break; 70309267e0ebSDouglas Gilbert default: 70319267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 70323b01d7eaSDinghao Liu ret = -EINVAL; 70333b01d7eaSDinghao Liu goto free_q_arr; 70349267e0ebSDouglas Gilbert } 70359267e0ebSDouglas Gilbert } 70369267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 7037f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 70389267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70399267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 70409267e0ebSDouglas Gilbert } 7041f0d1cf93SDouglas Gilbert 70429267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70439267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 7044773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 7045773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 7046773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 7047773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 704828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 70491da177e4SLinus Torvalds 70501da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 70511da177e4SLinus Torvalds sdebug_heads = 8; 70521da177e4SLinus Torvalds sdebug_sectors_per = 32; 7053773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 70541da177e4SLinus Torvalds sdebug_heads = 64; 7055773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 7056fa785f0aSAndy Shevchenko sdebug_heads = 32; 70571da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70581da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70591da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 70601da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 70611da177e4SLinus Torvalds sdebug_heads = 255; 70621da177e4SLinus Torvalds sdebug_sectors_per = 63; 70631da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70641da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70651da177e4SLinus Torvalds } 70665b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 7067773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 7068773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 70696014759cSMartin K. Petersen 7070773642d9SDouglas Gilbert sdebug_unmap_max_desc = 7071773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 70726014759cSMartin K. Petersen 7073773642d9SDouglas Gilbert sdebug_unmap_granularity = 7074773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 70756014759cSMartin K. Petersen 7076773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 7077773642d9SDouglas Gilbert sdebug_unmap_granularity <= 7078773642d9SDouglas Gilbert sdebug_unmap_alignment) { 7079c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 7080c4837394SDouglas Gilbert ret = -EINVAL; 708187c715dcSDouglas Gilbert goto free_q_arr; 708244d92694SMartin K. Petersen } 708344d92694SMartin K. Petersen } 708487c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 708587c715dcSDouglas Gilbert if (want_store) { 708687c715dcSDouglas Gilbert idx = sdebug_add_store(); 708787c715dcSDouglas Gilbert if (idx < 0) { 708887c715dcSDouglas Gilbert ret = idx; 708987c715dcSDouglas Gilbert goto free_q_arr; 709087c715dcSDouglas Gilbert } 709144d92694SMartin K. Petersen } 709244d92694SMartin K. Petersen 70939b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 70949b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 7095c1287970STomas Winkler pr_warn("root_device_register() error\n"); 70969b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 70976ecaff7fSRandy Dunlap goto free_vm; 70986ecaff7fSRandy Dunlap } 70996ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 71006ecaff7fSRandy Dunlap if (ret < 0) { 7101c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 71026ecaff7fSRandy Dunlap goto dev_unreg; 71036ecaff7fSRandy Dunlap } 71046ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 71056ecaff7fSRandy Dunlap if (ret < 0) { 7106c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 71076ecaff7fSRandy Dunlap goto bus_unreg; 71086ecaff7fSRandy Dunlap } 71091da177e4SLinus Torvalds 711087c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 7111773642d9SDouglas Gilbert sdebug_add_host = 0; 71121da177e4SLinus Torvalds 711387c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 711487c715dcSDouglas Gilbert if (want_store && k == 0) { 711587c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 711687c715dcSDouglas Gilbert if (ret < 0) { 711787c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 711887c715dcSDouglas Gilbert k, -ret); 711987c715dcSDouglas Gilbert break; 712087c715dcSDouglas Gilbert } 712187c715dcSDouglas Gilbert } else { 712287c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 712387c715dcSDouglas Gilbert sdebug_per_host_store); 712487c715dcSDouglas Gilbert if (ret < 0) { 712587c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 71261da177e4SLinus Torvalds break; 71271da177e4SLinus Torvalds } 71281da177e4SLinus Torvalds } 712987c715dcSDouglas Gilbert } 7130773642d9SDouglas Gilbert if (sdebug_verbose) 7131f19fe8f3SBart Van Assche pr_info("built %d host(s)\n", sdebug_num_hosts); 7132c1287970STomas Winkler 71331da177e4SLinus Torvalds return 0; 71346ecaff7fSRandy Dunlap 71356ecaff7fSRandy Dunlap bus_unreg: 71366ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 71376ecaff7fSRandy Dunlap dev_unreg: 71389b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71396ecaff7fSRandy Dunlap free_vm: 714087c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 7141c4837394SDouglas Gilbert free_q_arr: 7142c4837394SDouglas Gilbert kfree(sdebug_q_arr); 71436ecaff7fSRandy Dunlap return ret; 71441da177e4SLinus Torvalds } 71451da177e4SLinus Torvalds 71461da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 71471da177e4SLinus Torvalds { 7148f19fe8f3SBart Van Assche int k = sdebug_num_hosts; 71491da177e4SLinus Torvalds 7150f19fe8f3SBart Van Assche stop_all_queued(); 7151f19fe8f3SBart Van Assche for (; k; k--) 715287c715dcSDouglas Gilbert sdebug_do_remove_host(true); 715352ab9768SLuis Henriques free_all_queued(); 71541da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 71551da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 71569b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71571da177e4SLinus Torvalds 715887c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 715987c715dcSDouglas Gilbert xa_destroy(per_store_ap); 7160f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 71611da177e4SLinus Torvalds } 71621da177e4SLinus Torvalds 71631da177e4SLinus Torvalds device_initcall(scsi_debug_init); 71641da177e4SLinus Torvalds module_exit(scsi_debug_exit); 71651da177e4SLinus Torvalds 71661da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 71671da177e4SLinus Torvalds { 71681da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71691da177e4SLinus Torvalds 71701da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 71711da177e4SLinus Torvalds kfree(sdbg_host); 71721da177e4SLinus Torvalds } 71731da177e4SLinus Torvalds 717487c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 717587c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 71761da177e4SLinus Torvalds { 717787c715dcSDouglas Gilbert if (idx < 0) 717887c715dcSDouglas Gilbert return; 717987c715dcSDouglas Gilbert if (!sip) { 718087c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 718187c715dcSDouglas Gilbert return; 718287c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 718387c715dcSDouglas Gilbert if (!sip) 718487c715dcSDouglas Gilbert return; 718587c715dcSDouglas Gilbert } 718687c715dcSDouglas Gilbert vfree(sip->map_storep); 718787c715dcSDouglas Gilbert vfree(sip->dif_storep); 718887c715dcSDouglas Gilbert vfree(sip->storep); 718987c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 719087c715dcSDouglas Gilbert kfree(sip); 719187c715dcSDouglas Gilbert } 719287c715dcSDouglas Gilbert 719387c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 719487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 719587c715dcSDouglas Gilbert { 719687c715dcSDouglas Gilbert unsigned long idx; 719787c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 719887c715dcSDouglas Gilbert 719987c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 720087c715dcSDouglas Gilbert if (apart_from_first) 720187c715dcSDouglas Gilbert apart_from_first = false; 720287c715dcSDouglas Gilbert else 720387c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 720487c715dcSDouglas Gilbert } 720587c715dcSDouglas Gilbert if (apart_from_first) 720687c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 720787c715dcSDouglas Gilbert } 720887c715dcSDouglas Gilbert 720987c715dcSDouglas Gilbert /* 721087c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 721187c715dcSDouglas Gilbert * Limit the number of stores to 65536. 721287c715dcSDouglas Gilbert */ 721387c715dcSDouglas Gilbert static int sdebug_add_store(void) 721487c715dcSDouglas Gilbert { 721587c715dcSDouglas Gilbert int res; 721687c715dcSDouglas Gilbert u32 n_idx; 721787c715dcSDouglas Gilbert unsigned long iflags; 721887c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 721987c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 722087c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 722187c715dcSDouglas Gilbert 722287c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 722387c715dcSDouglas Gilbert if (!sip) 722487c715dcSDouglas Gilbert return -ENOMEM; 722587c715dcSDouglas Gilbert 722687c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 722787c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 722887c715dcSDouglas Gilbert if (unlikely(res < 0)) { 722987c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 723087c715dcSDouglas Gilbert kfree(sip); 723187c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 723287c715dcSDouglas Gilbert return res; 723387c715dcSDouglas Gilbert } 723487c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 723587c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 723687c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 723787c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 723887c715dcSDouglas Gilbert 723987c715dcSDouglas Gilbert res = -ENOMEM; 724087c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 724187c715dcSDouglas Gilbert if (!sip->storep) { 724287c715dcSDouglas Gilbert pr_err("user data oom\n"); 724387c715dcSDouglas Gilbert goto err; 724487c715dcSDouglas Gilbert } 724587c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 724687c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 724787c715dcSDouglas Gilbert 724887c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 724987c715dcSDouglas Gilbert if (sdebug_dix) { 725087c715dcSDouglas Gilbert int dif_size; 725187c715dcSDouglas Gilbert 725287c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 725387c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 725487c715dcSDouglas Gilbert 725587c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 725687c715dcSDouglas Gilbert sip->dif_storep); 725787c715dcSDouglas Gilbert 725887c715dcSDouglas Gilbert if (!sip->dif_storep) { 725987c715dcSDouglas Gilbert pr_err("DIX oom\n"); 726087c715dcSDouglas Gilbert goto err; 726187c715dcSDouglas Gilbert } 726287c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 726387c715dcSDouglas Gilbert } 726487c715dcSDouglas Gilbert /* Logical Block Provisioning */ 726587c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 726687c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 726787c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 726887c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 726987c715dcSDouglas Gilbert 727087c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 727187c715dcSDouglas Gilbert 727287c715dcSDouglas Gilbert if (!sip->map_storep) { 727387c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 727487c715dcSDouglas Gilbert goto err; 727587c715dcSDouglas Gilbert } 727687c715dcSDouglas Gilbert 727787c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 727887c715dcSDouglas Gilbert 727987c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 728087c715dcSDouglas Gilbert if (sdebug_num_parts) 728187c715dcSDouglas Gilbert map_region(sip, 0, 2); 728287c715dcSDouglas Gilbert } 728387c715dcSDouglas Gilbert 728487c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 728587c715dcSDouglas Gilbert return (int)n_idx; 728687c715dcSDouglas Gilbert err: 728787c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 728887c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 728987c715dcSDouglas Gilbert return res; 729087c715dcSDouglas Gilbert } 729187c715dcSDouglas Gilbert 729287c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 729387c715dcSDouglas Gilbert { 729487c715dcSDouglas Gilbert int k, devs_per_host, idx; 729587c715dcSDouglas Gilbert int error = -ENOMEM; 72961da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72978b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 72981da177e4SLinus Torvalds 729924669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 730087c715dcSDouglas Gilbert if (!sdbg_host) 73011da177e4SLinus Torvalds return -ENOMEM; 730287c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 730387c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 730487c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 730587c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 73061da177e4SLinus Torvalds 73071da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 73081da177e4SLinus Torvalds 7309773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 73101da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 73115cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 731287c715dcSDouglas Gilbert if (!sdbg_devinfo) 73131da177e4SLinus Torvalds goto clean; 73141da177e4SLinus Torvalds } 73151da177e4SLinus Torvalds 73161da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73171da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 73181da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73191da177e4SLinus Torvalds 73201da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 73219b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 73221da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 7323f19fe8f3SBart Van Assche dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 73241da177e4SLinus Torvalds 73251da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 7326*e208a1d7SYuan Can if (error) { 7327*e208a1d7SYuan Can spin_lock(&sdebug_host_list_lock); 7328*e208a1d7SYuan Can list_del(&sdbg_host->host_list); 7329*e208a1d7SYuan Can spin_unlock(&sdebug_host_list_lock); 73301da177e4SLinus Torvalds goto clean; 7331*e208a1d7SYuan Can } 73321da177e4SLinus Torvalds 7333f19fe8f3SBart Van Assche ++sdebug_num_hosts; 733487c715dcSDouglas Gilbert return 0; 73351da177e4SLinus Torvalds 73361da177e4SLinus Torvalds clean: 73378b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 73388b40228fSFUJITA Tomonori dev_list) { 73391da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7340f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 73411da177e4SLinus Torvalds kfree(sdbg_devinfo); 73421da177e4SLinus Torvalds } 73431da177e4SLinus Torvalds kfree(sdbg_host); 734487c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 73451da177e4SLinus Torvalds return error; 73461da177e4SLinus Torvalds } 73471da177e4SLinus Torvalds 734887c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 73491da177e4SLinus Torvalds { 735087c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 735187c715dcSDouglas Gilbert 735287c715dcSDouglas Gilbert if (mk_new_store) { 735387c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 735487c715dcSDouglas Gilbert if (ph_idx < 0) 735587c715dcSDouglas Gilbert return ph_idx; 735687c715dcSDouglas Gilbert } 735787c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 735887c715dcSDouglas Gilbert } 735987c715dcSDouglas Gilbert 736087c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 736187c715dcSDouglas Gilbert { 736287c715dcSDouglas Gilbert int idx = -1; 73631da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 736487c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 73651da177e4SLinus Torvalds 73661da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73671da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 73681da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 73691da177e4SLinus Torvalds struct sdebug_host_info, host_list); 737087c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 73711da177e4SLinus Torvalds } 737287c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 737387c715dcSDouglas Gilbert bool unique = true; 737487c715dcSDouglas Gilbert 737587c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 737687c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 737787c715dcSDouglas Gilbert continue; 737887c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 737987c715dcSDouglas Gilbert unique = false; 738087c715dcSDouglas Gilbert break; 738187c715dcSDouglas Gilbert } 738287c715dcSDouglas Gilbert } 738387c715dcSDouglas Gilbert if (unique) { 738487c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 738587c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 738687c715dcSDouglas Gilbert --sdeb_most_recent_idx; 738787c715dcSDouglas Gilbert } 738887c715dcSDouglas Gilbert } 738987c715dcSDouglas Gilbert if (sdbg_host) 739087c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 73911da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73921da177e4SLinus Torvalds 73931da177e4SLinus Torvalds if (!sdbg_host) 73941da177e4SLinus Torvalds return; 73951da177e4SLinus Torvalds 73961da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 7397f19fe8f3SBart Van Assche --sdebug_num_hosts; 73981da177e4SLinus Torvalds } 73991da177e4SLinus Torvalds 7400fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7401cbf67842SDouglas Gilbert { 7402cbf67842SDouglas Gilbert int num_in_q = 0; 7403cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7404cbf67842SDouglas Gilbert 7405f19fe8f3SBart Van Assche block_unblock_all_queues(true); 7406cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7407cbf67842SDouglas Gilbert if (NULL == devip) { 7408f19fe8f3SBart Van Assche block_unblock_all_queues(false); 7409cbf67842SDouglas Gilbert return -ENODEV; 7410cbf67842SDouglas Gilbert } 7411cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7412c40ecc12SChristoph Hellwig 7413fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7414fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7415fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7416fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7417fc09acb7SDouglas Gilbert } 7418cbf67842SDouglas Gilbert if (qdepth < 1) 7419cbf67842SDouglas Gilbert qdepth = 1; 7420fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7421db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7422cbf67842SDouglas Gilbert 7423773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7424c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7425c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7426cbf67842SDouglas Gilbert } 7427f19fe8f3SBart Van Assche block_unblock_all_queues(false); 7428cbf67842SDouglas Gilbert return sdev->queue_depth; 7429cbf67842SDouglas Gilbert } 7430cbf67842SDouglas Gilbert 7431c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7432817fd66bSDouglas Gilbert { 7433c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7434773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7435773642d9SDouglas Gilbert sdebug_every_nth = -1; 7436773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7437c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7438773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7439817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7440c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7441817fd66bSDouglas Gilbert } 7442c4837394SDouglas Gilbert return false; 7443817fd66bSDouglas Gilbert } 7444817fd66bSDouglas Gilbert 7445fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7446fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7447fc13638aSDouglas Gilbert { 7448fc13638aSDouglas Gilbert int stopped_state; 7449fc13638aSDouglas Gilbert u64 diff_ns = 0; 7450fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7451fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7452fc13638aSDouglas Gilbert 7453fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7454fc13638aSDouglas Gilbert if (stopped_state == 2) { 7455fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7456fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7457fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7458fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7459fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7460fc13638aSDouglas Gilbert return 0; 7461fc13638aSDouglas Gilbert } 7462fc13638aSDouglas Gilbert } 7463fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7464fc13638aSDouglas Gilbert if (sdebug_verbose) 7465fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7466fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7467fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7468fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7469fc13638aSDouglas Gilbert 7470fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7471fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7472fc13638aSDouglas Gilbert else 7473fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7474fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7475fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7476fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7477fc13638aSDouglas Gilbert diff_ns); 7478fc13638aSDouglas Gilbert return check_condition_result; 7479fc13638aSDouglas Gilbert } 7480fc13638aSDouglas Gilbert } 7481fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7482fc13638aSDouglas Gilbert if (sdebug_verbose) 7483fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7484fc13638aSDouglas Gilbert my_name); 7485fc13638aSDouglas Gilbert return check_condition_result; 7486fc13638aSDouglas Gilbert } 7487fc13638aSDouglas Gilbert 7488a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost) 7489c4b57d89SKashyap Desai { 7490c4b57d89SKashyap Desai int i, qoff; 7491c4b57d89SKashyap Desai 7492c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7493a4e1d0b7SBart Van Assche return; 7494c4b57d89SKashyap Desai 7495c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7496c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7497c4b57d89SKashyap Desai 7498c4b57d89SKashyap Desai map->nr_queues = 0; 7499c4b57d89SKashyap Desai 7500c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7501c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7502c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7503c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7504c4b57d89SKashyap Desai 7505c4b57d89SKashyap Desai if (!map->nr_queues) { 7506c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7507c4b57d89SKashyap Desai continue; 7508c4b57d89SKashyap Desai } 7509c4b57d89SKashyap Desai 7510c4b57d89SKashyap Desai map->queue_offset = qoff; 7511c4b57d89SKashyap Desai blk_mq_map_queues(map); 7512c4b57d89SKashyap Desai 7513c4b57d89SKashyap Desai qoff += map->nr_queues; 7514c4b57d89SKashyap Desai } 7515c4b57d89SKashyap Desai } 7516c4b57d89SKashyap Desai 7517c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7518c4b57d89SKashyap Desai { 75194a0c6f43SDouglas Gilbert bool first; 75204a0c6f43SDouglas Gilbert bool retiring = false; 75214a0c6f43SDouglas Gilbert int num_entries = 0; 75224a0c6f43SDouglas Gilbert unsigned int qc_idx = 0; 7523c4b57d89SKashyap Desai unsigned long iflags; 75244a0c6f43SDouglas Gilbert ktime_t kt_from_boot = ktime_get_boottime(); 7525c4b57d89SKashyap Desai struct sdebug_queue *sqp; 7526c4b57d89SKashyap Desai struct sdebug_queued_cmd *sqcp; 7527c4b57d89SKashyap Desai struct scsi_cmnd *scp; 7528c4b57d89SKashyap Desai struct sdebug_dev_info *devip; 75294a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7530c4b57d89SKashyap Desai 7531c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 75324a0c6f43SDouglas Gilbert 7533c4b57d89SKashyap Desai spin_lock_irqsave(&sqp->qc_lock, iflags); 75344a0c6f43SDouglas Gilbert 75356a0d0ae3SDamien Le Moal qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 75366a0d0ae3SDamien Le Moal if (qc_idx >= sdebug_max_queue) 75376a0d0ae3SDamien Le Moal goto unlock; 75386a0d0ae3SDamien Le Moal 75394a0c6f43SDouglas Gilbert for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { 75404a0c6f43SDouglas Gilbert if (first) { 75414a0c6f43SDouglas Gilbert first = false; 7542b05d4e48SDouglas Gilbert if (!test_bit(qc_idx, sqp->in_use_bm)) 7543b05d4e48SDouglas Gilbert continue; 75444a0c6f43SDouglas Gilbert } else { 75454a0c6f43SDouglas Gilbert qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1); 75464a0c6f43SDouglas Gilbert } 7547b05d4e48SDouglas Gilbert if (qc_idx >= sdebug_max_queue) 75484a0c6f43SDouglas Gilbert break; 7549c4b57d89SKashyap Desai 7550c4b57d89SKashyap Desai sqcp = &sqp->qc_arr[qc_idx]; 75514a0c6f43SDouglas Gilbert sd_dp = sqcp->sd_dp; 75524a0c6f43SDouglas Gilbert if (unlikely(!sd_dp)) 75534a0c6f43SDouglas Gilbert continue; 7554c4b57d89SKashyap Desai scp = sqcp->a_cmnd; 7555c4b57d89SKashyap Desai if (unlikely(scp == NULL)) { 75564a0c6f43SDouglas Gilbert pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n", 7557c4b57d89SKashyap Desai queue_num, qc_idx, __func__); 75584a0c6f43SDouglas Gilbert break; 7559c4b57d89SKashyap Desai } 7560d9d23a5aSDouglas Gilbert if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) { 75614a0c6f43SDouglas Gilbert if (kt_from_boot < sd_dp->cmpl_ts) 75624a0c6f43SDouglas Gilbert continue; 75634a0c6f43SDouglas Gilbert 75646ce913feSChristoph Hellwig } else /* ignoring non REQ_POLLED requests */ 75654a0c6f43SDouglas Gilbert continue; 7566c4b57d89SKashyap Desai devip = (struct sdebug_dev_info *)scp->device->hostdata; 7567c4b57d89SKashyap Desai if (likely(devip)) 7568c4b57d89SKashyap Desai atomic_dec(&devip->num_in_q); 7569c4b57d89SKashyap Desai else 7570c4b57d89SKashyap Desai pr_err("devip=NULL from %s\n", __func__); 7571c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 75724a0c6f43SDouglas Gilbert retiring = true; 7573c4b57d89SKashyap Desai 7574c4b57d89SKashyap Desai sqcp->a_cmnd = NULL; 7575c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 75764a0c6f43SDouglas Gilbert pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n", 7577c4b57d89SKashyap Desai sqp, queue_num, qc_idx, __func__); 75784a0c6f43SDouglas Gilbert break; 7579c4b57d89SKashyap Desai } 7580c4b57d89SKashyap Desai if (unlikely(retiring)) { /* user has reduced max_queue */ 7581c4b57d89SKashyap Desai int k, retval; 7582c4b57d89SKashyap Desai 7583c4b57d89SKashyap Desai retval = atomic_read(&retired_max_queue); 7584c4b57d89SKashyap Desai if (qc_idx >= retval) { 7585c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 75864a0c6f43SDouglas Gilbert break; 7587c4b57d89SKashyap Desai } 7588c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7589c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7590c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7591c4b57d89SKashyap Desai else 7592c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7593c4b57d89SKashyap Desai } 7594d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 7595c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 75966c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 7597c4b57d89SKashyap Desai num_entries++; 75983fd07aecSDamien Le Moal spin_lock_irqsave(&sqp->qc_lock, iflags); 7599b05d4e48SDouglas Gilbert if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue) 76003fd07aecSDamien Le Moal break; 76014a0c6f43SDouglas Gilbert } 76023fd07aecSDamien Le Moal 76036a0d0ae3SDamien Le Moal unlock: 7604c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 76053fd07aecSDamien Le Moal 76064a0c6f43SDouglas Gilbert if (num_entries > 0) 76074a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7608c4b57d89SKashyap Desai return num_entries; 7609c4b57d89SKashyap Desai } 7610c4b57d89SKashyap Desai 7611fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7612fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7613c2248fc9SDouglas Gilbert { 7614c2248fc9SDouglas Gilbert u8 sdeb_i; 7615c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7616c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7617c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7618c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7619c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7620c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7621f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7622c2248fc9SDouglas Gilbert int k, na; 7623c2248fc9SDouglas Gilbert int errsts = 0; 7624ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7625c2248fc9SDouglas Gilbert u32 flags; 7626c2248fc9SDouglas Gilbert u16 sa; 7627c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7628c2248fc9SDouglas Gilbert bool has_wlun_rl; 76293a90a63dSDouglas Gilbert bool inject_now; 7630c2248fc9SDouglas Gilbert 7631c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 76323a90a63dSDouglas Gilbert if (sdebug_statistics) { 7633c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 76343a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 76353a90a63dSDouglas Gilbert } else { 76363a90a63dSDouglas Gilbert inject_now = false; 76373a90a63dSDouglas Gilbert } 7638f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7639f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7640c2248fc9SDouglas Gilbert char b[120]; 7641c2248fc9SDouglas Gilbert int n, len, sb; 7642c2248fc9SDouglas Gilbert 7643c2248fc9SDouglas Gilbert len = scp->cmd_len; 7644c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7645c2248fc9SDouglas Gilbert if (len > 32) 7646c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7647c2248fc9SDouglas Gilbert else { 7648c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7649c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7650c2248fc9SDouglas Gilbert (u32)cmd[k]); 7651c2248fc9SDouglas Gilbert } 7652458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7653a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7654c2248fc9SDouglas Gilbert } 76553a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 76567ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 765734d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7658ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7659f46eb0e9SDouglas Gilbert goto err_out; 7660c2248fc9SDouglas Gilbert 7661c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7662c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7663c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7664f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7665f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7666c2248fc9SDouglas Gilbert if (NULL == devip) 7667f46eb0e9SDouglas Gilbert goto err_out; 7668c2248fc9SDouglas Gilbert } 76693a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 76703a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 76713a90a63dSDouglas Gilbert 7672c2248fc9SDouglas Gilbert na = oip->num_attached; 7673c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7674c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7675c2248fc9SDouglas Gilbert r_oip = oip; 7676c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7677c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7678c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7679c2248fc9SDouglas Gilbert else 7680c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7681c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7682c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7683c2248fc9SDouglas Gilbert break; 7684c2248fc9SDouglas Gilbert } 7685c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7686c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7687c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7688c2248fc9SDouglas Gilbert break; 7689c2248fc9SDouglas Gilbert } 7690c2248fc9SDouglas Gilbert } 7691c2248fc9SDouglas Gilbert if (k > na) { 7692c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7693c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7694c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7695c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7696c2248fc9SDouglas Gilbert else 7697c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7698c2248fc9SDouglas Gilbert goto check_cond; 7699c2248fc9SDouglas Gilbert } 7700c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7701c2248fc9SDouglas Gilbert flags = oip->flags; 7702f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7703c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7704c2248fc9SDouglas Gilbert goto check_cond; 7705c2248fc9SDouglas Gilbert } 7706f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7707773642d9SDouglas Gilbert if (sdebug_verbose) 7708773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7709773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7710c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7711c2248fc9SDouglas Gilbert goto check_cond; 7712c2248fc9SDouglas Gilbert } 7713f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7714c2248fc9SDouglas Gilbert u8 rem; 7715c2248fc9SDouglas Gilbert int j; 7716c2248fc9SDouglas Gilbert 7717c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7718c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7719c2248fc9SDouglas Gilbert if (rem) { 7720c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7721c2248fc9SDouglas Gilbert if (0x80 & rem) 7722c2248fc9SDouglas Gilbert break; 7723c2248fc9SDouglas Gilbert } 7724c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7725c2248fc9SDouglas Gilbert goto check_cond; 7726c2248fc9SDouglas Gilbert } 7727c2248fc9SDouglas Gilbert } 7728c2248fc9SDouglas Gilbert } 7729f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7730b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7731b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7732f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7733c2248fc9SDouglas Gilbert if (errsts) 7734c2248fc9SDouglas Gilbert goto check_cond; 7735c2248fc9SDouglas Gilbert } 7736fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7737fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7738fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7739fc13638aSDouglas Gilbert if (errsts) 7740c2248fc9SDouglas Gilbert goto fini; 7741c2248fc9SDouglas Gilbert } 7742773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7743c2248fc9SDouglas Gilbert goto fini; 7744f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7745c4837394SDouglas Gilbert if (fake_timeout(scp)) 7746c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7747c2248fc9SDouglas Gilbert } 7748f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7749f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7750f66b8517SMartin Wilck else 7751f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7752c2248fc9SDouglas Gilbert 7753c2248fc9SDouglas Gilbert fini: 775467da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7755f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 775675aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 775775aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 775880c49563SDouglas Gilbert /* 775975aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 776075aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 776175aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 776275aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 776380c49563SDouglas Gilbert */ 776480c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 77654f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 776680c49563SDouglas Gilbert 77674f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7768f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 776980c49563SDouglas Gilbert } else 7770f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 777110bde980SDouglas Gilbert sdebug_ndelay); 7772c2248fc9SDouglas Gilbert check_cond: 7773f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7774f46eb0e9SDouglas Gilbert err_out: 7775f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7776c2248fc9SDouglas Gilbert } 7777c2248fc9SDouglas Gilbert 77789e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7779c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7780c8ed555aSAl Viro .write_info = scsi_debug_write_info, 77819e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 77829e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 77839e603ca0SFUJITA Tomonori .info = scsi_debug_info, 77849e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 77859e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 77869e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 77879e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7788185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7789cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7790c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7791c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 77929e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 77939e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7794cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7795cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 77969e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7797c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 77989e603ca0SFUJITA Tomonori .this_id = 7, 779965e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7800cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 78016bb5e6e7SAkinobu Mita .max_sectors = -1U, 780250c2e910SChristoph Hellwig .max_segment_size = -1U, 78039e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7804c40ecc12SChristoph Hellwig .track_queue_depth = 1, 78059e603ca0SFUJITA Tomonori }; 78069e603ca0SFUJITA Tomonori 78071da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 78081da177e4SLinus Torvalds { 78091da177e4SLinus Torvalds int error = 0; 78101da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 78111da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7812f46eb0e9SDouglas Gilbert int hprot; 78131da177e4SLinus Torvalds 78141da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 78151da177e4SLinus Torvalds 7816773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7817fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 78182a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 78194af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 78204af14d11SChristoph Hellwig 78211da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 78221da177e4SLinus Torvalds if (NULL == hpnt) { 7823c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 78241da177e4SLinus Torvalds error = -ENODEV; 78251da177e4SLinus Torvalds return error; 78261da177e4SLinus Torvalds } 7827c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 78289b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7829c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7830c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7831c4837394SDouglas Gilbert } 7832c10fa55fSJohn Garry /* 7833c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7834f7c4cdc7SJohn Garry * following should give the same answer for each host. 7835c10fa55fSJohn Garry */ 7836c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7837f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7838f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 78391da177e4SLinus Torvalds 7840c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7841c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7842c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7843c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7844c4b57d89SKashyap Desai poll_queues = 0; 7845c4b57d89SKashyap Desai } 7846c4b57d89SKashyap Desai 7847c4b57d89SKashyap Desai /* 7848c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7849c4b57d89SKashyap Desai * left over for non-polled I/O. 7850c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7851c4b57d89SKashyap Desai */ 7852c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7853fc09acb7SDouglas Gilbert if (submit_queues < 3) 7854c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7855fc09acb7SDouglas Gilbert else 7856fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7857fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7858c4b57d89SKashyap Desai poll_queues = 1; 7859c4b57d89SKashyap Desai } 7860c4b57d89SKashyap Desai if (poll_queues) 7861c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7862c4b57d89SKashyap Desai 78631da177e4SLinus Torvalds sdbg_host->shost = hpnt; 78641da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7865773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7866773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 78671da177e4SLinus Torvalds else 7868773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7869773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7870f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 78711da177e4SLinus Torvalds 7872f46eb0e9SDouglas Gilbert hprot = 0; 7873c6a44287SMartin K. Petersen 7874773642d9SDouglas Gilbert switch (sdebug_dif) { 7875c6a44287SMartin K. Petersen 78768475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7877f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7878773642d9SDouglas Gilbert if (sdebug_dix) 7879f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7880c6a44287SMartin K. Petersen break; 7881c6a44287SMartin K. Petersen 78828475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7883f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7884773642d9SDouglas Gilbert if (sdebug_dix) 7885f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7886c6a44287SMartin K. Petersen break; 7887c6a44287SMartin K. Petersen 78888475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7889f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7890773642d9SDouglas Gilbert if (sdebug_dix) 7891f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7892c6a44287SMartin K. Petersen break; 7893c6a44287SMartin K. Petersen 7894c6a44287SMartin K. Petersen default: 7895773642d9SDouglas Gilbert if (sdebug_dix) 7896f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7897c6a44287SMartin K. Petersen break; 7898c6a44287SMartin K. Petersen } 7899c6a44287SMartin K. Petersen 7900f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7901c6a44287SMartin K. Petersen 7902f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7903c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7904f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7905f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7906f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7907f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7908f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7909f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7910f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7911c6a44287SMartin K. Petersen 7912773642d9SDouglas Gilbert if (sdebug_guard == 1) 7913c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7914c6a44287SMartin K. Petersen else 7915c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7916c6a44287SMartin K. Petersen 7917773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7918773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7919c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7920c4837394SDouglas Gilbert sdebug_statistics = true; 79211da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 79221da177e4SLinus Torvalds if (error) { 7923c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 79241da177e4SLinus Torvalds error = -ENODEV; 79251da177e4SLinus Torvalds scsi_host_put(hpnt); 792687c715dcSDouglas Gilbert } else { 79271da177e4SLinus Torvalds scsi_scan_host(hpnt); 792887c715dcSDouglas Gilbert } 79291da177e4SLinus Torvalds 79301da177e4SLinus Torvalds return error; 79311da177e4SLinus Torvalds } 79321da177e4SLinus Torvalds 7933fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev) 79341da177e4SLinus Torvalds { 79351da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 79368b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 79371da177e4SLinus Torvalds 79381da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 79391da177e4SLinus Torvalds 79401da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 79411da177e4SLinus Torvalds 79428b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 79438b40228fSFUJITA Tomonori dev_list) { 79441da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7945f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 79461da177e4SLinus Torvalds kfree(sdbg_devinfo); 79471da177e4SLinus Torvalds } 79481da177e4SLinus Torvalds 79491da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 79501da177e4SLinus Torvalds } 79511da177e4SLinus Torvalds 79528dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 79538dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 79541da177e4SLinus Torvalds { 79558dea0d02SFUJITA Tomonori return 1; 79568dea0d02SFUJITA Tomonori } 79571da177e4SLinus Torvalds 79588dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 79598dea0d02SFUJITA Tomonori .name = "pseudo", 79608dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 79618dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 79628dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 796382069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 79648dea0d02SFUJITA Tomonori }; 7965