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 1902773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1903c6a44287SMartin K. Petersen 1904760f3b03SDouglas Gilbert if (have_dif_prot) { 1905773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1906c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1907c6a44287SMartin K. Petersen } 1908c6a44287SMartin K. Petersen 1909c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 19104e3ace00SYe Bin min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1911c65b1445SDouglas Gilbert } 1912c65b1445SDouglas Gilbert 19135a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 19145a09e398SHannes Reinecke 19155a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 19165a09e398SHannes Reinecke struct sdebug_dev_info *devip) 19175a09e398SHannes Reinecke { 191801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19195a09e398SHannes Reinecke unsigned char *arr; 19205a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 19215a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 1922f347c268SYe Bin u32 alen, n, rlen; 1923f347c268SYe Bin int ret; 19245a09e398SHannes Reinecke 1925773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19266f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19276f3cbf55SDouglas Gilbert if (! arr) 19286f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19295a09e398SHannes Reinecke /* 19305a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19315a09e398SHannes Reinecke * real and a fake port with no device connected. 19325a09e398SHannes Reinecke * So we create two port groups with one port each 19335a09e398SHannes Reinecke * and set the group with port B to unavailable. 19345a09e398SHannes Reinecke */ 19355a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19365a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19375a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19385a09e398SHannes Reinecke (devip->channel & 0x7f); 19395a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19405a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19415a09e398SHannes Reinecke 19425a09e398SHannes Reinecke /* 19435a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19445a09e398SHannes Reinecke */ 19455a09e398SHannes Reinecke n = 4; 1946b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19475a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19485a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19495a09e398SHannes Reinecke } else { 19505a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1951773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19525a09e398SHannes Reinecke } 1953773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1954773642d9SDouglas Gilbert n += 2; 19555a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19565a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19575a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19585a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19595a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19605a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1961773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1962773642d9SDouglas Gilbert n += 2; 19635a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19645a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1965773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1966773642d9SDouglas Gilbert n += 2; 19675a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19685a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19695a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19705a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19715a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19725a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1973773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1974773642d9SDouglas Gilbert n += 2; 19755a09e398SHannes Reinecke 19765a09e398SHannes Reinecke rlen = n - 4; 1977773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19785a09e398SHannes Reinecke 19795a09e398SHannes Reinecke /* 19805a09e398SHannes Reinecke * Return the smallest value of either 19815a09e398SHannes Reinecke * - The allocated length 19825a09e398SHannes Reinecke * - The constructed command length 19835a09e398SHannes Reinecke * - The maximum array size 19845a09e398SHannes Reinecke */ 1985f347c268SYe Bin rlen = min(alen, n); 19865a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1987f347c268SYe Bin min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19885a09e398SHannes Reinecke kfree(arr); 19895a09e398SHannes Reinecke return ret; 19905a09e398SHannes Reinecke } 19915a09e398SHannes Reinecke 1992fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1993fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 199438d5c833SDouglas Gilbert { 199538d5c833SDouglas Gilbert bool rctd; 199638d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 199738d5c833SDouglas Gilbert u16 req_sa, u; 199838d5c833SDouglas Gilbert u32 alloc_len, a_len; 199938d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 200038d5c833SDouglas Gilbert const struct opcode_info_t *oip; 200138d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 200238d5c833SDouglas Gilbert u8 *arr; 200338d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 200438d5c833SDouglas Gilbert 200538d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 200638d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 200738d5c833SDouglas Gilbert req_opcode = cmd[3]; 200838d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 200938d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 20106d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 201138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 201238d5c833SDouglas Gilbert return check_condition_result; 201338d5c833SDouglas Gilbert } 201438d5c833SDouglas Gilbert if (alloc_len > 8192) 201538d5c833SDouglas Gilbert a_len = 8192; 201638d5c833SDouglas Gilbert else 201738d5c833SDouglas Gilbert a_len = alloc_len; 201899531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 201938d5c833SDouglas Gilbert if (NULL == arr) { 202038d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 202138d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 202238d5c833SDouglas Gilbert return check_condition_result; 202338d5c833SDouglas Gilbert } 202438d5c833SDouglas Gilbert switch (reporting_opts) { 202538d5c833SDouglas Gilbert case 0: /* all commands */ 202638d5c833SDouglas Gilbert /* count number of commands */ 202738d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 202838d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 202938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 203038d5c833SDouglas Gilbert continue; 203138d5c833SDouglas Gilbert count += (oip->num_attached + 1); 203238d5c833SDouglas Gilbert } 203338d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 203438d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 203538d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 203638d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 203738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 203838d5c833SDouglas Gilbert continue; 203938d5c833SDouglas Gilbert na = oip->num_attached; 204038d5c833SDouglas Gilbert arr[offset] = oip->opcode; 204138d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 204238d5c833SDouglas Gilbert if (rctd) 204338d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 204438d5c833SDouglas Gilbert if (FF_SA & oip->flags) 204538d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 204638d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 204738d5c833SDouglas Gilbert if (rctd) 204838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 204938d5c833SDouglas Gilbert r_oip = oip; 205038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 205138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 205238d5c833SDouglas Gilbert continue; 205338d5c833SDouglas Gilbert offset += bump; 205438d5c833SDouglas Gilbert arr[offset] = oip->opcode; 205538d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 205638d5c833SDouglas Gilbert if (rctd) 205738d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 205838d5c833SDouglas Gilbert if (FF_SA & oip->flags) 205938d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 206038d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 206138d5c833SDouglas Gilbert arr + offset + 6); 206238d5c833SDouglas Gilbert if (rctd) 206338d5c833SDouglas Gilbert put_unaligned_be16(0xa, 206438d5c833SDouglas Gilbert arr + offset + 8); 206538d5c833SDouglas Gilbert } 206638d5c833SDouglas Gilbert oip = r_oip; 206738d5c833SDouglas Gilbert offset += bump; 206838d5c833SDouglas Gilbert } 206938d5c833SDouglas Gilbert break; 207038d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 207138d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 207238d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 207338d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 207438d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 207538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 207638d5c833SDouglas Gilbert supp = 1; 207738d5c833SDouglas Gilbert offset = 4; 207838d5c833SDouglas Gilbert } else { 207938d5c833SDouglas Gilbert if (1 == reporting_opts) { 208038d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 208138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 208238d5c833SDouglas Gilbert 2, 2); 208338d5c833SDouglas Gilbert kfree(arr); 208438d5c833SDouglas Gilbert return check_condition_result; 208538d5c833SDouglas Gilbert } 208638d5c833SDouglas Gilbert req_sa = 0; 208738d5c833SDouglas Gilbert } else if (2 == reporting_opts && 208838d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 208938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 209038d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 209138d5c833SDouglas Gilbert return check_condition_result; 209238d5c833SDouglas Gilbert } 209338d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 209438d5c833SDouglas Gilbert req_opcode == oip->opcode) 209538d5c833SDouglas Gilbert supp = 3; 209638d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 209738d5c833SDouglas Gilbert na = oip->num_attached; 209838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 209938d5c833SDouglas Gilbert ++k, ++oip) { 210038d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 210138d5c833SDouglas Gilbert break; 210238d5c833SDouglas Gilbert } 210338d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 210438d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 210538d5c833SDouglas Gilbert na = oip->num_attached; 210638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 210738d5c833SDouglas Gilbert ++k, ++oip) { 210838d5c833SDouglas Gilbert if (req_sa == oip->sa) 210938d5c833SDouglas Gilbert break; 211038d5c833SDouglas Gilbert } 211138d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 211238d5c833SDouglas Gilbert } else 211338d5c833SDouglas Gilbert supp = 3; 211438d5c833SDouglas Gilbert if (3 == supp) { 211538d5c833SDouglas Gilbert u = oip->len_mask[0]; 211638d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 211738d5c833SDouglas Gilbert arr[4] = oip->opcode; 211838d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 211938d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 212038d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 212138d5c833SDouglas Gilbert offset = 4 + u; 212238d5c833SDouglas Gilbert } else 212338d5c833SDouglas Gilbert offset = 4; 212438d5c833SDouglas Gilbert } 212538d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 212638d5c833SDouglas Gilbert if (rctd) { 212738d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 212838d5c833SDouglas Gilbert offset += 12; 212938d5c833SDouglas Gilbert } 213038d5c833SDouglas Gilbert break; 213138d5c833SDouglas Gilbert default: 213238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 213338d5c833SDouglas Gilbert kfree(arr); 213438d5c833SDouglas Gilbert return check_condition_result; 213538d5c833SDouglas Gilbert } 213638d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 213738d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 213838d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 213938d5c833SDouglas Gilbert kfree(arr); 214038d5c833SDouglas Gilbert return errsts; 214138d5c833SDouglas Gilbert } 214238d5c833SDouglas Gilbert 2143fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2144fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 214538d5c833SDouglas Gilbert { 214638d5c833SDouglas Gilbert bool repd; 214738d5c833SDouglas Gilbert u32 alloc_len, len; 214838d5c833SDouglas Gilbert u8 arr[16]; 214938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 215038d5c833SDouglas Gilbert 215138d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 215238d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 215338d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 215438d5c833SDouglas Gilbert if (alloc_len < 4) { 215538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 215638d5c833SDouglas Gilbert return check_condition_result; 215738d5c833SDouglas Gilbert } 215838d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 215938d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 216038d5c833SDouglas Gilbert if (repd) { 216138d5c833SDouglas Gilbert arr[3] = 0xc; 216238d5c833SDouglas Gilbert len = 16; 216338d5c833SDouglas Gilbert } else 216438d5c833SDouglas Gilbert len = 4; 216538d5c833SDouglas Gilbert 216638d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 216738d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 216838d5c833SDouglas Gilbert } 216938d5c833SDouglas Gilbert 21701da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21731da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21741da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21751da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21781da177e4SLinus Torvalds if (1 == pcontrol) 21791da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21801da177e4SLinus Torvalds return sizeof(err_recov_pg); 21811da177e4SLinus Torvalds } 21821da177e4SLinus Torvalds 21831da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21841da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21851da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21861da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21871da177e4SLinus Torvalds 21881da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21891da177e4SLinus Torvalds if (1 == pcontrol) 21901da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21911da177e4SLinus Torvalds return sizeof(disconnect_pg); 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds 21941da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21951da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21961da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21971da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21981da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21991da177e4SLinus Torvalds 22001da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2201773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2202773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2203773642d9SDouglas Gilbert if (sdebug_removable) 22041da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 22051da177e4SLinus Torvalds if (1 == pcontrol) 22061da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 22071da177e4SLinus Torvalds return sizeof(format_pg); 22081da177e4SLinus Torvalds } 22091da177e4SLinus Torvalds 2210fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2211fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2212fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2213fd32119bSDouglas Gilbert 22141da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 22151da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2216cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2217cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2218cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 22191da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 22201da177e4SLinus Torvalds 2221773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2222cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22231da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22241da177e4SLinus Torvalds if (1 == pcontrol) 2225cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2226cbf67842SDouglas Gilbert else if (2 == pcontrol) 2227cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22281da177e4SLinus Torvalds return sizeof(caching_pg); 22291da177e4SLinus Torvalds } 22301da177e4SLinus Torvalds 2231fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2232fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2233fd32119bSDouglas Gilbert 22341da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22351da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2236c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2237c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2238c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22391da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22401da177e4SLinus Torvalds 2241773642d9SDouglas Gilbert if (sdebug_dsense) 22421da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2243c65b1445SDouglas Gilbert else 2244c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2245c6a44287SMartin K. Petersen 2246773642d9SDouglas Gilbert if (sdebug_ato) 2247c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2248c6a44287SMartin K. Petersen 22491da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22501da177e4SLinus Torvalds if (1 == pcontrol) 2251c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2252c65b1445SDouglas Gilbert else if (2 == pcontrol) 2253c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22541da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22551da177e4SLinus Torvalds } 22561da177e4SLinus Torvalds 2257c65b1445SDouglas Gilbert 22581da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22591da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2260c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22611da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2262c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2263c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2264c65b1445SDouglas Gilbert 22651da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22661da177e4SLinus Torvalds if (1 == pcontrol) 2267c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2268c65b1445SDouglas Gilbert else if (2 == pcontrol) 2269c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22701da177e4SLinus Torvalds return sizeof(iec_m_pg); 22711da177e4SLinus Torvalds } 22721da177e4SLinus Torvalds 2273c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2274c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2275c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2276c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2277c65b1445SDouglas Gilbert 2278c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2279c65b1445SDouglas Gilbert if (1 == pcontrol) 2280c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2281c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2282c65b1445SDouglas Gilbert } 2283c65b1445SDouglas Gilbert 2284c65b1445SDouglas Gilbert 2285c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2286c65b1445SDouglas Gilbert int target_dev_id) 2287c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2288c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2289c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2290773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2291773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2292c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2293c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2294c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2295c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2296773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2297773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2298c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2299c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2300c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2301c65b1445SDouglas Gilbert }; 2302c65b1445SDouglas Gilbert int port_a, port_b; 2303c65b1445SDouglas Gilbert 23041b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 23051b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 23061b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 23071b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2308c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2309c65b1445SDouglas Gilbert port_b = port_a + 1; 2310c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2311773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2312773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2313c65b1445SDouglas Gilbert if (1 == pcontrol) 2314c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2315c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2316c65b1445SDouglas Gilbert } 2317c65b1445SDouglas Gilbert 2318c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2319c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2320c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2321c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2322c65b1445SDouglas Gilbert }; 2323c65b1445SDouglas Gilbert 2324c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2325c65b1445SDouglas Gilbert if (1 == pcontrol) 2326c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2327c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2328c65b1445SDouglas Gilbert } 2329c65b1445SDouglas Gilbert 23301da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23311da177e4SLinus Torvalds 2332fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2333fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23341da177e4SLinus Torvalds { 233523183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23361da177e4SLinus Torvalds unsigned char dev_spec; 233736e07d7eSGeorge Kennedy u32 alloc_len, offset, len; 233836e07d7eSGeorge Kennedy int target_dev_id; 2339c2248fc9SDouglas Gilbert int target = scp->device->id; 23401da177e4SLinus Torvalds unsigned char *ap; 23411da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 234201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2343d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23441da177e4SLinus Torvalds 2345760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23461da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23471da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23481da177e4SLinus Torvalds subpcode = cmd[3]; 23491da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2350760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2351760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 235264e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2353d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 235423183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 235523183910SDouglas Gilbert else 235623183910SDouglas Gilbert bd_len = 0; 2357773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23581da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23591da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2360cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23611da177e4SLinus Torvalds return check_condition_result; 23621da177e4SLinus Torvalds } 2363c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2364c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2365d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2366d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2367b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23689447b6ceSMartin K. Petersen if (sdebug_wp) 23699447b6ceSMartin K. Petersen dev_spec |= 0x80; 23709447b6ceSMartin K. Petersen } else 237123183910SDouglas Gilbert dev_spec = 0x0; 23721da177e4SLinus Torvalds if (msense_6) { 23731da177e4SLinus Torvalds arr[2] = dev_spec; 237423183910SDouglas Gilbert arr[3] = bd_len; 23751da177e4SLinus Torvalds offset = 4; 23761da177e4SLinus Torvalds } else { 23771da177e4SLinus Torvalds arr[3] = dev_spec; 237823183910SDouglas Gilbert if (16 == bd_len) 237923183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 238023183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23811da177e4SLinus Torvalds offset = 8; 23821da177e4SLinus Torvalds } 23831da177e4SLinus Torvalds ap = arr + offset; 238428898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 238528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 238628898873SFUJITA Tomonori 238723183910SDouglas Gilbert if (8 == bd_len) { 2388773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2389773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2390773642d9SDouglas Gilbert else 2391773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2392773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 239323183910SDouglas Gilbert offset += bd_len; 239423183910SDouglas Gilbert ap = arr + offset; 239523183910SDouglas Gilbert } else if (16 == bd_len) { 2396773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2397773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 239823183910SDouglas Gilbert offset += bd_len; 239923183910SDouglas Gilbert ap = arr + offset; 240023183910SDouglas Gilbert } 24011da177e4SLinus Torvalds 2402c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2403c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 240422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 24051da177e4SLinus Torvalds return check_condition_result; 24061da177e4SLinus Torvalds } 2407760f3b03SDouglas Gilbert bad_pcode = false; 2408760f3b03SDouglas Gilbert 24091da177e4SLinus Torvalds switch (pcode) { 24101da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 24111da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24121da177e4SLinus Torvalds offset += len; 24131da177e4SLinus Torvalds break; 24141da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 24151da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 24161da177e4SLinus Torvalds offset += len; 24171da177e4SLinus Torvalds break; 24181da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2419760f3b03SDouglas Gilbert if (is_disk) { 24201da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 24211da177e4SLinus Torvalds offset += len; 2422760f3b03SDouglas Gilbert } else 2423760f3b03SDouglas Gilbert bad_pcode = true; 24241da177e4SLinus Torvalds break; 24251da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2426d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24271da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24281da177e4SLinus Torvalds offset += len; 2429760f3b03SDouglas Gilbert } else 2430760f3b03SDouglas Gilbert bad_pcode = true; 24311da177e4SLinus Torvalds break; 24321da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24331da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24341da177e4SLinus Torvalds offset += len; 24351da177e4SLinus Torvalds break; 2436c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2437c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 243822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2439c65b1445SDouglas Gilbert return check_condition_result; 2440c65b1445SDouglas Gilbert } 2441c65b1445SDouglas Gilbert len = 0; 2442c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2443c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2444c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2445c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2446c65b1445SDouglas Gilbert target_dev_id); 2447c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2448c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2449c65b1445SDouglas Gilbert offset += len; 2450c65b1445SDouglas Gilbert break; 24511da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24521da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24531da177e4SLinus Torvalds offset += len; 24541da177e4SLinus Torvalds break; 24551da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2456c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24571da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24581da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2459760f3b03SDouglas Gilbert if (is_disk) { 2460760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2461760f3b03SDouglas Gilbert target); 2462760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2463760f3b03SDouglas Gilbert target); 2464d36da305SDouglas Gilbert } else if (is_zbc) { 2465d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2466d36da305SDouglas Gilbert target); 2467760f3b03SDouglas Gilbert } 24681da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2469c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2470c65b1445SDouglas Gilbert if (0xff == subpcode) { 2471c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2472c65b1445SDouglas Gilbert target, target_dev_id); 2473c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2474c65b1445SDouglas Gilbert } 24751da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2476760f3b03SDouglas Gilbert offset += len; 2477c65b1445SDouglas Gilbert } else { 247822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2479c65b1445SDouglas Gilbert return check_condition_result; 2480c65b1445SDouglas Gilbert } 24811da177e4SLinus Torvalds break; 24821da177e4SLinus Torvalds default: 2483760f3b03SDouglas Gilbert bad_pcode = true; 2484760f3b03SDouglas Gilbert break; 2485760f3b03SDouglas Gilbert } 2486760f3b03SDouglas Gilbert if (bad_pcode) { 248722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24881da177e4SLinus Torvalds return check_condition_result; 24891da177e4SLinus Torvalds } 24901da177e4SLinus Torvalds if (msense_6) 24911da177e4SLinus Torvalds arr[0] = offset - 1; 2492773642d9SDouglas Gilbert else 2493773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 249436e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 2497c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2498c65b1445SDouglas Gilbert 2499fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2500fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2501c65b1445SDouglas Gilbert { 2502c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2503c2248fc9SDouglas Gilbert int param_len, res, mpage; 2504c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 250501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2506c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2507c65b1445SDouglas Gilbert 2508c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2509c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2510c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2511773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2512c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 251322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2514c65b1445SDouglas Gilbert return check_condition_result; 2515c65b1445SDouglas Gilbert } 2516c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2517c65b1445SDouglas Gilbert if (-1 == res) 2518773642d9SDouglas Gilbert return DID_ERROR << 16; 2519773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2520cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2521cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2522cbf67842SDouglas Gilbert __func__, param_len, res); 2523773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2524773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 2525e0a2c28dSGeorge Kennedy off = bd_len + (mselect6 ? 4 : 8); 2526e0a2c28dSGeorge Kennedy if (md_len > 2 || off >= res) { 252722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2528c65b1445SDouglas Gilbert return check_condition_result; 2529c65b1445SDouglas Gilbert } 2530c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2531c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2532c65b1445SDouglas Gilbert if (ps) { 253322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2534c65b1445SDouglas Gilbert return check_condition_result; 2535c65b1445SDouglas Gilbert } 2536c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2537773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2538c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2539c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2540cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2541c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2542c65b1445SDouglas Gilbert return check_condition_result; 2543c65b1445SDouglas Gilbert } 2544c65b1445SDouglas Gilbert switch (mpage) { 2545cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2546cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2547cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2548cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2549cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2550cbf67842SDouglas Gilbert } 2551cbf67842SDouglas Gilbert break; 2552c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2553c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2554c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2555c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25569447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25579447b6ceSMartin K. Petersen sdebug_wp = true; 25589447b6ceSMartin K. Petersen else 25599447b6ceSMartin K. Petersen sdebug_wp = false; 2560773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2561cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2562c65b1445SDouglas Gilbert } 2563c65b1445SDouglas Gilbert break; 2564c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2565c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2566c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2567c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2568cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2569c65b1445SDouglas Gilbert } 2570c65b1445SDouglas Gilbert break; 2571c65b1445SDouglas Gilbert default: 2572c65b1445SDouglas Gilbert break; 2573c65b1445SDouglas Gilbert } 257422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2575c65b1445SDouglas Gilbert return check_condition_result; 2576cbf67842SDouglas Gilbert set_mode_changed_ua: 2577cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2578cbf67842SDouglas Gilbert return 0; 2579c65b1445SDouglas Gilbert } 2580c65b1445SDouglas Gilbert 2581c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2582c65b1445SDouglas Gilbert { 2583c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2584c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2585c65b1445SDouglas Gilbert }; 2586c65b1445SDouglas Gilbert 2587c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2588c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2589c65b1445SDouglas Gilbert } 2590c65b1445SDouglas Gilbert 2591c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2592c65b1445SDouglas Gilbert { 2593c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2594c65b1445SDouglas Gilbert }; 2595c65b1445SDouglas Gilbert 2596c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2597c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2598c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2599c65b1445SDouglas Gilbert arr[5] = 0xff; 2600c65b1445SDouglas Gilbert } 2601c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2602c65b1445SDouglas Gilbert } 2603c65b1445SDouglas Gilbert 26040790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr) 26050790797aSDouglas Gilbert { 26060790797aSDouglas Gilbert unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8, 26070790797aSDouglas Gilbert 0x0, 40, 72, 0xff, 45, 18, 0, 0, 26080790797aSDouglas Gilbert 0x1, 0x0, 0x23, 0x8, 26090790797aSDouglas Gilbert 0x0, 55, 72, 35, 55, 45, 0, 0, 26100790797aSDouglas Gilbert }; 26110790797aSDouglas Gilbert 26120790797aSDouglas Gilbert memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg)); 26130790797aSDouglas Gilbert return sizeof(env_rep_l_spg); 26140790797aSDouglas Gilbert } 26150790797aSDouglas Gilbert 2616c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2617c65b1445SDouglas Gilbert 2618c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2619c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2620c65b1445SDouglas Gilbert { 262136e07d7eSGeorge Kennedy int ppc, sp, pcode, subpcode; 262236e07d7eSGeorge Kennedy u32 alloc_len, len, n; 2623c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 262401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2625c65b1445SDouglas Gilbert 2626c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2627c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2628c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2629c65b1445SDouglas Gilbert if (ppc || sp) { 263022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2631c65b1445SDouglas Gilbert return check_condition_result; 2632c65b1445SDouglas Gilbert } 2633c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 263423183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2635773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2636c65b1445SDouglas Gilbert arr[0] = pcode; 263723183910SDouglas Gilbert if (0 == subpcode) { 2638c65b1445SDouglas Gilbert switch (pcode) { 2639c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2640c65b1445SDouglas Gilbert n = 4; 2641c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2642c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2643c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2644c65b1445SDouglas Gilbert arr[3] = n - 4; 2645c65b1445SDouglas Gilbert break; 2646c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2647c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2648c65b1445SDouglas Gilbert break; 2649c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2650c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2651c65b1445SDouglas Gilbert break; 2652c65b1445SDouglas Gilbert default: 265322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2654c65b1445SDouglas Gilbert return check_condition_result; 2655c65b1445SDouglas Gilbert } 265623183910SDouglas Gilbert } else if (0xff == subpcode) { 265723183910SDouglas Gilbert arr[0] |= 0x40; 265823183910SDouglas Gilbert arr[1] = subpcode; 265923183910SDouglas Gilbert switch (pcode) { 266023183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 266123183910SDouglas Gilbert n = 4; 266223183910SDouglas Gilbert arr[n++] = 0x0; 266323183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 266423183910SDouglas Gilbert arr[n++] = 0x0; 266523183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 266623183910SDouglas Gilbert arr[n++] = 0xd; 266723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26680790797aSDouglas Gilbert arr[n++] = 0xd; 26690790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26700790797aSDouglas Gilbert arr[n++] = 0xd; 26710790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0xd subpages */ 267223183910SDouglas Gilbert arr[n++] = 0x2f; 267323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26740790797aSDouglas Gilbert arr[n++] = 0x2f; 26750790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0x2f subpages */ 267623183910SDouglas Gilbert arr[3] = n - 4; 267723183910SDouglas Gilbert break; 267823183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 267923183910SDouglas Gilbert n = 4; 268023183910SDouglas Gilbert arr[n++] = 0xd; 268123183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26820790797aSDouglas Gilbert arr[n++] = 0xd; 26830790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26840790797aSDouglas Gilbert arr[n++] = 0xd; 26850790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 268623183910SDouglas Gilbert arr[3] = n - 4; 268723183910SDouglas Gilbert break; 268823183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 268923183910SDouglas Gilbert n = 4; 269023183910SDouglas Gilbert arr[n++] = 0x2f; 269123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26920790797aSDouglas Gilbert arr[n++] = 0x2f; 26930790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 269423183910SDouglas Gilbert arr[3] = n - 4; 269523183910SDouglas Gilbert break; 269623183910SDouglas Gilbert default: 269722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 269823183910SDouglas Gilbert return check_condition_result; 269923183910SDouglas Gilbert } 27000790797aSDouglas Gilbert } else if (subpcode > 0) { 27010790797aSDouglas Gilbert arr[0] |= 0x40; 27020790797aSDouglas Gilbert arr[1] = subpcode; 27030790797aSDouglas Gilbert if (pcode == 0xd && subpcode == 1) 27040790797aSDouglas Gilbert arr[3] = resp_env_rep_l_spg(arr + 4); 27050790797aSDouglas Gilbert else { 27060790797aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 27070790797aSDouglas Gilbert return check_condition_result; 27080790797aSDouglas Gilbert } 270923183910SDouglas Gilbert } else { 271022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 271123183910SDouglas Gilbert return check_condition_result; 271223183910SDouglas Gilbert } 271336e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 2714c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 271536e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 2716c65b1445SDouglas Gilbert } 2717c65b1445SDouglas Gilbert 2718f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2719f0d1cf93SDouglas Gilbert { 2720f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2721f0d1cf93SDouglas Gilbert } 2722f0d1cf93SDouglas Gilbert 2723f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2724f0d1cf93SDouglas Gilbert unsigned long long lba) 2725f0d1cf93SDouglas Gilbert { 27264a5fc1c6SDamien Le Moal u32 zno = lba >> devip->zsize_shift; 27274a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp; 27284a5fc1c6SDamien Le Moal 27294a5fc1c6SDamien Le Moal if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones) 27304a5fc1c6SDamien Le Moal return &devip->zstate[zno]; 27314a5fc1c6SDamien Le Moal 27324a5fc1c6SDamien Le Moal /* 27334a5fc1c6SDamien Le Moal * If the zone capacity is less than the zone size, adjust for gap 27344a5fc1c6SDamien Le Moal * zones. 27354a5fc1c6SDamien Le Moal */ 27364a5fc1c6SDamien Le Moal zno = 2 * zno - devip->nr_conv_zones; 27374a5fc1c6SDamien Le Moal WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones); 27384a5fc1c6SDamien Le Moal zsp = &devip->zstate[zno]; 27394a5fc1c6SDamien Le Moal if (lba >= zsp->z_start + zsp->z_size) 27404a5fc1c6SDamien Le Moal zsp++; 27414a5fc1c6SDamien Le Moal WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size); 27424a5fc1c6SDamien Le Moal return zsp; 2743f0d1cf93SDouglas Gilbert } 2744f0d1cf93SDouglas Gilbert 2745f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2746f0d1cf93SDouglas Gilbert { 274735dbe2b9SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_CNV; 2748f0d1cf93SDouglas Gilbert } 2749f0d1cf93SDouglas Gilbert 27504a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp) 27514a5fc1c6SDamien Le Moal { 27524a5fc1c6SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_GAP; 27534a5fc1c6SDamien Le Moal } 27544a5fc1c6SDamien Le Moal 27554a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp) 27564a5fc1c6SDamien Le Moal { 27574a5fc1c6SDamien Le Moal return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp); 27584a5fc1c6SDamien Le Moal } 27594a5fc1c6SDamien Le Moal 2760f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2761f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2762f0d1cf93SDouglas Gilbert { 2763f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2764f0d1cf93SDouglas Gilbert 27654a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2766f0d1cf93SDouglas Gilbert return; 2767f0d1cf93SDouglas Gilbert 2768f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2769f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2770f0d1cf93SDouglas Gilbert return; 2771f0d1cf93SDouglas Gilbert 2772f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2773f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2774f0d1cf93SDouglas Gilbert else 2775f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2776f0d1cf93SDouglas Gilbert 2777f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2778f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2779f0d1cf93SDouglas Gilbert } else { 2780f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2781f0d1cf93SDouglas Gilbert devip->nr_closed++; 2782f0d1cf93SDouglas Gilbert } 2783f0d1cf93SDouglas Gilbert } 2784f0d1cf93SDouglas Gilbert 2785f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2786f0d1cf93SDouglas Gilbert { 2787f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2788f0d1cf93SDouglas Gilbert unsigned int i; 2789f0d1cf93SDouglas Gilbert 2790f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2791f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2792f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2793f0d1cf93SDouglas Gilbert return; 2794f0d1cf93SDouglas Gilbert } 2795f0d1cf93SDouglas Gilbert } 2796f0d1cf93SDouglas Gilbert } 2797f0d1cf93SDouglas Gilbert 2798f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2799f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2800f0d1cf93SDouglas Gilbert { 2801f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2802f0d1cf93SDouglas Gilbert 28034a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2804f0d1cf93SDouglas Gilbert return; 2805f0d1cf93SDouglas Gilbert 2806f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2807f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2808f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2809f0d1cf93SDouglas Gilbert return; 2810f0d1cf93SDouglas Gilbert 2811f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2812f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2813f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2814f0d1cf93SDouglas Gilbert else if (devip->max_open && 2815f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2816f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2817f0d1cf93SDouglas Gilbert 2818f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2819f0d1cf93SDouglas Gilbert devip->nr_closed--; 2820f0d1cf93SDouglas Gilbert if (explicit) { 2821f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2822f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2823f0d1cf93SDouglas Gilbert } else { 2824f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2825f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2826f0d1cf93SDouglas Gilbert } 2827f0d1cf93SDouglas Gilbert } 2828f0d1cf93SDouglas Gilbert 2829566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip, 2830566d3c57SDamien Le Moal struct sdeb_zone_state *zsp) 2831566d3c57SDamien Le Moal { 2832566d3c57SDamien Le Moal switch (zsp->z_cond) { 2833566d3c57SDamien Le Moal case ZC2_IMPLICIT_OPEN: 2834566d3c57SDamien Le Moal devip->nr_imp_open--; 2835566d3c57SDamien Le Moal break; 2836566d3c57SDamien Le Moal case ZC3_EXPLICIT_OPEN: 2837566d3c57SDamien Le Moal devip->nr_exp_open--; 2838566d3c57SDamien Le Moal break; 2839566d3c57SDamien Le Moal default: 2840566d3c57SDamien Le Moal WARN_ONCE(true, "Invalid zone %llu condition %x\n", 2841566d3c57SDamien Le Moal zsp->z_start, zsp->z_cond); 2842566d3c57SDamien Le Moal break; 2843566d3c57SDamien Le Moal } 2844566d3c57SDamien Le Moal zsp->z_cond = ZC5_FULL; 2845566d3c57SDamien Le Moal } 2846566d3c57SDamien Le Moal 2847f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2848f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2849f0d1cf93SDouglas Gilbert { 2850f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 285164e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2852f0d1cf93SDouglas Gilbert 28534a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2854f0d1cf93SDouglas Gilbert return; 2855f0d1cf93SDouglas Gilbert 285635dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2857f0d1cf93SDouglas Gilbert zsp->z_wp += num; 285864e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2859566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 286064e14eceSDamien Le Moal return; 286164e14eceSDamien Le Moal } 286264e14eceSDamien Le Moal 286364e14eceSDamien Le Moal while (num) { 286464e14eceSDamien Le Moal if (lba != zsp->z_wp) 286564e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 286664e14eceSDamien Le Moal 286764e14eceSDamien Le Moal end = lba + num; 286864e14eceSDamien Le Moal if (end >= zend) { 286964e14eceSDamien Le Moal n = zend - lba; 287064e14eceSDamien Le Moal zsp->z_wp = zend; 287164e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 287264e14eceSDamien Le Moal n = num; 287364e14eceSDamien Le Moal zsp->z_wp = end; 287464e14eceSDamien Le Moal } else { 287564e14eceSDamien Le Moal n = num; 287664e14eceSDamien Le Moal } 287764e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2878566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 287964e14eceSDamien Le Moal 288064e14eceSDamien Le Moal num -= n; 288164e14eceSDamien Le Moal lba += n; 288264e14eceSDamien Le Moal if (num) { 288364e14eceSDamien Le Moal zsp++; 288464e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 288564e14eceSDamien Le Moal } 288664e14eceSDamien Le Moal } 2887f0d1cf93SDouglas Gilbert } 2888f0d1cf93SDouglas Gilbert 2889f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 28909447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 28911da177e4SLinus Torvalds { 2892f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2893f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2894f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2895f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2896f0d1cf93SDouglas Gilbert 2897f0d1cf93SDouglas Gilbert if (!write) { 289864e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 289964e14eceSDamien Le Moal return 0; 290064e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 29014a5fc1c6SDamien Le Moal if (zsp->z_type != zsp_end->z_type) { 2902f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2903f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2904f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2905f0d1cf93SDouglas Gilbert return check_condition_result; 2906f0d1cf93SDouglas Gilbert } 2907f0d1cf93SDouglas Gilbert return 0; 2908f0d1cf93SDouglas Gilbert } 2909f0d1cf93SDouglas Gilbert 29104a5fc1c6SDamien Le Moal /* Writing into a gap zone is not allowed */ 29114a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) { 29124a5fc1c6SDamien Le Moal mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 29134a5fc1c6SDamien Le Moal ATTEMPT_ACCESS_GAP); 29144a5fc1c6SDamien Le Moal return check_condition_result; 29154a5fc1c6SDamien Le Moal } 29164a5fc1c6SDamien Le Moal 2917f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2918f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2919f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2920f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2921f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2922f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2923f0d1cf93SDouglas Gilbert return check_condition_result; 2924f0d1cf93SDouglas Gilbert } 2925f0d1cf93SDouglas Gilbert return 0; 2926f0d1cf93SDouglas Gilbert } 2927f0d1cf93SDouglas Gilbert 292835dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2929f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2930f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2931f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2932f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2933f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2934f0d1cf93SDouglas Gilbert return check_condition_result; 2935f0d1cf93SDouglas Gilbert } 2936f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2937f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2938f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2939f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2940f0d1cf93SDouglas Gilbert return check_condition_result; 2941f0d1cf93SDouglas Gilbert } 2942f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2943f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2944f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2945f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2946f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2947f0d1cf93SDouglas Gilbert return check_condition_result; 2948f0d1cf93SDouglas Gilbert } 294964e14eceSDamien Le Moal } 2950f0d1cf93SDouglas Gilbert 2951f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2952f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2953f0d1cf93SDouglas Gilbert if (devip->max_open && 2954f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2955f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2956f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2957f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2958f0d1cf93SDouglas Gilbert return check_condition_result; 2959f0d1cf93SDouglas Gilbert } 2960f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2961f0d1cf93SDouglas Gilbert } 2962f0d1cf93SDouglas Gilbert 2963f0d1cf93SDouglas Gilbert return 0; 2964f0d1cf93SDouglas Gilbert } 2965f0d1cf93SDouglas Gilbert 2966f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2967f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2968f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2969f0d1cf93SDouglas Gilbert { 2970f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2971f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2972f0d1cf93SDouglas Gilbert 2973c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 297422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 29751da177e4SLinus Torvalds return check_condition_result; 29761da177e4SLinus Torvalds } 2977c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2978c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 297922017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2980cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2981c65b1445SDouglas Gilbert return check_condition_result; 2982c65b1445SDouglas Gilbert } 29839447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 29849447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 29859447b6ceSMartin K. Petersen return check_condition_result; 29869447b6ceSMartin K. Petersen } 2987f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2988f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2989f0d1cf93SDouglas Gilbert 299019789100SFUJITA Tomonori return 0; 299119789100SFUJITA Tomonori } 299219789100SFUJITA Tomonori 2993b6ff8ca7SDouglas Gilbert /* 2994b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 2995b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 2996b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 2997b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 2998b6ff8ca7SDouglas Gilbert */ 2999b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 3000b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 300187c715dcSDouglas Gilbert { 3002b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 3003b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 3004b6ff8ca7SDouglas Gilbert return NULL; 3005b6ff8ca7SDouglas Gilbert } 3006b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 300787c715dcSDouglas Gilbert } 300887c715dcSDouglas Gilbert 3009a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 301087c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 301187c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 301219789100SFUJITA Tomonori { 301319789100SFUJITA Tomonori int ret; 3014c2248fc9SDouglas Gilbert u64 block, rest = 0; 3015a4517511SAkinobu Mita enum dma_data_direction dir; 301687c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 301787c715dcSDouglas Gilbert u8 *fsp; 301819789100SFUJITA Tomonori 3019c2248fc9SDouglas Gilbert if (do_write) { 3020a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 30214f2c8bf6SDouglas Gilbert write_since_sync = true; 3022a4517511SAkinobu Mita } else { 3023a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 3024a4517511SAkinobu Mita } 3025a4517511SAkinobu Mita 302687c715dcSDouglas Gilbert if (!sdb->length || !sip) 3027a4517511SAkinobu Mita return 0; 302887c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 3029a4517511SAkinobu Mita return -1; 303087c715dcSDouglas Gilbert fsp = sip->storep; 303119789100SFUJITA Tomonori 303219789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 303319789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 303419789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 303519789100SFUJITA Tomonori 3036386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 303787c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 30380a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 3039773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 3040a4517511SAkinobu Mita return ret; 3041a4517511SAkinobu Mita 3042a4517511SAkinobu Mita if (rest) { 3043386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 304487c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 30450a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 30460a7e69c7SDouglas Gilbert do_write); 3047a4517511SAkinobu Mita } 304819789100SFUJITA Tomonori 304919789100SFUJITA Tomonori return ret; 305019789100SFUJITA Tomonori } 305119789100SFUJITA Tomonori 305287c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 305387c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 305487c715dcSDouglas Gilbert { 305587c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 305687c715dcSDouglas Gilbert 305787c715dcSDouglas Gilbert if (!sdb->length) 305887c715dcSDouglas Gilbert return 0; 305987c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 306087c715dcSDouglas Gilbert return -1; 306187c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 306287c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 306387c715dcSDouglas Gilbert } 306487c715dcSDouglas Gilbert 306587c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 306687c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 306738d5c833SDouglas Gilbert * return false. */ 306887c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 3069c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 307038d5c833SDouglas Gilbert { 307138d5c833SDouglas Gilbert bool res; 307238d5c833SDouglas Gilbert u64 block, rest = 0; 307338d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 3074773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 307587c715dcSDouglas Gilbert u8 *fsp = sip->storep; 307638d5c833SDouglas Gilbert 307738d5c833SDouglas Gilbert block = do_div(lba, store_blks); 307838d5c833SDouglas Gilbert if (block + num > store_blks) 307938d5c833SDouglas Gilbert rest = block + num - store_blks; 308038d5c833SDouglas Gilbert 308187c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 308238d5c833SDouglas Gilbert if (!res) 308338d5c833SDouglas Gilbert return res; 308438d5c833SDouglas Gilbert if (rest) 308587c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 308638d5c833SDouglas Gilbert rest * lb_size); 308738d5c833SDouglas Gilbert if (!res) 308838d5c833SDouglas Gilbert return res; 3089c3e2fe92SDouglas Gilbert if (compare_only) 3090c3e2fe92SDouglas Gilbert return true; 309138d5c833SDouglas Gilbert arr += num * lb_size; 309287c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 309338d5c833SDouglas Gilbert if (rest) 309487c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 309538d5c833SDouglas Gilbert return res; 309638d5c833SDouglas Gilbert } 309738d5c833SDouglas Gilbert 309851d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 3099beb40ea4SAkinobu Mita { 310051d648afSAkinobu Mita __be16 csum; 3101beb40ea4SAkinobu Mita 3102773642d9SDouglas Gilbert if (sdebug_guard) 310351d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 310451d648afSAkinobu Mita else 3105beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 310651d648afSAkinobu Mita 3107beb40ea4SAkinobu Mita return csum; 3108beb40ea4SAkinobu Mita } 3109beb40ea4SAkinobu Mita 31106ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3111beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3112beb40ea4SAkinobu Mita { 3113773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3114beb40ea4SAkinobu Mita 3115beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3116c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3117beb40ea4SAkinobu Mita (unsigned long)sector, 3118beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3119beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3120beb40ea4SAkinobu Mita return 0x01; 3121beb40ea4SAkinobu Mita } 31228475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3123beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3124c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3125c1287970STomas Winkler (unsigned long)sector); 3126beb40ea4SAkinobu Mita return 0x03; 3127beb40ea4SAkinobu Mita } 31288475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3129beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3130c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3131c1287970STomas Winkler (unsigned long)sector); 3132beb40ea4SAkinobu Mita return 0x03; 3133beb40ea4SAkinobu Mita } 3134beb40ea4SAkinobu Mita return 0; 3135beb40ea4SAkinobu Mita } 3136beb40ea4SAkinobu Mita 313787c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 313865f72f2aSAkinobu Mita unsigned int sectors, bool read) 3139c6a44287SMartin K. Petersen { 3140be4e11beSAkinobu Mita size_t resid; 3141c6a44287SMartin K. Petersen void *paddr; 314287c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3143b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 314487c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 314514faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3146be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3147c6a44287SMartin K. Petersen 3148e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3149e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3150c6a44287SMartin K. Petersen 315187c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 315287c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3153be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3154be4e11beSAkinobu Mita 3155be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 315687c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 315787c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3158be4e11beSAkinobu Mita size_t rest = 0; 315914faa944SAkinobu Mita 316014faa944SAkinobu Mita if (dif_store_end < start + len) 316114faa944SAkinobu Mita rest = start + len - dif_store_end; 3162c6a44287SMartin K. Petersen 3163be4e11beSAkinobu Mita paddr = miter.addr; 316414faa944SAkinobu Mita 316565f72f2aSAkinobu Mita if (read) 316665f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 316765f72f2aSAkinobu Mita else 316865f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 316965f72f2aSAkinobu Mita 317065f72f2aSAkinobu Mita if (rest) { 317165f72f2aSAkinobu Mita if (read) 317214faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 317365f72f2aSAkinobu Mita else 317465f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 317565f72f2aSAkinobu Mita } 3176c6a44287SMartin K. Petersen 3177e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3178c6a44287SMartin K. Petersen resid -= len; 3179c6a44287SMartin K. Petersen } 3180be4e11beSAkinobu Mita sg_miter_stop(&miter); 3181bb8c063cSAkinobu Mita } 3182c6a44287SMartin K. Petersen 318387c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3184bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3185bb8c063cSAkinobu Mita { 3186f7be6772SMartin K. Petersen int ret = 0; 3187bb8c063cSAkinobu Mita unsigned int i; 3188bb8c063cSAkinobu Mita sector_t sector; 318987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3190b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 319187c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3192bb8c063cSAkinobu Mita 3193c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3194bb8c063cSAkinobu Mita sector = start_sec + i; 319587c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3196bb8c063cSAkinobu Mita 319751d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3198bb8c063cSAkinobu Mita continue; 3199bb8c063cSAkinobu Mita 3200f7be6772SMartin K. Petersen /* 3201f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3202f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3203f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3204f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3205f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3206f7be6772SMartin K. Petersen */ 3207f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3208f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3209f7be6772SMartin K. Petersen sector, ei_lba); 3210bb8c063cSAkinobu Mita if (ret) { 3211bb8c063cSAkinobu Mita dif_errors++; 3212f7be6772SMartin K. Petersen break; 3213f7be6772SMartin K. Petersen } 3214bb8c063cSAkinobu Mita } 3215bb8c063cSAkinobu Mita } 3216bb8c063cSAkinobu Mita 321787c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3218c6a44287SMartin K. Petersen dix_reads++; 3219c6a44287SMartin K. Petersen 3220f7be6772SMartin K. Petersen return ret; 3221c6a44287SMartin K. Petersen } 3222c6a44287SMartin K. Petersen 32237109f370SDouglas Gilbert static inline void 32247109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip) 32257109f370SDouglas Gilbert { 3226e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3227e9c47801SDamien Le Moal if (sip) 3228e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3229e9c47801SDamien Le Moal else 3230e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3231e9c47801SDamien Le Moal } else { 32327109f370SDouglas Gilbert if (sip) 32337109f370SDouglas Gilbert read_lock(&sip->macc_lck); 32347109f370SDouglas Gilbert else 32357109f370SDouglas Gilbert read_lock(&sdeb_fake_rw_lck); 32367109f370SDouglas Gilbert } 3237e9c47801SDamien Le Moal } 32387109f370SDouglas Gilbert 32397109f370SDouglas Gilbert static inline void 32407109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip) 32417109f370SDouglas Gilbert { 3242e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3243e9c47801SDamien Le Moal if (sip) 3244e9c47801SDamien Le Moal __release(&sip->macc_lck); 3245e9c47801SDamien Le Moal else 3246e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3247e9c47801SDamien Le Moal } else { 32487109f370SDouglas Gilbert if (sip) 32497109f370SDouglas Gilbert read_unlock(&sip->macc_lck); 32507109f370SDouglas Gilbert else 32517109f370SDouglas Gilbert read_unlock(&sdeb_fake_rw_lck); 32527109f370SDouglas Gilbert } 3253e9c47801SDamien Le Moal } 32547109f370SDouglas Gilbert 32557109f370SDouglas Gilbert static inline void 32567109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip) 32577109f370SDouglas Gilbert { 3258e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3259e9c47801SDamien Le Moal if (sip) 3260e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3261e9c47801SDamien Le Moal else 3262e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3263e9c47801SDamien Le Moal } else { 32647109f370SDouglas Gilbert if (sip) 32657109f370SDouglas Gilbert write_lock(&sip->macc_lck); 32667109f370SDouglas Gilbert else 32677109f370SDouglas Gilbert write_lock(&sdeb_fake_rw_lck); 32687109f370SDouglas Gilbert } 3269e9c47801SDamien Le Moal } 32707109f370SDouglas Gilbert 32717109f370SDouglas Gilbert static inline void 32727109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip) 32737109f370SDouglas Gilbert { 3274e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3275e9c47801SDamien Le Moal if (sip) 3276e9c47801SDamien Le Moal __release(&sip->macc_lck); 3277e9c47801SDamien Le Moal else 3278e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3279e9c47801SDamien Le Moal } else { 32807109f370SDouglas Gilbert if (sip) 32817109f370SDouglas Gilbert write_unlock(&sip->macc_lck); 32827109f370SDouglas Gilbert else 32837109f370SDouglas Gilbert write_unlock(&sdeb_fake_rw_lck); 32847109f370SDouglas Gilbert } 3285e9c47801SDamien Le Moal } 32867109f370SDouglas Gilbert 3287fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 328819789100SFUJITA Tomonori { 328987c715dcSDouglas Gilbert bool check_prot; 3290c2248fc9SDouglas Gilbert u32 num; 3291c2248fc9SDouglas Gilbert u32 ei_lba; 329219789100SFUJITA Tomonori int ret; 329387c715dcSDouglas Gilbert u64 lba; 3294b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 329587c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 329619789100SFUJITA Tomonori 3297c2248fc9SDouglas Gilbert switch (cmd[0]) { 3298c2248fc9SDouglas Gilbert case READ_16: 3299c2248fc9SDouglas Gilbert ei_lba = 0; 3300c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3301c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3302c2248fc9SDouglas Gilbert check_prot = true; 3303c2248fc9SDouglas Gilbert break; 3304c2248fc9SDouglas Gilbert case READ_10: 3305c2248fc9SDouglas Gilbert ei_lba = 0; 3306c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3307c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3308c2248fc9SDouglas Gilbert check_prot = true; 3309c2248fc9SDouglas Gilbert break; 3310c2248fc9SDouglas Gilbert case READ_6: 3311c2248fc9SDouglas Gilbert ei_lba = 0; 3312c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3313c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3314c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3315c2248fc9SDouglas Gilbert check_prot = true; 3316c2248fc9SDouglas Gilbert break; 3317c2248fc9SDouglas Gilbert case READ_12: 3318c2248fc9SDouglas Gilbert ei_lba = 0; 3319c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3320c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3321c2248fc9SDouglas Gilbert check_prot = true; 3322c2248fc9SDouglas Gilbert break; 3323c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3324c2248fc9SDouglas Gilbert ei_lba = 0; 3325c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3326c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3327c2248fc9SDouglas Gilbert check_prot = false; 3328c2248fc9SDouglas Gilbert break; 3329c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3330c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3331c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3332c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3333c2248fc9SDouglas Gilbert check_prot = false; 3334c2248fc9SDouglas Gilbert break; 3335c2248fc9SDouglas Gilbert } 3336f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 33378475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3338c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3339c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3340c2248fc9SDouglas Gilbert return check_condition_result; 3341c2248fc9SDouglas Gilbert } 33428475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 33438475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3344c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3345c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3346c2248fc9SDouglas Gilbert "to DIF device\n"); 3347c2248fc9SDouglas Gilbert } 33483a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 33493a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3350c2248fc9SDouglas Gilbert num /= 2; 33513a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3352c2248fc9SDouglas Gilbert } 3353c2248fc9SDouglas Gilbert 33549447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 33559447b6ceSMartin K. Petersen if (ret) 33569447b6ceSMartin K. Petersen return ret; 3357f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3358d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3359d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3360c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3361c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3362c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3363c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3364c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 336532f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 336632f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3367c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3368c65b1445SDouglas Gilbert } 3369c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 33701da177e4SLinus Torvalds return check_condition_result; 33711da177e4SLinus Torvalds } 3372c6a44287SMartin K. Petersen 33737109f370SDouglas Gilbert sdeb_read_lock(sip); 33746c78cc06SAkinobu Mita 3375c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3376f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3377f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3378f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3379f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33807109f370SDouglas Gilbert sdeb_read_unlock(sip); 3381f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3382f7be6772SMartin K. Petersen return check_condition_result; 3383f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 33847109f370SDouglas Gilbert sdeb_read_unlock(sip); 3385f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3386c6a44287SMartin K. Petersen return illegal_condition_result; 3387c6a44287SMartin K. Petersen } 3388f7be6772SMartin K. Petersen break; 3389f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3390f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33917109f370SDouglas Gilbert sdeb_read_unlock(sip); 3392f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3393f7be6772SMartin K. Petersen return check_condition_result; 3394f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 33957109f370SDouglas Gilbert sdeb_read_unlock(sip); 3396f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3397f7be6772SMartin K. Petersen return illegal_condition_result; 3398f7be6772SMartin K. Petersen } 3399f7be6772SMartin K. Petersen break; 3400f7be6772SMartin K. Petersen } 3401c6a44287SMartin K. Petersen } 3402c6a44287SMartin K. Petersen 340387c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 34047109f370SDouglas Gilbert sdeb_read_unlock(sip); 3405f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3406a4517511SAkinobu Mita return DID_ERROR << 16; 3407a4517511SAkinobu Mita 340842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3409a4517511SAkinobu Mita 34103a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 34113a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 34123a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 34133a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 34143a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3415c2248fc9SDouglas Gilbert return check_condition_result; 34163a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3417c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3418c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 34193a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3420c2248fc9SDouglas Gilbert return illegal_condition_result; 34213a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3422c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 34233a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3424c2248fc9SDouglas Gilbert return illegal_condition_result; 3425c2248fc9SDouglas Gilbert } 3426c2248fc9SDouglas Gilbert } 3427a4517511SAkinobu Mita return 0; 34281da177e4SLinus Torvalds } 34291da177e4SLinus Torvalds 3430c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3431395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3432c6a44287SMartin K. Petersen { 3433be4e11beSAkinobu Mita int ret; 34346ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3435be4e11beSAkinobu Mita void *daddr; 343665f72f2aSAkinobu Mita sector_t sector = start_sec; 3437c6a44287SMartin K. Petersen int ppage_offset; 3438be4e11beSAkinobu Mita int dpage_offset; 3439be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3440be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3441c6a44287SMartin K. Petersen 3442c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3443c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3444c6a44287SMartin K. Petersen 3445be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3446be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3447be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3448be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3449be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3450c6a44287SMartin K. Petersen 3451be4e11beSAkinobu Mita /* For each protection page */ 3452be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3453be4e11beSAkinobu Mita dpage_offset = 0; 3454be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3455be4e11beSAkinobu Mita ret = 0x01; 3456be4e11beSAkinobu Mita goto out; 3457c6a44287SMartin K. Petersen } 3458c6a44287SMartin K. Petersen 3459be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 34606ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3461be4e11beSAkinobu Mita /* If we're at the end of the current 3462be4e11beSAkinobu Mita * data page advance to the next one 3463be4e11beSAkinobu Mita */ 3464be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3465be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3466be4e11beSAkinobu Mita ret = 0x01; 3467be4e11beSAkinobu Mita goto out; 3468be4e11beSAkinobu Mita } 3469be4e11beSAkinobu Mita dpage_offset = 0; 3470be4e11beSAkinobu Mita } 3471c6a44287SMartin K. Petersen 3472be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3473be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3474be4e11beSAkinobu Mita 3475f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3476be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3477c78be80dSMartin K. Petersen if (ret) 3478395cef03SMartin K. Petersen goto out; 3479395cef03SMartin K. Petersen } 3480395cef03SMartin K. Petersen 3481c6a44287SMartin K. Petersen sector++; 3482395cef03SMartin K. Petersen ei_lba++; 3483773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3484c6a44287SMartin K. Petersen } 3485be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3486be4e11beSAkinobu Mita sg_miter_stop(&diter); 3487c6a44287SMartin K. Petersen } 3488be4e11beSAkinobu Mita sg_miter_stop(&piter); 3489c6a44287SMartin K. Petersen 349065f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3491c6a44287SMartin K. Petersen dix_writes++; 3492c6a44287SMartin K. Petersen 3493c6a44287SMartin K. Petersen return 0; 3494c6a44287SMartin K. Petersen 3495c6a44287SMartin K. Petersen out: 3496c6a44287SMartin K. Petersen dif_errors++; 3497be4e11beSAkinobu Mita sg_miter_stop(&diter); 3498be4e11beSAkinobu Mita sg_miter_stop(&piter); 3499c6a44287SMartin K. Petersen return ret; 3500c6a44287SMartin K. Petersen } 3501c6a44287SMartin K. Petersen 3502b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3503b90ebc3dSAkinobu Mita { 3504773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3505773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3506773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3507b90ebc3dSAkinobu Mita return lba; 3508b90ebc3dSAkinobu Mita } 3509b90ebc3dSAkinobu Mita 3510b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3511b90ebc3dSAkinobu Mita { 3512773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3513a027b5b9SAkinobu Mita 3514773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3515773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3516a027b5b9SAkinobu Mita return lba; 3517a027b5b9SAkinobu Mita } 3518a027b5b9SAkinobu Mita 351987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 352087c715dcSDouglas Gilbert unsigned int *num) 352144d92694SMartin K. Petersen { 3522b90ebc3dSAkinobu Mita sector_t end; 3523b90ebc3dSAkinobu Mita unsigned int mapped; 3524b90ebc3dSAkinobu Mita unsigned long index; 3525b90ebc3dSAkinobu Mita unsigned long next; 352644d92694SMartin K. Petersen 3527b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 352887c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 352944d92694SMartin K. Petersen 353044d92694SMartin K. Petersen if (mapped) 353187c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 353244d92694SMartin K. Petersen else 353387c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 353444d92694SMartin K. Petersen 3535b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 353644d92694SMartin K. Petersen *num = end - lba; 353744d92694SMartin K. Petersen return mapped; 353844d92694SMartin K. Petersen } 353944d92694SMartin K. Petersen 354087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 354187c715dcSDouglas Gilbert unsigned int len) 354244d92694SMartin K. Petersen { 354344d92694SMartin K. Petersen sector_t end = lba + len; 354444d92694SMartin K. Petersen 354544d92694SMartin K. Petersen while (lba < end) { 3546b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 354744d92694SMartin K. Petersen 3548b90ebc3dSAkinobu Mita if (index < map_size) 354987c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 355044d92694SMartin K. Petersen 3551b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 355244d92694SMartin K. Petersen } 355344d92694SMartin K. Petersen } 355444d92694SMartin K. Petersen 355587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 355687c715dcSDouglas Gilbert unsigned int len) 355744d92694SMartin K. Petersen { 355844d92694SMartin K. Petersen sector_t end = lba + len; 355987c715dcSDouglas Gilbert u8 *fsp = sip->storep; 356044d92694SMartin K. Petersen 356144d92694SMartin K. Petersen while (lba < end) { 3562b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 356344d92694SMartin K. Petersen 3564b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3565773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3566b90ebc3dSAkinobu Mita index < map_size) { 356787c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3568760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 356987c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3570760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3571773642d9SDouglas Gilbert sdebug_sector_size * 3572773642d9SDouglas Gilbert sdebug_unmap_granularity); 3573be1dd78dSEric Sandeen } 357487c715dcSDouglas Gilbert if (sip->dif_storep) { 357587c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 357687c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3577773642d9SDouglas Gilbert sdebug_unmap_granularity); 3578e9926b43SAkinobu Mita } 3579b90ebc3dSAkinobu Mita } 3580b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 358144d92694SMartin K. Petersen } 358244d92694SMartin K. Petersen } 358344d92694SMartin K. Petersen 3584fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 35851da177e4SLinus Torvalds { 358687c715dcSDouglas Gilbert bool check_prot; 3587c2248fc9SDouglas Gilbert u32 num; 3588c2248fc9SDouglas Gilbert u32 ei_lba; 358919789100SFUJITA Tomonori int ret; 359087c715dcSDouglas Gilbert u64 lba; 3591b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 359287c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 35931da177e4SLinus Torvalds 3594c2248fc9SDouglas Gilbert switch (cmd[0]) { 3595c2248fc9SDouglas Gilbert case WRITE_16: 3596c2248fc9SDouglas Gilbert ei_lba = 0; 3597c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3598c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3599c2248fc9SDouglas Gilbert check_prot = true; 3600c2248fc9SDouglas Gilbert break; 3601c2248fc9SDouglas Gilbert case WRITE_10: 3602c2248fc9SDouglas Gilbert ei_lba = 0; 3603c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3604c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3605c2248fc9SDouglas Gilbert check_prot = true; 3606c2248fc9SDouglas Gilbert break; 3607c2248fc9SDouglas Gilbert case WRITE_6: 3608c2248fc9SDouglas Gilbert ei_lba = 0; 3609c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3610c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3611c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3612c2248fc9SDouglas Gilbert check_prot = true; 3613c2248fc9SDouglas Gilbert break; 3614c2248fc9SDouglas Gilbert case WRITE_12: 3615c2248fc9SDouglas Gilbert ei_lba = 0; 3616c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3617c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3618c2248fc9SDouglas Gilbert check_prot = true; 3619c2248fc9SDouglas Gilbert break; 3620c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3621c2248fc9SDouglas Gilbert ei_lba = 0; 3622c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3623c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3624c2248fc9SDouglas Gilbert check_prot = false; 3625c2248fc9SDouglas Gilbert break; 3626c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3627c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3628c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3629c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3630c2248fc9SDouglas Gilbert check_prot = false; 3631c2248fc9SDouglas Gilbert break; 3632c2248fc9SDouglas Gilbert } 3633f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 36348475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3635c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3636c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3637c2248fc9SDouglas Gilbert return check_condition_result; 3638c2248fc9SDouglas Gilbert } 36398475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 36408475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3641c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3642c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3643c2248fc9SDouglas Gilbert "to DIF device\n"); 3644c2248fc9SDouglas Gilbert } 3645f0d1cf93SDouglas Gilbert 36467109f370SDouglas Gilbert sdeb_write_lock(sip); 3647f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3648f0d1cf93SDouglas Gilbert if (ret) { 36497109f370SDouglas Gilbert sdeb_write_unlock(sip); 3650f0d1cf93SDouglas Gilbert return ret; 3651f0d1cf93SDouglas Gilbert } 36526c78cc06SAkinobu Mita 3653c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3654f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3655f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3656f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3657f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 36587109f370SDouglas Gilbert sdeb_write_unlock(sip); 3659f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3660c6a44287SMartin K. Petersen return illegal_condition_result; 3661f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36627109f370SDouglas Gilbert sdeb_write_unlock(sip); 3663f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3664f7be6772SMartin K. Petersen return check_condition_result; 3665f7be6772SMartin K. Petersen } 3666f7be6772SMartin K. Petersen break; 3667f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3668f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 36697109f370SDouglas Gilbert sdeb_write_unlock(sip); 3670f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3671f7be6772SMartin K. Petersen return illegal_condition_result; 3672f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36737109f370SDouglas Gilbert sdeb_write_unlock(sip); 3674f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3675f7be6772SMartin K. Petersen return check_condition_result; 3676f7be6772SMartin K. Petersen } 3677f7be6772SMartin K. Petersen break; 3678c6a44287SMartin K. Petersen } 3679c6a44287SMartin K. Petersen } 3680c6a44287SMartin K. Petersen 368187c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3682f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 368387c715dcSDouglas Gilbert map_region(sip, lba, num); 3684f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3685f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3686f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 36877109f370SDouglas Gilbert sdeb_write_unlock(sip); 3688f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3689773642d9SDouglas Gilbert return DID_ERROR << 16; 3690c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3691c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3692c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3693cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3694773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 369544d92694SMartin K. Petersen 36963a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 36973a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 36983a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 36993a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 37003a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3701c2248fc9SDouglas Gilbert return check_condition_result; 37023a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3703c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3704c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 37053a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3706c2248fc9SDouglas Gilbert return illegal_condition_result; 37073a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3708c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 37093a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3710c2248fc9SDouglas Gilbert return illegal_condition_result; 3711c2248fc9SDouglas Gilbert } 3712c2248fc9SDouglas Gilbert } 37131da177e4SLinus Torvalds return 0; 37141da177e4SLinus Torvalds } 37151da177e4SLinus Torvalds 3716481b5e5cSDouglas Gilbert /* 3717481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3718481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3719481b5e5cSDouglas Gilbert */ 3720481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3721481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3722481b5e5cSDouglas Gilbert { 3723481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3724481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3725481b5e5cSDouglas Gilbert u8 *up; 3726b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3727481b5e5cSDouglas Gilbert u8 wrprotect; 3728481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3729481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3730481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3731481b5e5cSDouglas Gilbert u32 ei_lba; 3732481b5e5cSDouglas Gilbert u64 lba; 3733481b5e5cSDouglas Gilbert int ret, res; 3734481b5e5cSDouglas Gilbert bool is_16; 3735481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3736481b5e5cSDouglas Gilbert 3737481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3738481b5e5cSDouglas Gilbert is_16 = false; 3739481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3740481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3741481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3742481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3743481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3744481b5e5cSDouglas Gilbert is_16 = true; 3745481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3746481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3747481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3748481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3749481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3750481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3751481b5e5cSDouglas Gilbert wrprotect) { 3752481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3753481b5e5cSDouglas Gilbert return illegal_condition_result; 3754481b5e5cSDouglas Gilbert } 3755481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3756481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3757481b5e5cSDouglas Gilbert wrprotect == 0) 3758481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3759481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3760481b5e5cSDouglas Gilbert } 3761481b5e5cSDouglas Gilbert } 3762481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3763481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3764481b5e5cSDouglas Gilbert if (lbdof == 0) { 3765481b5e5cSDouglas Gilbert if (sdebug_verbose) 3766481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3767481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3768481b5e5cSDouglas Gilbert my_name, __func__); 3769481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3770481b5e5cSDouglas Gilbert return illegal_condition_result; 3771481b5e5cSDouglas Gilbert } 3772481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3773481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3774481b5e5cSDouglas Gilbert if (sdebug_verbose) 3775481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3776481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3777481b5e5cSDouglas Gilbert my_name, __func__); 3778481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3779481b5e5cSDouglas Gilbert return illegal_condition_result; 3780481b5e5cSDouglas Gilbert } 3781216e1797SHarshit Mogalapalli lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN); 3782481b5e5cSDouglas Gilbert if (lrdp == NULL) 3783481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3784481b5e5cSDouglas Gilbert if (sdebug_verbose) 3785481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3786481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3787481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3788481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3789481b5e5cSDouglas Gilbert if (res == -1) { 3790481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3791481b5e5cSDouglas Gilbert goto err_out; 3792481b5e5cSDouglas Gilbert } 3793481b5e5cSDouglas Gilbert 37947109f370SDouglas Gilbert sdeb_write_lock(sip); 3795481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3796481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3797481b5e5cSDouglas Gilbert cum_lb = 0; 3798481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3799481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3800481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3801481b5e5cSDouglas Gilbert if (sdebug_verbose) 3802481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3803481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3804481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3805481b5e5cSDouglas Gilbert if (num == 0) 3806481b5e5cSDouglas Gilbert continue; 38079447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3808481b5e5cSDouglas Gilbert if (ret) 3809481b5e5cSDouglas Gilbert goto err_out_unlock; 3810481b5e5cSDouglas Gilbert num_by = num * lb_size; 3811481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3812481b5e5cSDouglas Gilbert 3813481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3814481b5e5cSDouglas Gilbert if (sdebug_verbose) 3815481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3816481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3817481b5e5cSDouglas Gilbert my_name, __func__); 3818481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3819481b5e5cSDouglas Gilbert 0); 3820481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3821481b5e5cSDouglas Gilbert goto err_out_unlock; 3822481b5e5cSDouglas Gilbert } 3823481b5e5cSDouglas Gilbert 3824481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3825481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3826481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3827481b5e5cSDouglas Gilbert ei_lba); 3828481b5e5cSDouglas Gilbert 3829481b5e5cSDouglas Gilbert if (prot_ret) { 3830481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3831481b5e5cSDouglas Gilbert prot_ret); 3832481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3833481b5e5cSDouglas Gilbert goto err_out_unlock; 3834481b5e5cSDouglas Gilbert } 3835481b5e5cSDouglas Gilbert } 3836481b5e5cSDouglas Gilbert 383787c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3838f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3839f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3840f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3841481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 384287c715dcSDouglas Gilbert map_region(sip, lba, num); 3843481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3844481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3845481b5e5cSDouglas Gilbert goto err_out_unlock; 3846481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3847481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3848481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3849481b5e5cSDouglas Gilbert my_name, num_by, ret); 3850481b5e5cSDouglas Gilbert 38513a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 38523a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 38533a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 38543a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 38553a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 38563a90a63dSDouglas Gilbert ret = check_condition_result; 3857481b5e5cSDouglas Gilbert goto err_out_unlock; 38583a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3859481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 38603a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 38613a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3862481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3863481b5e5cSDouglas Gilbert goto err_out_unlock; 38643a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 38653a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 38663a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3867481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3868481b5e5cSDouglas Gilbert goto err_out_unlock; 3869481b5e5cSDouglas Gilbert } 3870481b5e5cSDouglas Gilbert } 3871481b5e5cSDouglas Gilbert sg_off += num_by; 3872481b5e5cSDouglas Gilbert cum_lb += num; 3873481b5e5cSDouglas Gilbert } 3874481b5e5cSDouglas Gilbert ret = 0; 3875481b5e5cSDouglas Gilbert err_out_unlock: 38767109f370SDouglas Gilbert sdeb_write_unlock(sip); 3877481b5e5cSDouglas Gilbert err_out: 3878481b5e5cSDouglas Gilbert kfree(lrdp); 3879481b5e5cSDouglas Gilbert return ret; 3880481b5e5cSDouglas Gilbert } 3881481b5e5cSDouglas Gilbert 3882fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3883fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 388444d92694SMartin K. Petersen { 3885f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3886f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 388744d92694SMartin K. Petersen unsigned long long i; 388840d07b52SDouglas Gilbert u64 block, lbaa; 388987c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 389087c715dcSDouglas Gilbert int ret; 389187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3892b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 389340d07b52SDouglas Gilbert u8 *fs1p; 389487c715dcSDouglas Gilbert u8 *fsp; 389544d92694SMartin K. Petersen 38967109f370SDouglas Gilbert sdeb_write_lock(sip); 389744d92694SMartin K. Petersen 3898f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3899f0d1cf93SDouglas Gilbert if (ret) { 39007109f370SDouglas Gilbert sdeb_write_unlock(sip); 3901f0d1cf93SDouglas Gilbert return ret; 3902f0d1cf93SDouglas Gilbert } 3903f0d1cf93SDouglas Gilbert 39049ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 390587c715dcSDouglas Gilbert unmap_region(sip, lba, num); 390644d92694SMartin K. Petersen goto out; 390744d92694SMartin K. Petersen } 390840d07b52SDouglas Gilbert lbaa = lba; 390940d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3910c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 391187c715dcSDouglas Gilbert fsp = sip->storep; 391287c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3913c2248fc9SDouglas Gilbert if (ndob) { 391440d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3915c2248fc9SDouglas Gilbert ret = 0; 3916c2248fc9SDouglas Gilbert } else 391740d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 391844d92694SMartin K. Petersen 391944d92694SMartin K. Petersen if (-1 == ret) { 39207109f370SDouglas Gilbert sdeb_write_unlock(sip); 3921773642d9SDouglas Gilbert return DID_ERROR << 16; 392240d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3923c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3924e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 392540d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 392644d92694SMartin K. Petersen 392744d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 392840d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 392940d07b52SDouglas Gilbert lbaa = lba + i; 393040d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 393187c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 393240d07b52SDouglas Gilbert } 39339ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 393487c715dcSDouglas Gilbert map_region(sip, lba, num); 3935f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3936f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3937f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 393844d92694SMartin K. Petersen out: 39397109f370SDouglas Gilbert sdeb_write_unlock(sip); 394044d92694SMartin K. Petersen 394144d92694SMartin K. Petersen return 0; 394244d92694SMartin K. Petersen } 394344d92694SMartin K. Petersen 3944fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3945fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3946c2248fc9SDouglas Gilbert { 3947c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3948c2248fc9SDouglas Gilbert u32 lba; 3949c2248fc9SDouglas Gilbert u16 num; 3950c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3951c2248fc9SDouglas Gilbert bool unmap = false; 3952c2248fc9SDouglas Gilbert 3953c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3954773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3955c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3956c2248fc9SDouglas Gilbert return check_condition_result; 3957c2248fc9SDouglas Gilbert } else 3958c2248fc9SDouglas Gilbert unmap = true; 3959c2248fc9SDouglas Gilbert } 3960c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3961c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3962773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3963c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3964c2248fc9SDouglas Gilbert return check_condition_result; 3965c2248fc9SDouglas Gilbert } 3966c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3967c2248fc9SDouglas Gilbert } 3968c2248fc9SDouglas Gilbert 3969fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3970fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3971c2248fc9SDouglas Gilbert { 3972c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3973c2248fc9SDouglas Gilbert u64 lba; 3974c2248fc9SDouglas Gilbert u32 num; 3975c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3976c2248fc9SDouglas Gilbert bool unmap = false; 3977c2248fc9SDouglas Gilbert bool ndob = false; 3978c2248fc9SDouglas Gilbert 3979c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3980773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3981c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3982c2248fc9SDouglas Gilbert return check_condition_result; 3983c2248fc9SDouglas Gilbert } else 3984c2248fc9SDouglas Gilbert unmap = true; 3985c2248fc9SDouglas Gilbert } 3986c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3987c2248fc9SDouglas Gilbert ndob = true; 3988c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3989c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3990773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3991c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3992c2248fc9SDouglas Gilbert return check_condition_result; 3993c2248fc9SDouglas Gilbert } 3994c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3995c2248fc9SDouglas Gilbert } 3996c2248fc9SDouglas Gilbert 3997acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3998acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3999acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 4000fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 4001fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 4002acafd0b9SEwan D. Milne { 4003acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 4004acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 4005acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 4006acafd0b9SEwan D. Milne u8 mode; 4007acafd0b9SEwan D. Milne 4008acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 4009acafd0b9SEwan D. Milne switch (mode) { 4010acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 4011acafd0b9SEwan D. Milne /* set UAs on this device only */ 4012acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4013acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 4014acafd0b9SEwan D. Milne break; 4015acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 4016acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 4017acafd0b9SEwan D. Milne break; 4018acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 4019acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 4020acafd0b9SEwan D. Milne list_for_each_entry(dp, 4021acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4022acafd0b9SEwan D. Milne dev_list) 4023acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 4024acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 4025acafd0b9SEwan D. Milne if (devip != dp) 4026acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 4027acafd0b9SEwan D. Milne dp->uas_bm); 4028acafd0b9SEwan D. Milne } 4029acafd0b9SEwan D. Milne break; 4030acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 4031acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 4032acafd0b9SEwan D. Milne list_for_each_entry(dp, 4033acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4034acafd0b9SEwan D. Milne dev_list) 4035acafd0b9SEwan D. Milne if (dp->target == sdp->id) 4036acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 4037acafd0b9SEwan D. Milne dp->uas_bm); 4038acafd0b9SEwan D. Milne break; 4039acafd0b9SEwan D. Milne default: 4040acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 4041acafd0b9SEwan D. Milne break; 4042acafd0b9SEwan D. Milne } 4043acafd0b9SEwan D. Milne return 0; 4044acafd0b9SEwan D. Milne } 4045acafd0b9SEwan D. Milne 4046fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 4047fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 404838d5c833SDouglas Gilbert { 404938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 405038d5c833SDouglas Gilbert u8 *arr; 4051b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 405238d5c833SDouglas Gilbert u64 lba; 405338d5c833SDouglas Gilbert u32 dnum; 4054773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 405538d5c833SDouglas Gilbert u8 num; 405638d5c833SDouglas Gilbert int ret; 4057d467d31fSDouglas Gilbert int retval = 0; 405838d5c833SDouglas Gilbert 4059d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 406038d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 406138d5c833SDouglas Gilbert if (0 == num) 406238d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 40638475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 406438d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 406538d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 406638d5c833SDouglas Gilbert return check_condition_result; 406738d5c833SDouglas Gilbert } 40688475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 40698475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 407038d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 407138d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 407238d5c833SDouglas Gilbert "to DIF device\n"); 40739447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 40749447b6ceSMartin K. Petersen if (ret) 40759447b6ceSMartin K. Petersen return ret; 4076d467d31fSDouglas Gilbert dnum = 2 * num; 40776396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 4078d467d31fSDouglas Gilbert if (NULL == arr) { 4079d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4080d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 4081d467d31fSDouglas Gilbert return check_condition_result; 4082d467d31fSDouglas Gilbert } 408338d5c833SDouglas Gilbert 40847109f370SDouglas Gilbert sdeb_write_lock(sip); 408538d5c833SDouglas Gilbert 408687c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 408738d5c833SDouglas Gilbert if (ret == -1) { 4088d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 4089d467d31fSDouglas Gilbert goto cleanup; 4090773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 409138d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 409238d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 409338d5c833SDouglas Gilbert dnum * lb_size, ret); 4094c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 409538d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4096d467d31fSDouglas Gilbert retval = check_condition_result; 4097d467d31fSDouglas Gilbert goto cleanup; 409838d5c833SDouglas Gilbert } 409938d5c833SDouglas Gilbert if (scsi_debug_lbp()) 410087c715dcSDouglas Gilbert map_region(sip, lba, num); 4101d467d31fSDouglas Gilbert cleanup: 41027109f370SDouglas Gilbert sdeb_write_unlock(sip); 4103d467d31fSDouglas Gilbert kfree(arr); 4104d467d31fSDouglas Gilbert return retval; 410538d5c833SDouglas Gilbert } 410638d5c833SDouglas Gilbert 410744d92694SMartin K. Petersen struct unmap_block_desc { 410844d92694SMartin K. Petersen __be64 lba; 410944d92694SMartin K. Petersen __be32 blocks; 411044d92694SMartin K. Petersen __be32 __reserved; 411144d92694SMartin K. Petersen }; 411244d92694SMartin K. Petersen 4113fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 411444d92694SMartin K. Petersen { 411544d92694SMartin K. Petersen unsigned char *buf; 411644d92694SMartin K. Petersen struct unmap_block_desc *desc; 4117b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 411844d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 411944d92694SMartin K. Petersen int ret; 412044d92694SMartin K. Petersen 4121c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 4122c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 4123c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 4124c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 412544d92694SMartin K. Petersen 412644d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 4127773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 4128c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 412944d92694SMartin K. Petersen return check_condition_result; 4130c2248fc9SDouglas Gilbert } 413144d92694SMartin K. Petersen 4132b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 4133c2248fc9SDouglas Gilbert if (!buf) { 4134c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4135c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 4136c2248fc9SDouglas Gilbert return check_condition_result; 4137c2248fc9SDouglas Gilbert } 4138c2248fc9SDouglas Gilbert 4139c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 414044d92694SMartin K. Petersen 414144d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 414244d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 414344d92694SMartin K. Petersen 414444d92694SMartin K. Petersen desc = (void *)&buf[8]; 414544d92694SMartin K. Petersen 41467109f370SDouglas Gilbert sdeb_write_lock(sip); 41476c78cc06SAkinobu Mita 414844d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 414944d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 415044d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 415144d92694SMartin K. Petersen 41529447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 415344d92694SMartin K. Petersen if (ret) 415444d92694SMartin K. Petersen goto out; 415544d92694SMartin K. Petersen 415687c715dcSDouglas Gilbert unmap_region(sip, lba, num); 415744d92694SMartin K. Petersen } 415844d92694SMartin K. Petersen 415944d92694SMartin K. Petersen ret = 0; 416044d92694SMartin K. Petersen 416144d92694SMartin K. Petersen out: 41627109f370SDouglas Gilbert sdeb_write_unlock(sip); 416344d92694SMartin K. Petersen kfree(buf); 416444d92694SMartin K. Petersen 416544d92694SMartin K. Petersen return ret; 416644d92694SMartin K. Petersen } 416744d92694SMartin K. Petersen 416844d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 416944d92694SMartin K. Petersen 4170fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4171fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 417244d92694SMartin K. Petersen { 4173c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4174c2248fc9SDouglas Gilbert u64 lba; 4175c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 417644d92694SMartin K. Petersen int ret; 417787c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 417844d92694SMartin K. Petersen 4179c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4180c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 418144d92694SMartin K. Petersen 418244d92694SMartin K. Petersen if (alloc_len < 24) 418344d92694SMartin K. Petersen return 0; 418444d92694SMartin K. Petersen 41859447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 418644d92694SMartin K. Petersen if (ret) 418744d92694SMartin K. Petersen return ret; 418844d92694SMartin K. Petersen 4189b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4190b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4191b6ff8ca7SDouglas Gilbert 419287c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4193b6ff8ca7SDouglas Gilbert } else { 4194c2248fc9SDouglas Gilbert mapped = 1; 4195c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4196c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4197c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4198c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4199c2248fc9SDouglas Gilbert else 4200c2248fc9SDouglas Gilbert num = 0xffffffff; 4201c2248fc9SDouglas Gilbert } 420244d92694SMartin K. Petersen 420344d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4204c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4205c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4206c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4207c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 420844d92694SMartin K. Petersen 4209c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 421044d92694SMartin K. Petersen } 421144d92694SMartin K. Petersen 421280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 421380c49563SDouglas Gilbert struct sdebug_dev_info *devip) 421480c49563SDouglas Gilbert { 42154f2c8bf6SDouglas Gilbert int res = 0; 421680c49563SDouglas Gilbert u64 lba; 421780c49563SDouglas Gilbert u32 num_blocks; 421880c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 421980c49563SDouglas Gilbert 422080c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 422180c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 422280c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 422380c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 422480c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 422580c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 422680c49563SDouglas Gilbert } 422780c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 422880c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 422980c49563SDouglas Gilbert return check_condition_result; 423080c49563SDouglas Gilbert } 4231fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 42324f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 42334f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 42344f2c8bf6SDouglas Gilbert write_since_sync = false; 42354f2c8bf6SDouglas Gilbert return res; 423680c49563SDouglas Gilbert } 423780c49563SDouglas Gilbert 4238ed9f3e25SDouglas Gilbert /* 4239ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4240ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4241ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4242ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4243ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4244ed9f3e25SDouglas Gilbert */ 4245ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4246ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4247ed9f3e25SDouglas Gilbert { 4248ed9f3e25SDouglas Gilbert int res = 0; 4249ed9f3e25SDouglas Gilbert u64 lba; 4250ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4251ed9f3e25SDouglas Gilbert u32 nblks; 4252ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4253b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4254b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4255ed9f3e25SDouglas Gilbert 4256ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4257ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4258ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4259ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4260ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4261ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4262ed9f3e25SDouglas Gilbert } 4263ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4264ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4265ed9f3e25SDouglas Gilbert return check_condition_result; 4266ed9f3e25SDouglas Gilbert } 4267ed9f3e25SDouglas Gilbert if (!fsp) 4268ed9f3e25SDouglas Gilbert goto fini; 4269ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4270ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4271ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4272ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4273ed9f3e25SDouglas Gilbert 4274ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 42757109f370SDouglas Gilbert sdeb_read_lock(sip); 4276ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4277ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4278ed9f3e25SDouglas Gilbert if (rest) 4279ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 42807109f370SDouglas Gilbert sdeb_read_unlock(sip); 4281ed9f3e25SDouglas Gilbert fini: 4282ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4283ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4284ed9f3e25SDouglas Gilbert return res | condition_met_result; 4285ed9f3e25SDouglas Gilbert } 4286ed9f3e25SDouglas Gilbert 4287fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4288fb0cc8d1SDouglas Gilbert 42898d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 42908d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 42918d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 42928d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 42938d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 42948d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 42958d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 42968d039e22SDouglas Gilbert */ 42971da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 42981da177e4SLinus Torvalds struct sdebug_dev_info *devip) 42991da177e4SLinus Torvalds { 430001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 43018d039e22SDouglas Gilbert unsigned int alloc_len; 43028d039e22SDouglas Gilbert unsigned char select_report; 43038d039e22SDouglas Gilbert u64 lun; 43048d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4305fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 43068d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 43078d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 43088d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 43098d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4310fb0cc8d1SDouglas Gilbert int k, j, n, res; 4311fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4312fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 43131da177e4SLinus Torvalds 431419c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 43158d039e22SDouglas Gilbert 43168d039e22SDouglas Gilbert select_report = cmd[2]; 43178d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 43188d039e22SDouglas Gilbert 43198d039e22SDouglas Gilbert if (alloc_len < 4) { 43208d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 43218d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 43221da177e4SLinus Torvalds return check_condition_result; 43231da177e4SLinus Torvalds } 43248d039e22SDouglas Gilbert 43258d039e22SDouglas Gilbert switch (select_report) { 43268d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4327773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 43288d039e22SDouglas Gilbert wlun_cnt = 0; 43298d039e22SDouglas Gilbert break; 43308d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4331c65b1445SDouglas Gilbert lun_cnt = 0; 43328d039e22SDouglas Gilbert wlun_cnt = 1; 43338d039e22SDouglas Gilbert break; 43348d039e22SDouglas Gilbert case 2: /* all LUNs */ 43358d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 43368d039e22SDouglas Gilbert wlun_cnt = 1; 43378d039e22SDouglas Gilbert break; 43388d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 43398d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 43408d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 43418d039e22SDouglas Gilbert default: 43428d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 43438d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 43448d039e22SDouglas Gilbert return check_condition_result; 43458d039e22SDouglas Gilbert } 43468d039e22SDouglas Gilbert 43478d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4348c65b1445SDouglas Gilbert --lun_cnt; 43498d039e22SDouglas Gilbert 43508d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4351fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4352fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 43538d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 43548d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 43558d039e22SDouglas Gilbert 4356fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 43578d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4358fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4359fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4360fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4361fb0cc8d1SDouglas Gilbert if (k == 0) { 4362fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4363fb0cc8d1SDouglas Gilbert ++lun_p; 4364fb0cc8d1SDouglas Gilbert j = 1; 4365fb0cc8d1SDouglas Gilbert } 4366fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4367fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4368fb0cc8d1SDouglas Gilbert break; 4369fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4370ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4371ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4372fb0cc8d1SDouglas Gilbert } 4373fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4374fb0cc8d1SDouglas Gilbert break; 4375fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4376fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4377fb0cc8d1SDouglas Gilbert if (res) 4378fb0cc8d1SDouglas Gilbert return res; 4379fb0cc8d1SDouglas Gilbert off_rsp += n; 4380fb0cc8d1SDouglas Gilbert } 4381fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4382fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4383fb0cc8d1SDouglas Gilbert ++j; 4384fb0cc8d1SDouglas Gilbert } 4385fb0cc8d1SDouglas Gilbert if (j > 0) 4386fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 43878d039e22SDouglas Gilbert return res; 43881da177e4SLinus Torvalds } 43891da177e4SLinus Torvalds 4390c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4391c3e2fe92SDouglas Gilbert { 4392c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4393c3e2fe92SDouglas Gilbert u8 bytchk; 4394c3e2fe92SDouglas Gilbert int ret, j; 4395c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4396c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4397c3e2fe92SDouglas Gilbert u64 lba; 4398c3e2fe92SDouglas Gilbert u8 *arr; 4399c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4400b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4401c3e2fe92SDouglas Gilbert 4402c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4403c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4404c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4405c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4406c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4407c3e2fe92SDouglas Gilbert return check_condition_result; 4408c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4409c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4410c3e2fe92SDouglas Gilbert } 4411c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4412c3e2fe92SDouglas Gilbert case VERIFY_16: 4413c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4414c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4415c3e2fe92SDouglas Gilbert break; 4416c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4417c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4418c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4419c3e2fe92SDouglas Gilbert break; 4420c3e2fe92SDouglas Gilbert default: 4421c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4422c3e2fe92SDouglas Gilbert return check_condition_result; 4423c3e2fe92SDouglas Gilbert } 44243344b58bSGeorge Kennedy if (vnum == 0) 44253344b58bSGeorge Kennedy return 0; /* not an error */ 4426c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4427c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4428c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4429c3e2fe92SDouglas Gilbert if (ret) 4430c3e2fe92SDouglas Gilbert return ret; 4431c3e2fe92SDouglas Gilbert 4432ed0f17b7SHarshit Mogalapalli arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN); 4433c3e2fe92SDouglas Gilbert if (!arr) { 4434c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4435c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4436c3e2fe92SDouglas Gilbert return check_condition_result; 4437c3e2fe92SDouglas Gilbert } 4438c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 44397109f370SDouglas Gilbert sdeb_read_lock(sip); 4440c3e2fe92SDouglas Gilbert 4441c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4442c3e2fe92SDouglas Gilbert if (ret == -1) { 4443c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4444c3e2fe92SDouglas Gilbert goto cleanup; 4445c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4446c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4447c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4448c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4449c3e2fe92SDouglas Gilbert } 4450c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4451c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4452c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4453c3e2fe92SDouglas Gilbert } 4454c3e2fe92SDouglas Gilbert ret = 0; 4455c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4456c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4457c3e2fe92SDouglas Gilbert ret = check_condition_result; 4458c3e2fe92SDouglas Gilbert goto cleanup; 4459c3e2fe92SDouglas Gilbert } 4460c3e2fe92SDouglas Gilbert cleanup: 44617109f370SDouglas Gilbert sdeb_read_unlock(sip); 4462c3e2fe92SDouglas Gilbert kfree(arr); 4463c3e2fe92SDouglas Gilbert return ret; 4464c3e2fe92SDouglas Gilbert } 4465c3e2fe92SDouglas Gilbert 4466f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4467f0d1cf93SDouglas Gilbert 4468897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */ 4469f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4470f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4471f0d1cf93SDouglas Gilbert { 44724a5fc1c6SDamien Le Moal unsigned int rep_max_zones, nrz = 0; 4473f0d1cf93SDouglas Gilbert int ret = 0; 4474f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4475f0d1cf93SDouglas Gilbert bool partial; 4476f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4477f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4478f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 44794a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp = NULL; 4480b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4481f0d1cf93SDouglas Gilbert 4482f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4483f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4484f0d1cf93SDouglas Gilbert return check_condition_result; 4485f0d1cf93SDouglas Gilbert } 4486f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4487f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 44883344b58bSGeorge Kennedy if (alloc_len == 0) 44893344b58bSGeorge Kennedy return 0; /* not an error */ 4490f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4491f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4492f0d1cf93SDouglas Gilbert 4493f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4494f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4495f0d1cf93SDouglas Gilbert return check_condition_result; 4496f0d1cf93SDouglas Gilbert } 4497f0d1cf93SDouglas Gilbert 44984a5fc1c6SDamien Le Moal rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD); 4499f0d1cf93SDouglas Gilbert 4500*07f2ca13SHarshit Mogalapalli arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN); 4501f0d1cf93SDouglas Gilbert if (!arr) { 4502f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4503f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4504f0d1cf93SDouglas Gilbert return check_condition_result; 4505f0d1cf93SDouglas Gilbert } 4506f0d1cf93SDouglas Gilbert 45077109f370SDouglas Gilbert sdeb_read_lock(sip); 4508f0d1cf93SDouglas Gilbert 4509f0d1cf93SDouglas Gilbert desc = arr + 64; 45104a5fc1c6SDamien Le Moal for (lba = zs_lba; lba < sdebug_capacity; 45114a5fc1c6SDamien Le Moal lba = zsp->z_start + zsp->z_size) { 45124a5fc1c6SDamien Le Moal if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba)) 4513f0d1cf93SDouglas Gilbert break; 4514f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4515f0d1cf93SDouglas Gilbert switch (rep_opts) { 4516f0d1cf93SDouglas Gilbert case 0x00: 4517f0d1cf93SDouglas Gilbert /* All zones */ 4518f0d1cf93SDouglas Gilbert break; 4519f0d1cf93SDouglas Gilbert case 0x01: 4520f0d1cf93SDouglas Gilbert /* Empty zones */ 4521f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4522f0d1cf93SDouglas Gilbert continue; 4523f0d1cf93SDouglas Gilbert break; 4524f0d1cf93SDouglas Gilbert case 0x02: 4525f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4526f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4527f0d1cf93SDouglas Gilbert continue; 4528f0d1cf93SDouglas Gilbert break; 4529f0d1cf93SDouglas Gilbert case 0x03: 4530f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4531f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4532f0d1cf93SDouglas Gilbert continue; 4533f0d1cf93SDouglas Gilbert break; 4534f0d1cf93SDouglas Gilbert case 0x04: 4535f0d1cf93SDouglas Gilbert /* Closed zones */ 4536f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4537f0d1cf93SDouglas Gilbert continue; 4538f0d1cf93SDouglas Gilbert break; 4539f0d1cf93SDouglas Gilbert case 0x05: 4540f0d1cf93SDouglas Gilbert /* Full zones */ 4541f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4542f0d1cf93SDouglas Gilbert continue; 4543f0d1cf93SDouglas Gilbert break; 4544f0d1cf93SDouglas Gilbert case 0x06: 4545f0d1cf93SDouglas Gilbert case 0x07: 4546f0d1cf93SDouglas Gilbert case 0x10: 4547f0d1cf93SDouglas Gilbert /* 454864e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 454964e14eceSDamien Le Moal * not emulated: no zones to report; 4550f0d1cf93SDouglas Gilbert */ 4551f0d1cf93SDouglas Gilbert continue; 455264e14eceSDamien Le Moal case 0x11: 455364e14eceSDamien Le Moal /* non-seq-resource set */ 455464e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 455564e14eceSDamien Le Moal continue; 455664e14eceSDamien Le Moal break; 45574a5fc1c6SDamien Le Moal case 0x3e: 45584a5fc1c6SDamien Le Moal /* All zones except gap zones. */ 45594a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) 45604a5fc1c6SDamien Le Moal continue; 45614a5fc1c6SDamien Le Moal break; 4562f0d1cf93SDouglas Gilbert case 0x3f: 4563f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 45644a5fc1c6SDamien Le Moal if (zbc_zone_is_seq(zsp)) 4565f0d1cf93SDouglas Gilbert continue; 4566f0d1cf93SDouglas Gilbert break; 4567f0d1cf93SDouglas Gilbert default: 4568f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4569f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4570f0d1cf93SDouglas Gilbert ret = check_condition_result; 4571f0d1cf93SDouglas Gilbert goto fini; 4572f0d1cf93SDouglas Gilbert } 4573f0d1cf93SDouglas Gilbert 4574f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4575f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 457664e14eceSDamien Le Moal desc[0] = zsp->z_type; 4577f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 457864e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 457964e14eceSDamien Le Moal desc[1] |= 1 << 1; 4580f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4581f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4582f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4583f0d1cf93SDouglas Gilbert desc += 64; 4584f0d1cf93SDouglas Gilbert } 4585f0d1cf93SDouglas Gilbert 4586f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4587f0d1cf93SDouglas Gilbert break; 4588f0d1cf93SDouglas Gilbert 4589f0d1cf93SDouglas Gilbert nrz++; 4590f0d1cf93SDouglas Gilbert } 4591f0d1cf93SDouglas Gilbert 4592f0d1cf93SDouglas Gilbert /* Report header */ 45934a5fc1c6SDamien Le Moal /* Zone list length. */ 4594f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 45954a5fc1c6SDamien Le Moal /* Maximum LBA */ 4596f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 45974a5fc1c6SDamien Le Moal /* Zone starting LBA granularity. */ 45984a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 45994a5fc1c6SDamien Le Moal put_unaligned_be64(devip->zsize, arr + 16); 4600f0d1cf93SDouglas Gilbert 4601f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 460236e07d7eSGeorge Kennedy ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)); 4603f0d1cf93SDouglas Gilbert 4604f0d1cf93SDouglas Gilbert fini: 46057109f370SDouglas Gilbert sdeb_read_unlock(sip); 4606f0d1cf93SDouglas Gilbert kfree(arr); 4607f0d1cf93SDouglas Gilbert return ret; 4608f0d1cf93SDouglas Gilbert } 4609f0d1cf93SDouglas Gilbert 4610f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4611f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4612f0d1cf93SDouglas Gilbert { 4613f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4614f0d1cf93SDouglas Gilbert unsigned int i; 4615f0d1cf93SDouglas Gilbert 4616f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4617f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4618f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4619f0d1cf93SDouglas Gilbert } 4620f0d1cf93SDouglas Gilbert } 4621f0d1cf93SDouglas Gilbert 4622f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4623f0d1cf93SDouglas Gilbert { 4624f0d1cf93SDouglas Gilbert int res = 0; 4625f0d1cf93SDouglas Gilbert u64 z_id; 4626f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4627f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4628f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4629f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4630b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4631f0d1cf93SDouglas Gilbert 4632f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4633f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4634f0d1cf93SDouglas Gilbert return check_condition_result; 4635f0d1cf93SDouglas Gilbert } 4636f0d1cf93SDouglas Gilbert 46377109f370SDouglas Gilbert sdeb_write_lock(sip); 4638f0d1cf93SDouglas Gilbert 4639f0d1cf93SDouglas Gilbert if (all) { 4640f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4641f0d1cf93SDouglas Gilbert if (devip->max_open && 4642f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4643f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4644f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4645f0d1cf93SDouglas Gilbert res = check_condition_result; 4646f0d1cf93SDouglas Gilbert goto fini; 4647f0d1cf93SDouglas Gilbert } 4648f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4649f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4650f0d1cf93SDouglas Gilbert goto fini; 4651f0d1cf93SDouglas Gilbert } 4652f0d1cf93SDouglas Gilbert 4653f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4654f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4655f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4656f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4657f0d1cf93SDouglas Gilbert res = check_condition_result; 4658f0d1cf93SDouglas Gilbert goto fini; 4659f0d1cf93SDouglas Gilbert } 4660f0d1cf93SDouglas Gilbert 4661f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4662f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4663f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4664f0d1cf93SDouglas Gilbert res = check_condition_result; 4665f0d1cf93SDouglas Gilbert goto fini; 4666f0d1cf93SDouglas Gilbert } 4667f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4668f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4669f0d1cf93SDouglas Gilbert res = check_condition_result; 4670f0d1cf93SDouglas Gilbert goto fini; 4671f0d1cf93SDouglas Gilbert } 4672f0d1cf93SDouglas Gilbert 4673f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4674f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4675f0d1cf93SDouglas Gilbert goto fini; 4676f0d1cf93SDouglas Gilbert 4677f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4678f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4679f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4680f0d1cf93SDouglas Gilbert res = check_condition_result; 4681f0d1cf93SDouglas Gilbert goto fini; 4682f0d1cf93SDouglas Gilbert } 4683f0d1cf93SDouglas Gilbert 4684f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4685f0d1cf93SDouglas Gilbert fini: 46867109f370SDouglas Gilbert sdeb_write_unlock(sip); 4687f0d1cf93SDouglas Gilbert return res; 4688f0d1cf93SDouglas Gilbert } 4689f0d1cf93SDouglas Gilbert 4690f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4691f0d1cf93SDouglas Gilbert { 4692f0d1cf93SDouglas Gilbert unsigned int i; 4693f0d1cf93SDouglas Gilbert 4694f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4695f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4696f0d1cf93SDouglas Gilbert } 4697f0d1cf93SDouglas Gilbert 4698f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4699f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4700f0d1cf93SDouglas Gilbert { 4701f0d1cf93SDouglas Gilbert int res = 0; 4702f0d1cf93SDouglas Gilbert u64 z_id; 4703f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4704f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4705f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4706b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4707f0d1cf93SDouglas Gilbert 4708f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4709f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4710f0d1cf93SDouglas Gilbert return check_condition_result; 4711f0d1cf93SDouglas Gilbert } 4712f0d1cf93SDouglas Gilbert 47137109f370SDouglas Gilbert sdeb_write_lock(sip); 4714f0d1cf93SDouglas Gilbert 4715f0d1cf93SDouglas Gilbert if (all) { 4716f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4717f0d1cf93SDouglas Gilbert goto fini; 4718f0d1cf93SDouglas Gilbert } 4719f0d1cf93SDouglas Gilbert 4720f0d1cf93SDouglas Gilbert /* Close specified zone */ 4721f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4722f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4723f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4724f0d1cf93SDouglas Gilbert res = check_condition_result; 4725f0d1cf93SDouglas Gilbert goto fini; 4726f0d1cf93SDouglas Gilbert } 4727f0d1cf93SDouglas Gilbert 4728f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4729f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4730f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4731f0d1cf93SDouglas Gilbert res = check_condition_result; 4732f0d1cf93SDouglas Gilbert goto fini; 4733f0d1cf93SDouglas Gilbert } 4734f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4735f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4736f0d1cf93SDouglas Gilbert res = check_condition_result; 4737f0d1cf93SDouglas Gilbert goto fini; 4738f0d1cf93SDouglas Gilbert } 4739f0d1cf93SDouglas Gilbert 4740f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4741f0d1cf93SDouglas Gilbert fini: 47427109f370SDouglas Gilbert sdeb_write_unlock(sip); 4743f0d1cf93SDouglas Gilbert return res; 4744f0d1cf93SDouglas Gilbert } 4745f0d1cf93SDouglas Gilbert 4746f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4747f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4748f0d1cf93SDouglas Gilbert { 4749f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4750f0d1cf93SDouglas Gilbert 4751f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4752f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4753f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4754f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4755f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4756f0d1cf93SDouglas Gilbert devip->nr_closed--; 4757f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4758f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4759f0d1cf93SDouglas Gilbert } 4760f0d1cf93SDouglas Gilbert } 4761f0d1cf93SDouglas Gilbert 4762f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4763f0d1cf93SDouglas Gilbert { 4764f0d1cf93SDouglas Gilbert unsigned int i; 4765f0d1cf93SDouglas Gilbert 4766f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4767f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4768f0d1cf93SDouglas Gilbert } 4769f0d1cf93SDouglas Gilbert 4770f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4771f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4772f0d1cf93SDouglas Gilbert { 4773f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4774f0d1cf93SDouglas Gilbert int res = 0; 4775f0d1cf93SDouglas Gilbert u64 z_id; 4776f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4777f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4778b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4779f0d1cf93SDouglas Gilbert 4780f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4781f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4782f0d1cf93SDouglas Gilbert return check_condition_result; 4783f0d1cf93SDouglas Gilbert } 4784f0d1cf93SDouglas Gilbert 47857109f370SDouglas Gilbert sdeb_write_lock(sip); 4786f0d1cf93SDouglas Gilbert 4787f0d1cf93SDouglas Gilbert if (all) { 4788f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4789f0d1cf93SDouglas Gilbert goto fini; 4790f0d1cf93SDouglas Gilbert } 4791f0d1cf93SDouglas Gilbert 4792f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4793f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4794f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4795f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4796f0d1cf93SDouglas Gilbert res = check_condition_result; 4797f0d1cf93SDouglas Gilbert goto fini; 4798f0d1cf93SDouglas Gilbert } 4799f0d1cf93SDouglas Gilbert 4800f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4801f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4802f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4803f0d1cf93SDouglas Gilbert res = check_condition_result; 4804f0d1cf93SDouglas Gilbert goto fini; 4805f0d1cf93SDouglas Gilbert } 4806f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4807f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4808f0d1cf93SDouglas Gilbert res = check_condition_result; 4809f0d1cf93SDouglas Gilbert goto fini; 4810f0d1cf93SDouglas Gilbert } 4811f0d1cf93SDouglas Gilbert 4812f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4813f0d1cf93SDouglas Gilbert fini: 48147109f370SDouglas Gilbert sdeb_write_unlock(sip); 4815f0d1cf93SDouglas Gilbert return res; 4816f0d1cf93SDouglas Gilbert } 4817f0d1cf93SDouglas Gilbert 4818f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4819f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4820f0d1cf93SDouglas Gilbert { 4821f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 48222d62253eSShin'ichiro Kawasaki struct sdeb_store_info *sip = devip2sip(devip, false); 4823f0d1cf93SDouglas Gilbert 48244a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 4825f0d1cf93SDouglas Gilbert return; 4826f0d1cf93SDouglas Gilbert 4827f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4828f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4829f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4830f0d1cf93SDouglas Gilbert 4831f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4832f0d1cf93SDouglas Gilbert devip->nr_closed--; 4833f0d1cf93SDouglas Gilbert 48342d62253eSShin'ichiro Kawasaki if (zsp->z_wp > zsp->z_start) 48352d62253eSShin'ichiro Kawasaki memset(sip->storep + zsp->z_start * sdebug_sector_size, 0, 48362d62253eSShin'ichiro Kawasaki (zsp->z_wp - zsp->z_start) * sdebug_sector_size); 48372d62253eSShin'ichiro Kawasaki 483864e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4839f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4840f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4841f0d1cf93SDouglas Gilbert } 4842f0d1cf93SDouglas Gilbert 4843f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4844f0d1cf93SDouglas Gilbert { 4845f0d1cf93SDouglas Gilbert unsigned int i; 4846f0d1cf93SDouglas Gilbert 4847f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4848f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4849f0d1cf93SDouglas Gilbert } 4850f0d1cf93SDouglas Gilbert 4851f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4852f0d1cf93SDouglas Gilbert { 4853f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4854f0d1cf93SDouglas Gilbert int res = 0; 4855f0d1cf93SDouglas Gilbert u64 z_id; 4856f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4857f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4858b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4859f0d1cf93SDouglas Gilbert 4860f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4861f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4862f0d1cf93SDouglas Gilbert return check_condition_result; 4863f0d1cf93SDouglas Gilbert } 4864f0d1cf93SDouglas Gilbert 48657109f370SDouglas Gilbert sdeb_write_lock(sip); 4866f0d1cf93SDouglas Gilbert 4867f0d1cf93SDouglas Gilbert if (all) { 4868f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4869f0d1cf93SDouglas Gilbert goto fini; 4870f0d1cf93SDouglas Gilbert } 4871f0d1cf93SDouglas Gilbert 4872f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4873f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4874f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4875f0d1cf93SDouglas Gilbert res = check_condition_result; 4876f0d1cf93SDouglas Gilbert goto fini; 4877f0d1cf93SDouglas Gilbert } 4878f0d1cf93SDouglas Gilbert 4879f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4880f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4881f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4882f0d1cf93SDouglas Gilbert res = check_condition_result; 4883f0d1cf93SDouglas Gilbert goto fini; 4884f0d1cf93SDouglas Gilbert } 4885f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4886f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4887f0d1cf93SDouglas Gilbert res = check_condition_result; 4888f0d1cf93SDouglas Gilbert goto fini; 4889f0d1cf93SDouglas Gilbert } 4890f0d1cf93SDouglas Gilbert 4891f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4892f0d1cf93SDouglas Gilbert fini: 48937109f370SDouglas Gilbert sdeb_write_unlock(sip); 4894f0d1cf93SDouglas Gilbert return res; 4895f0d1cf93SDouglas Gilbert } 4896f0d1cf93SDouglas Gilbert 4897c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4898c4837394SDouglas Gilbert { 4899c10fa55fSJohn Garry u16 hwq; 4900a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4901c10fa55fSJohn Garry 4902c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4903c4837394SDouglas Gilbert 4904458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4905458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4906458df78bSBart Van Assche hwq = 0; 4907f7c4cdc7SJohn Garry 4908458df78bSBart Van Assche return sdebug_q_arr + hwq; 4909c4837394SDouglas Gilbert } 4910c4837394SDouglas Gilbert 4911c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4912c10fa55fSJohn Garry { 4913a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4914c10fa55fSJohn Garry } 4915c10fa55fSJohn Garry 4916c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4917fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 49181da177e4SLinus Torvalds { 49197382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4920c4837394SDouglas Gilbert int qc_idx; 4921cbf67842SDouglas Gilbert int retiring = 0; 49221da177e4SLinus Torvalds unsigned long iflags; 4923c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4924cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4925cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4926cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 49271da177e4SLinus Torvalds 49287382f9d8SDouglas Gilbert if (unlikely(aborted)) 49297382f9d8SDouglas Gilbert sd_dp->aborted = false; 4930c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4931c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4932c4837394SDouglas Gilbert if (sdebug_statistics) { 4933cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4934c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4935c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4936c4837394SDouglas Gilbert } 4937c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4938c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 49391da177e4SLinus Torvalds return; 49401da177e4SLinus Torvalds } 4941c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4942d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 4943c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4944cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4945b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4946c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4947c10fa55fSJohn Garry pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n", 4948c10fa55fSJohn Garry sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx); 49491da177e4SLinus Torvalds return; 49501da177e4SLinus Torvalds } 4951cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4952f46eb0e9SDouglas Gilbert if (likely(devip)) 4953cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4954cbf67842SDouglas Gilbert else 4955c1287970STomas Winkler pr_err("devip=NULL\n"); 4956f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4957cbf67842SDouglas Gilbert retiring = 1; 4958cbf67842SDouglas Gilbert 4959cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4960c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4961c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4962c1287970STomas Winkler pr_err("Unexpected completion\n"); 4963cbf67842SDouglas Gilbert return; 49641da177e4SLinus Torvalds } 49651da177e4SLinus Torvalds 4966cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4967cbf67842SDouglas Gilbert int k, retval; 4968cbf67842SDouglas Gilbert 4969cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4970c4837394SDouglas Gilbert if (qc_idx >= retval) { 4971c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4972c1287970STomas Winkler pr_err("index %d too large\n", retval); 4973cbf67842SDouglas Gilbert return; 4974cbf67842SDouglas Gilbert } 4975c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4976773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4977cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4978cbf67842SDouglas Gilbert else 4979cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4980cbf67842SDouglas Gilbert } 4981c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 49827382f9d8SDouglas Gilbert if (unlikely(aborted)) { 49837382f9d8SDouglas Gilbert if (sdebug_verbose) 49847382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 49857382f9d8SDouglas Gilbert return; 49867382f9d8SDouglas Gilbert } 49876c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 4988cbf67842SDouglas Gilbert } 4989cbf67842SDouglas Gilbert 4990cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4991fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4992cbf67842SDouglas Gilbert { 4993a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4994a10bc12aSDouglas Gilbert hrt); 4995a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4996cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4997cbf67842SDouglas Gilbert } 49981da177e4SLinus Torvalds 4999a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 5000fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 5001a10bc12aSDouglas Gilbert { 5002a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 5003a10bc12aSDouglas Gilbert ew.work); 5004a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 5005a10bc12aSDouglas Gilbert } 5006a10bc12aSDouglas Gilbert 500709ba24c1SDouglas Gilbert static bool got_shared_uuid; 5008bf476433SChristoph Hellwig static uuid_t shared_uuid; 500909ba24c1SDouglas Gilbert 5010f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 5011f0d1cf93SDouglas Gilbert { 5012f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 5013f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 50144a5fc1c6SDamien Le Moal sector_t conv_capacity; 5015f0d1cf93SDouglas Gilbert sector_t zstart = 0; 5016f0d1cf93SDouglas Gilbert unsigned int i; 5017f0d1cf93SDouglas Gilbert 5018f0d1cf93SDouglas Gilbert /* 501998e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 502098e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 5021f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 5022f0d1cf93SDouglas Gilbert * created for the device. 5023f0d1cf93SDouglas Gilbert */ 502498e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 5025f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 5026f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5027f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 5028f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 5029f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 5030f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 5031f0d1cf93SDouglas Gilbert return -EINVAL; 5032f0d1cf93SDouglas Gilbert } 5033f0d1cf93SDouglas Gilbert } else { 5034108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 5035108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 5036108e36f0SDamien Le Moal return -EINVAL; 5037108e36f0SDamien Le Moal } 503898e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 5039f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5040f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 5041f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 5042f0d1cf93SDouglas Gilbert return -EINVAL; 5043f0d1cf93SDouglas Gilbert } 5044f0d1cf93SDouglas Gilbert } 5045f0d1cf93SDouglas Gilbert 5046f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 5047f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 5048f0d1cf93SDouglas Gilbert 50494a5fc1c6SDamien Le Moal if (sdeb_zbc_zone_cap_mb == 0) { 50504a5fc1c6SDamien Le Moal devip->zcap = devip->zsize; 50514a5fc1c6SDamien Le Moal } else { 50524a5fc1c6SDamien Le Moal devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >> 50534a5fc1c6SDamien Le Moal ilog2(sdebug_sector_size); 50544a5fc1c6SDamien Le Moal if (devip->zcap > devip->zsize) { 50554a5fc1c6SDamien Le Moal pr_err("Zone capacity too large\n"); 50564a5fc1c6SDamien Le Moal return -EINVAL; 50574a5fc1c6SDamien Le Moal } 50584a5fc1c6SDamien Le Moal } 50594a5fc1c6SDamien Le Moal 50604a5fc1c6SDamien Le Moal conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift; 50614a5fc1c6SDamien Le Moal if (conv_capacity >= capacity) { 5062aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 5063aa8fecf9SDamien Le Moal return -EINVAL; 5064aa8fecf9SDamien Le Moal } 5065aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 50664a5fc1c6SDamien Le Moal devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >> 50674a5fc1c6SDamien Le Moal devip->zsize_shift; 50684a5fc1c6SDamien Le Moal devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones; 50694a5fc1c6SDamien Le Moal 50704a5fc1c6SDamien Le Moal /* Add gap zones if zone capacity is smaller than the zone size */ 50714a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 50724a5fc1c6SDamien Le Moal devip->nr_zones += devip->nr_seq_zones; 5073aa8fecf9SDamien Le Moal 507464e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 507564e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 5076380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 5077f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 5078f0d1cf93SDouglas Gilbert else 5079380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 508064e14eceSDamien Le Moal } 5081f0d1cf93SDouglas Gilbert 5082f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 5083f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 5084f0d1cf93SDouglas Gilbert if (!devip->zstate) 5085f0d1cf93SDouglas Gilbert return -ENOMEM; 5086f0d1cf93SDouglas Gilbert 5087f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 5088f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 5089f0d1cf93SDouglas Gilbert 5090f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 5091f0d1cf93SDouglas Gilbert 5092aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 509335dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_CNV; 5094f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 5095f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 50964a5fc1c6SDamien Le Moal zsp->z_size = 50974a5fc1c6SDamien Le Moal min_t(u64, devip->zsize, capacity - zstart); 50984a5fc1c6SDamien Le Moal } else if ((zstart & (devip->zsize - 1)) == 0) { 509964e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 510035dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWR; 510164e14eceSDamien Le Moal else 510235dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWP; 5103f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 5104f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 51054a5fc1c6SDamien Le Moal zsp->z_size = 51064a5fc1c6SDamien Le Moal min_t(u64, devip->zcap, capacity - zstart); 51074a5fc1c6SDamien Le Moal } else { 51084a5fc1c6SDamien Le Moal zsp->z_type = ZBC_ZTYPE_GAP; 51094a5fc1c6SDamien Le Moal zsp->z_cond = ZBC_NOT_WRITE_POINTER; 51104a5fc1c6SDamien Le Moal zsp->z_wp = (sector_t)-1; 51114a5fc1c6SDamien Le Moal zsp->z_size = min_t(u64, devip->zsize - devip->zcap, 51124a5fc1c6SDamien Le Moal capacity - zstart); 5113f0d1cf93SDouglas Gilbert } 5114f0d1cf93SDouglas Gilbert 51154a5fc1c6SDamien Le Moal WARN_ON_ONCE((int)zsp->z_size <= 0); 5116f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 5117f0d1cf93SDouglas Gilbert } 5118f0d1cf93SDouglas Gilbert 5119f0d1cf93SDouglas Gilbert return 0; 5120f0d1cf93SDouglas Gilbert } 5121f0d1cf93SDouglas Gilbert 5122fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 5123fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 51245cb2fc06SFUJITA Tomonori { 51255cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 51265cb2fc06SFUJITA Tomonori 51275cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 51285cb2fc06SFUJITA Tomonori if (devip) { 512909ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 5130bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 513109ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 513209ba24c1SDouglas Gilbert if (got_shared_uuid) 513309ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 513409ba24c1SDouglas Gilbert else { 5135bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 513609ba24c1SDouglas Gilbert got_shared_uuid = true; 513709ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 513809ba24c1SDouglas Gilbert } 513909ba24c1SDouglas Gilbert } 51405cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 5141f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 514264e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 5143f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 5144f0d1cf93SDouglas Gilbert kfree(devip); 5145f0d1cf93SDouglas Gilbert return NULL; 5146f0d1cf93SDouglas Gilbert } 514764e14eceSDamien Le Moal } else { 514864e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 5149f0d1cf93SDouglas Gilbert } 5150f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 5151fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 5152fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 51535cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 51545cb2fc06SFUJITA Tomonori } 51555cb2fc06SFUJITA Tomonori return devip; 51565cb2fc06SFUJITA Tomonori } 51575cb2fc06SFUJITA Tomonori 5158f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 51591da177e4SLinus Torvalds { 51601da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51611da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 5162f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 51631da177e4SLinus Torvalds 5164d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 51651da177e4SLinus Torvalds if (!sdbg_host) { 5166c1287970STomas Winkler pr_err("Host info NULL\n"); 51671da177e4SLinus Torvalds return NULL; 51681da177e4SLinus Torvalds } 5169ad0c7775SDouglas Gilbert 51701da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 51711da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 51721da177e4SLinus Torvalds (devip->target == sdev->id) && 51731da177e4SLinus Torvalds (devip->lun == sdev->lun)) 51741da177e4SLinus Torvalds return devip; 51751da177e4SLinus Torvalds else { 51761da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 51771da177e4SLinus Torvalds open_devip = devip; 51781da177e4SLinus Torvalds } 51791da177e4SLinus Torvalds } 51805cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 51815cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 51825cb2fc06SFUJITA Tomonori if (!open_devip) { 5183c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51841da177e4SLinus Torvalds return NULL; 51851da177e4SLinus Torvalds } 51861da177e4SLinus Torvalds } 5187a75869d1SFUJITA Tomonori 51881da177e4SLinus Torvalds open_devip->channel = sdev->channel; 51891da177e4SLinus Torvalds open_devip->target = sdev->id; 51901da177e4SLinus Torvalds open_devip->lun = sdev->lun; 51911da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 5192cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 5193500d0d24SDouglas Gilbert set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm); 5194c2248fc9SDouglas Gilbert open_devip->used = true; 51951da177e4SLinus Torvalds return open_devip; 51961da177e4SLinus Torvalds } 51971da177e4SLinus Torvalds 51988dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 51991da177e4SLinus Torvalds { 5200773642d9SDouglas Gilbert if (sdebug_verbose) 5201c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 52028dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52038dea0d02SFUJITA Tomonori return 0; 52048dea0d02SFUJITA Tomonori } 52051da177e4SLinus Torvalds 52068dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 52078dea0d02SFUJITA Tomonori { 5208f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5209f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5210a34c4e98SFUJITA Tomonori 5211773642d9SDouglas Gilbert if (sdebug_verbose) 5212c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 52138dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5214b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5215b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 5216b01f6f83SDouglas Gilbert if (devip == NULL) { 5217f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5218b01f6f83SDouglas Gilbert if (devip == NULL) 52198dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5220f46eb0e9SDouglas Gilbert } 5221c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5222773642d9SDouglas Gilbert if (sdebug_no_uld) 522378d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 52249b760fd8SDouglas Gilbert config_cdb_len(sdp); 52258dea0d02SFUJITA Tomonori return 0; 52268dea0d02SFUJITA Tomonori } 52278dea0d02SFUJITA Tomonori 52288dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 52298dea0d02SFUJITA Tomonori { 52308dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 52318dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 52328dea0d02SFUJITA Tomonori 5233773642d9SDouglas Gilbert if (sdebug_verbose) 5234c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 52358dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52368dea0d02SFUJITA Tomonori if (devip) { 523725985edcSLucas De Marchi /* make this slot available for re-use */ 5238c2248fc9SDouglas Gilbert devip->used = false; 52398dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 52408dea0d02SFUJITA Tomonori } 52418dea0d02SFUJITA Tomonori } 52428dea0d02SFUJITA Tomonori 524310bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 524410bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5245c4837394SDouglas Gilbert { 5246c4837394SDouglas Gilbert if (!sd_dp) 5247c4837394SDouglas Gilbert return; 524810bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5249c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 525010bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5251c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5252c4837394SDouglas Gilbert } 5253c4837394SDouglas Gilbert 5254a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5255a10bc12aSDouglas Gilbert returns false */ 5256a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 52578dea0d02SFUJITA Tomonori { 52588dea0d02SFUJITA Tomonori unsigned long iflags; 5259c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 526010bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5261c4837394SDouglas Gilbert struct sdebug_queue *sqp; 52628dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5263cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5264a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 52658dea0d02SFUJITA Tomonori 5266c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5267c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5268773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5269cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5270cbf67842SDouglas Gilbert if (r_qmax > qmax) 5271cbf67842SDouglas Gilbert qmax = r_qmax; 5272cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5273c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5274c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5275a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5276a10bc12aSDouglas Gilbert continue; 5277c4837394SDouglas Gilbert /* found */ 5278db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5279db525fceSDouglas Gilbert cmnd->device->hostdata; 5280db525fceSDouglas Gilbert if (devip) 5281db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5282db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5283a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 528410bde980SDouglas Gilbert if (sd_dp) { 5285d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5286d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 528710bde980SDouglas Gilbert } else 528810bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5289c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 529010bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5291c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5292a10bc12aSDouglas Gilbert return true; 52938dea0d02SFUJITA Tomonori } 5294cbf67842SDouglas Gilbert } 5295c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5296c4837394SDouglas Gilbert } 5297a10bc12aSDouglas Gilbert return false; 52988dea0d02SFUJITA Tomonori } 52998dea0d02SFUJITA Tomonori 5300a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 5301f19fe8f3SBart Van Assche static void stop_all_queued(void) 53028dea0d02SFUJITA Tomonori { 53038dea0d02SFUJITA Tomonori unsigned long iflags; 5304c4837394SDouglas Gilbert int j, k; 530510bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5306c4837394SDouglas Gilbert struct sdebug_queue *sqp; 53078dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5308cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5309a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 53108dea0d02SFUJITA Tomonori 5311c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5312c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5313c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5314c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5315c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5316f19fe8f3SBart Van Assche if (sqcp->a_cmnd == NULL) 5317a10bc12aSDouglas Gilbert continue; 5318db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5319db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5320db525fceSDouglas Gilbert if (devip) 5321db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5322db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5323a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 532410bde980SDouglas Gilbert if (sd_dp) { 5325d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5326d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 532710bde980SDouglas Gilbert } else 532810bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5329c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 533010bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5331c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5332c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 53338dea0d02SFUJITA Tomonori } 53348dea0d02SFUJITA Tomonori } 5335c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5336c4837394SDouglas Gilbert } 5337cbf67842SDouglas Gilbert } 5338cbf67842SDouglas Gilbert 5339cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5340cbf67842SDouglas Gilbert static void free_all_queued(void) 5341cbf67842SDouglas Gilbert { 5342c4837394SDouglas Gilbert int j, k; 5343c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5344cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5345cbf67842SDouglas Gilbert 5346c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5347c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5348c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5349a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5350a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5351cbf67842SDouglas Gilbert } 53521da177e4SLinus Torvalds } 5353c4837394SDouglas Gilbert } 53541da177e4SLinus Torvalds 53551da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 53561da177e4SLinus Torvalds { 5357a10bc12aSDouglas Gilbert bool ok; 5358a10bc12aSDouglas Gilbert 53591da177e4SLinus Torvalds ++num_aborts; 5360cbf67842SDouglas Gilbert if (SCpnt) { 5361a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5362a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5363a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5364a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5365a10bc12aSDouglas Gilbert ok ? "" : " not"); 5366cbf67842SDouglas Gilbert } 53671da177e4SLinus Torvalds return SUCCESS; 53681da177e4SLinus Torvalds } 53691da177e4SLinus Torvalds 53701da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 53711da177e4SLinus Torvalds { 53721da177e4SLinus Torvalds ++num_dev_resets; 5373cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5374cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5375f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5376f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5377cbf67842SDouglas Gilbert 5378773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5379cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 53801da177e4SLinus Torvalds if (devip) 5381cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 53821da177e4SLinus Torvalds } 53831da177e4SLinus Torvalds return SUCCESS; 53841da177e4SLinus Torvalds } 53851da177e4SLinus Torvalds 5386cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5387cbf67842SDouglas Gilbert { 5388cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5389cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5390cbf67842SDouglas Gilbert struct scsi_device *sdp; 5391cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5392cbf67842SDouglas Gilbert int k = 0; 5393cbf67842SDouglas Gilbert 5394cbf67842SDouglas Gilbert ++num_target_resets; 5395cbf67842SDouglas Gilbert if (!SCpnt) 5396cbf67842SDouglas Gilbert goto lie; 5397cbf67842SDouglas Gilbert sdp = SCpnt->device; 5398cbf67842SDouglas Gilbert if (!sdp) 5399cbf67842SDouglas Gilbert goto lie; 5400773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5401cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5402cbf67842SDouglas Gilbert hp = sdp->host; 5403cbf67842SDouglas Gilbert if (!hp) 5404cbf67842SDouglas Gilbert goto lie; 5405cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5406cbf67842SDouglas Gilbert if (sdbg_host) { 5407cbf67842SDouglas Gilbert list_for_each_entry(devip, 5408cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5409cbf67842SDouglas Gilbert dev_list) 5410cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5411cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5412cbf67842SDouglas Gilbert ++k; 5413cbf67842SDouglas Gilbert } 5414cbf67842SDouglas Gilbert } 5415773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5416cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5417cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5418cbf67842SDouglas Gilbert lie: 5419cbf67842SDouglas Gilbert return SUCCESS; 5420cbf67842SDouglas Gilbert } 5421cbf67842SDouglas Gilbert 54221da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 54231da177e4SLinus Torvalds { 54241da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5425cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 54261da177e4SLinus Torvalds struct scsi_device *sdp; 54271da177e4SLinus Torvalds struct Scsi_Host *hp; 5428cbf67842SDouglas Gilbert int k = 0; 54291da177e4SLinus Torvalds 54301da177e4SLinus Torvalds ++num_bus_resets; 5431cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5432cbf67842SDouglas Gilbert goto lie; 5433cbf67842SDouglas Gilbert sdp = SCpnt->device; 5434773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5435cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5436cbf67842SDouglas Gilbert hp = sdp->host; 5437cbf67842SDouglas Gilbert if (hp) { 5438d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 54391da177e4SLinus Torvalds if (sdbg_host) { 5440cbf67842SDouglas Gilbert list_for_each_entry(devip, 54411da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5442cbf67842SDouglas Gilbert dev_list) { 5443cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5444cbf67842SDouglas Gilbert ++k; 54451da177e4SLinus Torvalds } 54461da177e4SLinus Torvalds } 5447cbf67842SDouglas Gilbert } 5448773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5449cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5450cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5451cbf67842SDouglas Gilbert lie: 54521da177e4SLinus Torvalds return SUCCESS; 54531da177e4SLinus Torvalds } 54541da177e4SLinus Torvalds 54551da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 54561da177e4SLinus Torvalds { 54571da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5458cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5459cbf67842SDouglas Gilbert int k = 0; 54601da177e4SLinus Torvalds 54611da177e4SLinus Torvalds ++num_host_resets; 5462773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5463cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 54641da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 54651da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5466cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5467cbf67842SDouglas Gilbert dev_list) { 5468cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5469cbf67842SDouglas Gilbert ++k; 5470cbf67842SDouglas Gilbert } 54711da177e4SLinus Torvalds } 54721da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 5473f19fe8f3SBart Van Assche stop_all_queued(); 5474773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5475cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5476cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 54771da177e4SLinus Torvalds return SUCCESS; 54781da177e4SLinus Torvalds } 54791da177e4SLinus Torvalds 548087c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 54811da177e4SLinus Torvalds { 54821442f76dSChristoph Hellwig struct msdos_partition *pp; 5483979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 54841da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 54851da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 54861da177e4SLinus Torvalds 54871da177e4SLinus Torvalds /* assume partition table already zeroed */ 5488773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 54891da177e4SLinus Torvalds return; 5490773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5491773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5492c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 54931da177e4SLinus Torvalds } 54948c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 54951da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5496773642d9SDouglas Gilbert / sdebug_num_parts; 54971da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 54981da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5499979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5500979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 55011da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 55021da177e4SLinus Torvalds * heads_by_sects; 5503979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5504979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5505979e0dc3SJohn Pittman } 5506773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5507773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 55081da177e4SLinus Torvalds 55091da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 55101da177e4SLinus Torvalds ramp[511] = 0xAA; 55111442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 55121da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 55131da177e4SLinus Torvalds start_sec = starts[k]; 5514979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 55151da177e4SLinus Torvalds pp->boot_ind = 0; 55161da177e4SLinus Torvalds 55171da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 55181da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 55191da177e4SLinus Torvalds / sdebug_sectors_per; 55201da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 55211da177e4SLinus Torvalds 55221da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 55231da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 55241da177e4SLinus Torvalds / sdebug_sectors_per; 55251da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 55261da177e4SLinus Torvalds 5527150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5528150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 55291da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 55301da177e4SLinus Torvalds } 55311da177e4SLinus Torvalds } 55321da177e4SLinus Torvalds 5533f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block) 5534c4837394SDouglas Gilbert { 5535c4837394SDouglas Gilbert int j; 5536c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5537c4837394SDouglas Gilbert 5538c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 5539f19fe8f3SBart Van Assche atomic_set(&sqp->blocked, (int)block); 5540c4837394SDouglas Gilbert } 5541c4837394SDouglas Gilbert 5542c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5543c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5544c4837394SDouglas Gilbert */ 5545c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5546c4837394SDouglas Gilbert { 5547c4837394SDouglas Gilbert int count, modulo; 5548c4837394SDouglas Gilbert 5549c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5550c4837394SDouglas Gilbert if (modulo < 2) 5551c4837394SDouglas Gilbert return; 5552f19fe8f3SBart Van Assche block_unblock_all_queues(true); 5553c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5554c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5555f19fe8f3SBart Van Assche block_unblock_all_queues(false); 5556c4837394SDouglas Gilbert } 5557c4837394SDouglas Gilbert 5558c4837394SDouglas Gilbert static void clear_queue_stats(void) 5559c4837394SDouglas Gilbert { 5560c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5561c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5562c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5563c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5564c4837394SDouglas Gilbert } 5565c4837394SDouglas Gilbert 55663a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5567c4837394SDouglas Gilbert { 55683a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 55693a90a63dSDouglas Gilbert return false; 55703a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5571c4837394SDouglas Gilbert } 5572c4837394SDouglas Gilbert 5573a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5574a2aede97SDouglas Gilbert 5575c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5576c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5577c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5578c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5579c4837394SDouglas Gilbert */ 5580fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5581f66b8517SMartin Wilck int scsi_result, 5582f19fe8f3SBart Van Assche int (*pfp)(struct scsi_cmnd *, 5583f19fe8f3SBart Van Assche struct sdebug_dev_info *), 5584f66b8517SMartin Wilck int delta_jiff, int ndelay) 55851da177e4SLinus Torvalds { 5586a2aede97SDouglas Gilbert bool new_sd_dp; 55873a90a63dSDouglas Gilbert bool inject = false; 55886ce913feSChristoph Hellwig bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED; 55893a90a63dSDouglas Gilbert int k, num_in_q, qdepth; 5590a2aede97SDouglas Gilbert unsigned long iflags; 5591a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5592c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5593c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5594299b6c07STomas Winkler struct scsi_device *sdp; 5595a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 55961da177e4SLinus Torvalds 5597b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5598b01f6f83SDouglas Gilbert if (scsi_result == 0) 5599f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5600f46eb0e9SDouglas Gilbert goto respond_in_thread; 56011da177e4SLinus Torvalds } 5602299b6c07STomas Winkler sdp = cmnd->device; 5603299b6c07STomas Winkler 5604f19fe8f3SBart Van Assche if (delta_jiff == 0) 5605cd62b7daSDouglas Gilbert goto respond_in_thread; 56061da177e4SLinus Torvalds 5607c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5608c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5609c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5610c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5611c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5612c4837394SDouglas Gilbert } 5613cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5614cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5615f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5616cd62b7daSDouglas Gilbert if (scsi_result) { 5617c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5618cd62b7daSDouglas Gilbert goto respond_in_thread; 5619cd62b7daSDouglas Gilbert } else 5620cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5621c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5622773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5623f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5624cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5625cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5626773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5627cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 56283a90a63dSDouglas Gilbert inject = true; 5629cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 56301da177e4SLinus Torvalds } 5631cbf67842SDouglas Gilbert } 5632cbf67842SDouglas Gilbert 5633c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5634f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5635c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5636cd62b7daSDouglas Gilbert if (scsi_result) 5637cd62b7daSDouglas Gilbert goto respond_in_thread; 5638cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5639773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 56407d5a129bSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n", 56417d5a129bSDouglas Gilbert __func__, sdebug_max_queue); 5642cd62b7daSDouglas Gilbert goto respond_in_thread; 56431da177e4SLinus Torvalds } 564474595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5645cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5646c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 56471da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5648c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5649a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5650c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5651c4b57d89SKashyap Desai 565274595c04SDouglas Gilbert if (!sd_dp) { 565310bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 565474595c04SDouglas Gilbert if (!sd_dp) { 565574595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 565674595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 565710bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 565874595c04SDouglas Gilbert } 5659a2aede97SDouglas Gilbert new_sd_dp = true; 5660a2aede97SDouglas Gilbert } else { 5661a2aede97SDouglas Gilbert new_sd_dp = false; 566210bde980SDouglas Gilbert } 5663f66b8517SMartin Wilck 5664c10fa55fSJohn Garry /* Set the hostwide tag */ 5665c10fa55fSJohn Garry if (sdebug_host_max_queue) 5666c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5667c10fa55fSJohn Garry 56686ce913feSChristoph Hellwig if (polled) 5669a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5670a2aede97SDouglas Gilbert 5671a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 56723a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5673f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5674f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5675f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5676f66b8517SMartin Wilck } 5677f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5678f66b8517SMartin Wilck cmnd->result = scsi_result; 56793a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 56803a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 56813a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 56823a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 56833a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 56843a90a63dSDouglas Gilbert } 56853a90a63dSDouglas Gilbert } 5686f66b8517SMartin Wilck 5687f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5688f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5689f66b8517SMartin Wilck __func__, cmnd->result); 5690f66b8517SMartin Wilck 569110bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5692b333a819SDouglas Gilbert ktime_t kt; 5693cbf67842SDouglas Gilbert 5694b333a819SDouglas Gilbert if (delta_jiff > 0) { 56950c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 56960c4bc91dSDouglas Gilbert 56970c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 56980c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 56990c4bc91dSDouglas Gilbert } else if (sdebug_random) { 57000c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 57010c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 57020c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 57030c4bc91dSDouglas Gilbert ns <<= 12; 57040c4bc91dSDouglas Gilbert } 57050c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 57060c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 57070c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 57080c4bc91dSDouglas Gilbert (u32)ndelay; 5709a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5710a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5711a2aede97SDouglas Gilbert 5712a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5713223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5714a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5715a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5716a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5717223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5718a2aede97SDouglas Gilbert if (new_sd_dp) 5719a2aede97SDouglas Gilbert kfree(sd_dp); 5720a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 57216c2c7d6aSBart Van Assche scsi_done(cmnd); 5722a2aede97SDouglas Gilbert return 0; 5723a2aede97SDouglas Gilbert } 5724a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5725a2aede97SDouglas Gilbert kt -= d; 5726a2aede97SDouglas Gilbert } 57270c4bc91dSDouglas Gilbert } 57286ce913feSChristoph Hellwig if (polled) { 57294a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 57304a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57314a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57324a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57334a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57344a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57354a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57364a0c6f43SDouglas Gilbert } 5737d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57384a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57394a0c6f43SDouglas Gilbert } else { 574010bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 574110bde980SDouglas Gilbert sd_dp->init_hrt = true; 5742a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5743a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5744c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5745a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5746c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5747c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5748cbf67842SDouglas Gilbert } 5749d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); 5750a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5751c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 57524a0c6f43SDouglas Gilbert } 57534a0c6f43SDouglas Gilbert if (sdebug_statistics) 57544a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 5755c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 57564a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 57574a0c6f43SDouglas Gilbert atomic_read(&sdeb_inject_pending))) 57584a0c6f43SDouglas Gilbert sd_dp->aborted = true; 57596ce913feSChristoph Hellwig if (polled) { 57604a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 57614a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57624a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 57634a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 57644a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 57654a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 57664a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 57674a0c6f43SDouglas Gilbert } 5768d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57694a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 57704a0c6f43SDouglas Gilbert } else { 577110bde980SDouglas Gilbert if (!sd_dp->init_wq) { 577210bde980SDouglas Gilbert sd_dp->init_wq = true; 5773a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5774c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5775c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5776a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5777cbf67842SDouglas Gilbert } 5778d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); 57794a0c6f43SDouglas Gilbert schedule_work(&sd_dp->ew.work); 57804a0c6f43SDouglas Gilbert } 5781c4837394SDouglas Gilbert if (sdebug_statistics) 5782c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 57834a0c6f43SDouglas Gilbert if (unlikely(sd_dp->aborted)) { 5784a6e76e6fSBart Van Assche sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 5785a6e76e6fSBart Van Assche scsi_cmd_to_rq(cmnd)->tag); 5786a6e76e6fSBart Van Assche blk_abort_request(scsi_cmd_to_rq(cmnd)); 57873a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 57884a0c6f43SDouglas Gilbert sd_dp->aborted = false; 57897382f9d8SDouglas Gilbert } 5790cbf67842SDouglas Gilbert } 57913a90a63dSDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result)) 57923a90a63dSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__, 57933a90a63dSDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL"); 57941da177e4SLinus Torvalds return 0; 5795cd62b7daSDouglas Gilbert 5796cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5797f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5798f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5799f19fe8f3SBart Van Assche if (cmnd->result == 0 && scsi_result != 0) 5800cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 58016c2c7d6aSBart Van Assche scsi_done(cmnd); 5802cd62b7daSDouglas Gilbert return 0; 58031da177e4SLinus Torvalds } 5804cbf67842SDouglas Gilbert 580523183910SDouglas Gilbert /* Note: The following macros create attribute files in the 580623183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 580723183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 580823183910SDouglas Gilbert as it can when the corresponding attribute in the 580923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 581023183910SDouglas Gilbert */ 5811773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5812773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 58139b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5814773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5815c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5816773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5817773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5818773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5819773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5820773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5821773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5822773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5823773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5824c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5825e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5826e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5827e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5828e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 58295d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 58305d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 58315d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5832773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5833773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5834773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5835773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5836ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5837773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5838773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 58395d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 58405d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 58415d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 58425d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5843773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5844773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 58457109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR); 5846773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5847773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5848773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5849773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 58505d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5851773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 585287c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 585387c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5854773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5855773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 58560c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5857773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5858773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5859773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5860c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5861773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5862c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5863c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5864fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5865773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5866773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5867773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5868773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 586909ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 58705d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5871773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 587223183910SDouglas Gilbert S_IRUGO | S_IWUSR); 58739447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5874773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 58755b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 58769267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 58774a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO); 5878380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5879aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 588098e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 58811da177e4SLinus Torvalds 58821da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 58831da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 58841da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5885b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 58861da177e4SLinus Torvalds 58875d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 58885b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 58899b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 58900759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5891cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5892c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 58935b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 58945b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5895c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5896beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 589723183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 58985b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5899185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5900c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5901c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5902e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 59039b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 59049b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 59055d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 59065d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 59075d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 59085b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 59095b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 59105b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 59115b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5912ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5913fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5914cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5915d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 59165d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5917cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5918c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 59197109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)"); 592078d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 59211da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5922c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 592332c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 592486e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 59255d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 59265d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 59275d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5928fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 59291da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 59300c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5931d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5932760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5933ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5934c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5935c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5936c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5937fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 59385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 59395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 59406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 59416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 594209ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 594309ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5944c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 59455b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 59469447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 59475b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 59489267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 59494a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)"); 5950380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5951aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 595298e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 59531da177e4SLinus Torvalds 5954760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5955760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 59561da177e4SLinus Torvalds 59571da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 59581da177e4SLinus Torvalds { 5959c4837394SDouglas Gilbert int k; 5960c4837394SDouglas Gilbert 5961760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5962760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5963760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5964c4837394SDouglas Gilbert return sdebug_info; 5965760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5966760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5967760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5968760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 59691da177e4SLinus Torvalds return sdebug_info; 59701da177e4SLinus Torvalds } 59711da177e4SLinus Torvalds 5972cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5973fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5974fd32119bSDouglas Gilbert int length) 59751da177e4SLinus Torvalds { 59761da177e4SLinus Torvalds char arr[16]; 5977c8ed555aSAl Viro int opts; 59781da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 59791da177e4SLinus Torvalds 59801da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 59811da177e4SLinus Torvalds return -EACCES; 59821da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 59831da177e4SLinus Torvalds arr[minLen] = '\0'; 5984c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 59851da177e4SLinus Torvalds return -EINVAL; 5986773642d9SDouglas Gilbert sdebug_opts = opts; 5987773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5988773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5989773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5990c4837394SDouglas Gilbert tweak_cmnd_count(); 59911da177e4SLinus Torvalds return length; 59921da177e4SLinus Torvalds } 5993c8ed555aSAl Viro 5994cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5995cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5996cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5997c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5998c8ed555aSAl Viro { 5999c4837394SDouglas Gilbert int f, j, l; 6000c4837394SDouglas Gilbert struct sdebug_queue *sqp; 600187c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 6002cbf67842SDouglas Gilbert 6003c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 6004c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 6005c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 6006c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 6007c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 6008c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 6009c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 6010c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 6011c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 6012c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 6013c4837394SDouglas Gilbert num_aborts); 6014c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 6015c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 6016c4837394SDouglas Gilbert num_host_resets); 6017c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 6018c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 6019458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 6020458df78bSBart Van Assche sdebug_statistics); 60214a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 6022c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 6023c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 6024c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 60254a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 60264a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 6027cbf67842SDouglas Gilbert 6028c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 6029c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 6030c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 6031c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 6032773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 6033c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 6034c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 6035c4837394SDouglas Gilbert "first,last bits", f, l); 6036c4837394SDouglas Gilbert } 6037cbf67842SDouglas Gilbert } 603887c715dcSDouglas Gilbert 603987c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 604087c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 604187c715dcSDouglas Gilbert bool niu; 604287c715dcSDouglas Gilbert int idx; 604387c715dcSDouglas Gilbert unsigned long l_idx; 604487c715dcSDouglas Gilbert struct sdeb_store_info *sip; 604587c715dcSDouglas Gilbert 604687c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 604787c715dcSDouglas Gilbert j = 0; 604887c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 604987c715dcSDouglas Gilbert idx = sdhp->si_idx; 605087c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 605187c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 605287c715dcSDouglas Gilbert ++j; 605387c715dcSDouglas Gilbert } 605487c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 605587c715dcSDouglas Gilbert sdeb_most_recent_idx); 605687c715dcSDouglas Gilbert j = 0; 605787c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 605887c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 605987c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 606087c715dcSDouglas Gilbert idx = (int)l_idx; 606187c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 606287c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 606387c715dcSDouglas Gilbert ++j; 606487c715dcSDouglas Gilbert } 606587c715dcSDouglas Gilbert } 6066c8ed555aSAl Viro return 0; 60671da177e4SLinus Torvalds } 60681da177e4SLinus Torvalds 606982069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 60701da177e4SLinus Torvalds { 6071c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 60721da177e4SLinus Torvalds } 6073c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 6074c4837394SDouglas Gilbert * of delay is jiffies. 6075c4837394SDouglas Gilbert */ 607682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 607782069379SAkinobu Mita size_t count) 60781da177e4SLinus Torvalds { 6079c2206098SDouglas Gilbert int jdelay, res; 60801da177e4SLinus Torvalds 6081b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 6082cbf67842SDouglas Gilbert res = count; 6083c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 6084c4837394SDouglas Gilbert int j, k; 6085c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6086cbf67842SDouglas Gilbert 6087f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6088c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6089c4837394SDouglas Gilbert ++j, ++sqp) { 6090c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6091c4837394SDouglas Gilbert sdebug_max_queue); 6092c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6093c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6094c4837394SDouglas Gilbert break; 6095c4837394SDouglas Gilbert } 6096c4837394SDouglas Gilbert } 6097c4837394SDouglas Gilbert if (res > 0) { 6098c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 6099773642d9SDouglas Gilbert sdebug_ndelay = 0; 61001da177e4SLinus Torvalds } 6101f19fe8f3SBart Van Assche block_unblock_all_queues(false); 6102cbf67842SDouglas Gilbert } 6103cbf67842SDouglas Gilbert return res; 61041da177e4SLinus Torvalds } 61051da177e4SLinus Torvalds return -EINVAL; 61061da177e4SLinus Torvalds } 610782069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 61081da177e4SLinus Torvalds 6109cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 6110cbf67842SDouglas Gilbert { 6111773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 6112cbf67842SDouglas Gilbert } 6113cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 6114c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 6115cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 6116cbf67842SDouglas Gilbert size_t count) 6117cbf67842SDouglas Gilbert { 6118c4837394SDouglas Gilbert int ndelay, res; 6119cbf67842SDouglas Gilbert 6120cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 6121c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 6122cbf67842SDouglas Gilbert res = count; 6123773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 6124c4837394SDouglas Gilbert int j, k; 6125c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6126c4837394SDouglas Gilbert 6127f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6128c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6129c4837394SDouglas Gilbert ++j, ++sqp) { 6130c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6131c4837394SDouglas Gilbert sdebug_max_queue); 6132c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6133c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6134c4837394SDouglas Gilbert break; 6135c4837394SDouglas Gilbert } 6136c4837394SDouglas Gilbert } 6137c4837394SDouglas Gilbert if (res > 0) { 6138773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 6139c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 6140c2206098SDouglas Gilbert : DEF_JDELAY; 6141cbf67842SDouglas Gilbert } 6142f19fe8f3SBart Van Assche block_unblock_all_queues(false); 6143cbf67842SDouglas Gilbert } 6144cbf67842SDouglas Gilbert return res; 6145cbf67842SDouglas Gilbert } 6146cbf67842SDouglas Gilbert return -EINVAL; 6147cbf67842SDouglas Gilbert } 6148cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 6149cbf67842SDouglas Gilbert 615082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 61511da177e4SLinus Torvalds { 6152773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 61531da177e4SLinus Torvalds } 61541da177e4SLinus Torvalds 615582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 615682069379SAkinobu Mita size_t count) 61571da177e4SLinus Torvalds { 61581da177e4SLinus Torvalds int opts; 61591da177e4SLinus Torvalds char work[20]; 61601da177e4SLinus Torvalds 61619a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 61629a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 61639a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 61641da177e4SLinus Torvalds goto opts_done; 61651da177e4SLinus Torvalds } else { 61669a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 61671da177e4SLinus Torvalds goto opts_done; 61681da177e4SLinus Torvalds } 61691da177e4SLinus Torvalds } 61701da177e4SLinus Torvalds return -EINVAL; 61711da177e4SLinus Torvalds opts_done: 6172773642d9SDouglas Gilbert sdebug_opts = opts; 6173773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 6174773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 6175c4837394SDouglas Gilbert tweak_cmnd_count(); 61761da177e4SLinus Torvalds return count; 61771da177e4SLinus Torvalds } 617882069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 61791da177e4SLinus Torvalds 618082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 61811da177e4SLinus Torvalds { 6182773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 61831da177e4SLinus Torvalds } 618482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 618582069379SAkinobu Mita size_t count) 61861da177e4SLinus Torvalds { 61871da177e4SLinus Torvalds int n; 61881da177e4SLinus Torvalds 6189f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 6190f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 6191f0d1cf93SDouglas Gilbert return -EINVAL; 6192f0d1cf93SDouglas Gilbert 61931da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6194f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 6195f0d1cf93SDouglas Gilbert return -EINVAL; 6196773642d9SDouglas Gilbert sdebug_ptype = n; 61971da177e4SLinus Torvalds return count; 61981da177e4SLinus Torvalds } 61991da177e4SLinus Torvalds return -EINVAL; 62001da177e4SLinus Torvalds } 620182069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 62021da177e4SLinus Torvalds 620382069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 62041da177e4SLinus Torvalds { 6205773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 62061da177e4SLinus Torvalds } 620782069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 620882069379SAkinobu Mita size_t count) 62091da177e4SLinus Torvalds { 62101da177e4SLinus Torvalds int n; 62111da177e4SLinus Torvalds 62121da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6213773642d9SDouglas Gilbert sdebug_dsense = n; 62141da177e4SLinus Torvalds return count; 62151da177e4SLinus Torvalds } 62161da177e4SLinus Torvalds return -EINVAL; 62171da177e4SLinus Torvalds } 621882069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 62191da177e4SLinus Torvalds 622082069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 622123183910SDouglas Gilbert { 6222773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 622323183910SDouglas Gilbert } 622482069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 622582069379SAkinobu Mita size_t count) 622623183910SDouglas Gilbert { 622787c715dcSDouglas Gilbert int n, idx; 622823183910SDouglas Gilbert 622923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 623087c715dcSDouglas Gilbert bool want_store = (n == 0); 623187c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 623287c715dcSDouglas Gilbert 6233cbf67842SDouglas Gilbert n = (n > 0); 6234773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 623587c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 623687c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6237cbf67842SDouglas Gilbert 623887c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 623987c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 624087c715dcSDouglas Gilbert idx = sdebug_add_store(); 624187c715dcSDouglas Gilbert if (idx < 0) 624287c715dcSDouglas Gilbert return idx; 624387c715dcSDouglas Gilbert } else { 624487c715dcSDouglas Gilbert idx = sdeb_first_idx; 624587c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 624687c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6247cbf67842SDouglas Gilbert } 624887c715dcSDouglas Gilbert /* make all hosts use same store */ 624987c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 625087c715dcSDouglas Gilbert host_list) { 625187c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 625287c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 625387c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 625487c715dcSDouglas Gilbert sdhp->si_idx = idx; 625587c715dcSDouglas Gilbert } 625687c715dcSDouglas Gilbert } 625787c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 625887c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 625987c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6260cbf67842SDouglas Gilbert } 6261773642d9SDouglas Gilbert sdebug_fake_rw = n; 626223183910SDouglas Gilbert return count; 626323183910SDouglas Gilbert } 626423183910SDouglas Gilbert return -EINVAL; 626523183910SDouglas Gilbert } 626682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 626723183910SDouglas Gilbert 626882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6269c65b1445SDouglas Gilbert { 6270773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6271c65b1445SDouglas Gilbert } 627282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 627382069379SAkinobu Mita size_t count) 6274c65b1445SDouglas Gilbert { 6275c65b1445SDouglas Gilbert int n; 6276c65b1445SDouglas Gilbert 6277c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6278773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6279c65b1445SDouglas Gilbert return count; 6280c65b1445SDouglas Gilbert } 6281c65b1445SDouglas Gilbert return -EINVAL; 6282c65b1445SDouglas Gilbert } 628382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6284c65b1445SDouglas Gilbert 628582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 62861da177e4SLinus Torvalds { 6287773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 62881da177e4SLinus Torvalds } 628982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 629082069379SAkinobu Mita size_t count) 62911da177e4SLinus Torvalds { 62921da177e4SLinus Torvalds int n; 62931da177e4SLinus Torvalds 62941da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6295773642d9SDouglas Gilbert sdebug_num_tgts = n; 62961da177e4SLinus Torvalds sdebug_max_tgts_luns(); 62971da177e4SLinus Torvalds return count; 62981da177e4SLinus Torvalds } 62991da177e4SLinus Torvalds return -EINVAL; 63001da177e4SLinus Torvalds } 630182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 63021da177e4SLinus Torvalds 630382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 63041da177e4SLinus Torvalds { 6305773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 63061da177e4SLinus Torvalds } 630782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 63081da177e4SLinus Torvalds 630987c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 631087c715dcSDouglas Gilbert { 631187c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 631287c715dcSDouglas Gilbert } 631387c715dcSDouglas Gilbert 631487c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 631587c715dcSDouglas Gilbert size_t count) 631687c715dcSDouglas Gilbert { 631787c715dcSDouglas Gilbert bool v; 631887c715dcSDouglas Gilbert 631987c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 632087c715dcSDouglas Gilbert return -EINVAL; 632187c715dcSDouglas Gilbert 632287c715dcSDouglas Gilbert sdebug_per_host_store = v; 632387c715dcSDouglas Gilbert return count; 632487c715dcSDouglas Gilbert } 632587c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 632687c715dcSDouglas Gilbert 632782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 63281da177e4SLinus Torvalds { 6329773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 63301da177e4SLinus Torvalds } 633182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 63321da177e4SLinus Torvalds 633382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 63341da177e4SLinus Torvalds { 6335773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 63361da177e4SLinus Torvalds } 633782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 633882069379SAkinobu Mita size_t count) 63391da177e4SLinus Torvalds { 63401da177e4SLinus Torvalds int nth; 63413a90a63dSDouglas Gilbert char work[20]; 63421da177e4SLinus Torvalds 63433a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 63443a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 63453a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 63463a90a63dSDouglas Gilbert goto every_nth_done; 63473a90a63dSDouglas Gilbert } else { 63483a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 63493a90a63dSDouglas Gilbert goto every_nth_done; 63503a90a63dSDouglas Gilbert } 63513a90a63dSDouglas Gilbert } 63523a90a63dSDouglas Gilbert return -EINVAL; 63533a90a63dSDouglas Gilbert 63543a90a63dSDouglas Gilbert every_nth_done: 6355773642d9SDouglas Gilbert sdebug_every_nth = nth; 6356c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6357c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6358c4837394SDouglas Gilbert sdebug_statistics = true; 6359c4837394SDouglas Gilbert } 6360c4837394SDouglas Gilbert tweak_cmnd_count(); 63611da177e4SLinus Torvalds return count; 63621da177e4SLinus Torvalds } 636382069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 63641da177e4SLinus Torvalds 6365ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6366ad0c7775SDouglas Gilbert { 6367ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6368ad0c7775SDouglas Gilbert } 6369ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6370ad0c7775SDouglas Gilbert size_t count) 6371ad0c7775SDouglas Gilbert { 6372ad0c7775SDouglas Gilbert int n; 6373ad0c7775SDouglas Gilbert bool changed; 6374ad0c7775SDouglas Gilbert 6375ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6376ad0c7775SDouglas Gilbert return -EINVAL; 6377ad0c7775SDouglas Gilbert if (n >= 0) { 6378ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6379ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6380ad0c7775SDouglas Gilbert return -EINVAL; 6381ad0c7775SDouglas Gilbert } 6382ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6383ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6384ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6385ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6386ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6387ad0c7775SDouglas Gilbert 6388ad0c7775SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 6389ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6390ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6391ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6392ad0c7775SDouglas Gilbert } 6393ad0c7775SDouglas Gilbert } 6394ad0c7775SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 6395ad0c7775SDouglas Gilbert } 6396ad0c7775SDouglas Gilbert return count; 6397ad0c7775SDouglas Gilbert } 6398ad0c7775SDouglas Gilbert return -EINVAL; 6399ad0c7775SDouglas Gilbert } 6400ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6401ad0c7775SDouglas Gilbert 640282069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 64031da177e4SLinus Torvalds { 6404773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 64051da177e4SLinus Torvalds } 640682069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 640782069379SAkinobu Mita size_t count) 64081da177e4SLinus Torvalds { 64091da177e4SLinus Torvalds int n; 641019c8ead7SEwan D. Milne bool changed; 64111da177e4SLinus Torvalds 64121da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 64138d039e22SDouglas Gilbert if (n > 256) { 64148d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 64158d039e22SDouglas Gilbert return -EINVAL; 64168d039e22SDouglas Gilbert } 6417773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6418773642d9SDouglas Gilbert sdebug_max_luns = n; 64191da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6420773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 642119c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 642219c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 642319c8ead7SEwan D. Milne 642419c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 642519c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 642619c8ead7SEwan D. Milne host_list) { 642719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 642819c8ead7SEwan D. Milne dev_list) { 642919c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 643019c8ead7SEwan D. Milne dp->uas_bm); 643119c8ead7SEwan D. Milne } 643219c8ead7SEwan D. Milne } 643319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 643419c8ead7SEwan D. Milne } 64351da177e4SLinus Torvalds return count; 64361da177e4SLinus Torvalds } 64371da177e4SLinus Torvalds return -EINVAL; 64381da177e4SLinus Torvalds } 643982069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 64401da177e4SLinus Torvalds 644182069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 644278d4e5a0SDouglas Gilbert { 6443773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 644478d4e5a0SDouglas Gilbert } 6445cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6446cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 644782069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 644882069379SAkinobu Mita size_t count) 644978d4e5a0SDouglas Gilbert { 6450c4837394SDouglas Gilbert int j, n, k, a; 6451c4837394SDouglas Gilbert struct sdebug_queue *sqp; 645278d4e5a0SDouglas Gilbert 645378d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6454c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6455c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 6456f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6457c4837394SDouglas Gilbert k = 0; 6458c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6459c4837394SDouglas Gilbert ++j, ++sqp) { 6460c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6461c4837394SDouglas Gilbert if (a > k) 6462c4837394SDouglas Gilbert k = a; 6463c4837394SDouglas Gilbert } 6464773642d9SDouglas Gilbert sdebug_max_queue = n; 6465c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6466cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6467cbf67842SDouglas Gilbert else if (k >= n) 6468cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6469cbf67842SDouglas Gilbert else 6470cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6471f19fe8f3SBart Van Assche block_unblock_all_queues(false); 647278d4e5a0SDouglas Gilbert return count; 647378d4e5a0SDouglas Gilbert } 647478d4e5a0SDouglas Gilbert return -EINVAL; 647578d4e5a0SDouglas Gilbert } 647682069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 647778d4e5a0SDouglas Gilbert 6478c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6479c10fa55fSJohn Garry { 6480c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6481c10fa55fSJohn Garry } 6482c10fa55fSJohn Garry 64837109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf) 64847109f370SDouglas Gilbert { 64857109f370SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock); 64867109f370SDouglas Gilbert } 64877109f370SDouglas Gilbert 64887109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count) 64897109f370SDouglas Gilbert { 64907109f370SDouglas Gilbert bool v; 64917109f370SDouglas Gilbert 64927109f370SDouglas Gilbert if (kstrtobool(buf, &v)) 64937109f370SDouglas Gilbert return -EINVAL; 64947109f370SDouglas Gilbert 64957109f370SDouglas Gilbert sdebug_no_rwlock = v; 64967109f370SDouglas Gilbert return count; 64977109f370SDouglas Gilbert } 64987109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock); 64997109f370SDouglas Gilbert 6500c10fa55fSJohn Garry /* 6501c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6502c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6503c10fa55fSJohn Garry */ 6504c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6505c10fa55fSJohn Garry 650682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 650778d4e5a0SDouglas Gilbert { 6508773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 650978d4e5a0SDouglas Gilbert } 651082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 651178d4e5a0SDouglas Gilbert 651282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 65131da177e4SLinus Torvalds { 6514773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 65151da177e4SLinus Torvalds } 651682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 65171da177e4SLinus Torvalds 651882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6519c65b1445SDouglas Gilbert { 6520773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6521c65b1445SDouglas Gilbert } 652282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 652382069379SAkinobu Mita size_t count) 6524c65b1445SDouglas Gilbert { 6525c65b1445SDouglas Gilbert int n; 65260d01c5dfSDouglas Gilbert bool changed; 6527c65b1445SDouglas Gilbert 6528f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6529f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6530f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6531f0d1cf93SDouglas Gilbert 6532c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6533773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6534773642d9SDouglas Gilbert sdebug_virtual_gb = n; 653528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 65360d01c5dfSDouglas Gilbert if (changed) { 65370d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 65380d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 653928898873SFUJITA Tomonori 65404bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 65410d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 65420d01c5dfSDouglas Gilbert host_list) { 65430d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 65440d01c5dfSDouglas Gilbert dev_list) { 65450d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 65460d01c5dfSDouglas Gilbert dp->uas_bm); 65470d01c5dfSDouglas Gilbert } 65480d01c5dfSDouglas Gilbert } 65494bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 65500d01c5dfSDouglas Gilbert } 6551c65b1445SDouglas Gilbert return count; 6552c65b1445SDouglas Gilbert } 6553c65b1445SDouglas Gilbert return -EINVAL; 6554c65b1445SDouglas Gilbert } 655582069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6556c65b1445SDouglas Gilbert 655782069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 65581da177e4SLinus Torvalds { 655987c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 6560f19fe8f3SBart Van Assche return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 65611da177e4SLinus Torvalds } 65621da177e4SLinus Torvalds 656382069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 656482069379SAkinobu Mita size_t count) 65651da177e4SLinus Torvalds { 6566f19fe8f3SBart Van Assche bool found; 6567f19fe8f3SBart Van Assche unsigned long idx; 6568f19fe8f3SBart Van Assche struct sdeb_store_info *sip; 6569f19fe8f3SBart Van Assche bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 65701da177e4SLinus Torvalds int delta_hosts; 65711da177e4SLinus Torvalds 6572f19fe8f3SBart Van Assche if (sscanf(buf, "%d", &delta_hosts) != 1) 65731da177e4SLinus Torvalds return -EINVAL; 65741da177e4SLinus Torvalds if (delta_hosts > 0) { 65751da177e4SLinus Torvalds do { 6576f19fe8f3SBart Van Assche found = false; 6577f19fe8f3SBart Van Assche if (want_phs) { 6578f19fe8f3SBart Van Assche xa_for_each_marked(per_store_ap, idx, sip, 6579f19fe8f3SBart Van Assche SDEB_XA_NOT_IN_USE) { 6580f19fe8f3SBart Van Assche sdeb_most_recent_idx = (int)idx; 6581f19fe8f3SBart Van Assche found = true; 658287c715dcSDouglas Gilbert break; 658387c715dcSDouglas Gilbert } 6584f19fe8f3SBart Van Assche if (found) /* re-use case */ 6585f19fe8f3SBart Van Assche sdebug_add_host_helper((int)idx); 6586f19fe8f3SBart Van Assche else 6587f19fe8f3SBart Van Assche sdebug_do_add_host(true); 6588f19fe8f3SBart Van Assche } else { 6589f19fe8f3SBart Van Assche sdebug_do_add_host(false); 6590f19fe8f3SBart Van Assche } 6591f19fe8f3SBart Van Assche } while (--delta_hosts); 6592f19fe8f3SBart Van Assche } else if (delta_hosts < 0) { 6593f19fe8f3SBart Van Assche do { 659487c715dcSDouglas Gilbert sdebug_do_remove_host(false); 65951da177e4SLinus Torvalds } while (++delta_hosts); 65961da177e4SLinus Torvalds } 65971da177e4SLinus Torvalds return count; 65981da177e4SLinus Torvalds } 659982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 66001da177e4SLinus Torvalds 660182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 660223183910SDouglas Gilbert { 6603773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 660423183910SDouglas Gilbert } 660582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 660682069379SAkinobu Mita size_t count) 660723183910SDouglas Gilbert { 660823183910SDouglas Gilbert int n; 660923183910SDouglas Gilbert 661023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6611773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 661223183910SDouglas Gilbert return count; 661323183910SDouglas Gilbert } 661423183910SDouglas Gilbert return -EINVAL; 661523183910SDouglas Gilbert } 661682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 661723183910SDouglas Gilbert 6618c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6619c4837394SDouglas Gilbert { 6620c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6621c4837394SDouglas Gilbert } 6622c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6623c4837394SDouglas Gilbert size_t count) 6624c4837394SDouglas Gilbert { 6625c4837394SDouglas Gilbert int n; 6626c4837394SDouglas Gilbert 6627c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6628c4837394SDouglas Gilbert if (n > 0) 6629c4837394SDouglas Gilbert sdebug_statistics = true; 6630c4837394SDouglas Gilbert else { 6631c4837394SDouglas Gilbert clear_queue_stats(); 6632c4837394SDouglas Gilbert sdebug_statistics = false; 6633c4837394SDouglas Gilbert } 6634c4837394SDouglas Gilbert return count; 6635c4837394SDouglas Gilbert } 6636c4837394SDouglas Gilbert return -EINVAL; 6637c4837394SDouglas Gilbert } 6638c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6639c4837394SDouglas Gilbert 664082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6641597136abSMartin K. Petersen { 6642773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6643597136abSMartin K. Petersen } 664482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6645597136abSMartin K. Petersen 6646c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6647c4837394SDouglas Gilbert { 6648c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6649c4837394SDouglas Gilbert } 6650c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6651c4837394SDouglas Gilbert 665282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6653c6a44287SMartin K. Petersen { 6654773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6655c6a44287SMartin K. Petersen } 665682069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6657c6a44287SMartin K. Petersen 665882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6659c6a44287SMartin K. Petersen { 6660773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6661c6a44287SMartin K. Petersen } 666282069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6663c6a44287SMartin K. Petersen 666482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6665c6a44287SMartin K. Petersen { 6666773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6667c6a44287SMartin K. Petersen } 666882069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6669c6a44287SMartin K. Petersen 667082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6671c6a44287SMartin K. Petersen { 6672773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6673c6a44287SMartin K. Petersen } 667482069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6675c6a44287SMartin K. Petersen 667682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 667744d92694SMartin K. Petersen { 667887c715dcSDouglas Gilbert ssize_t count = 0; 667944d92694SMartin K. Petersen 66805b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 668144d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 668244d92694SMartin K. Petersen sdebug_store_sectors); 668344d92694SMartin K. Petersen 668487c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 668587c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 668687c715dcSDouglas Gilbert 668787c715dcSDouglas Gilbert if (sip) 6688c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 668987c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 669087c715dcSDouglas Gilbert } 669144d92694SMartin K. Petersen buf[count++] = '\n'; 6692c7badc90STejun Heo buf[count] = '\0'; 669344d92694SMartin K. Petersen 669444d92694SMartin K. Petersen return count; 669544d92694SMartin K. Petersen } 669682069379SAkinobu Mita static DRIVER_ATTR_RO(map); 669744d92694SMartin K. Petersen 66980c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 66990c4bc91dSDouglas Gilbert { 67000c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 67010c4bc91dSDouglas Gilbert } 67020c4bc91dSDouglas Gilbert 67030c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 67040c4bc91dSDouglas Gilbert size_t count) 67050c4bc91dSDouglas Gilbert { 67060c4bc91dSDouglas Gilbert bool v; 67070c4bc91dSDouglas Gilbert 67080c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 67090c4bc91dSDouglas Gilbert return -EINVAL; 67100c4bc91dSDouglas Gilbert 67110c4bc91dSDouglas Gilbert sdebug_random = v; 67120c4bc91dSDouglas Gilbert return count; 67130c4bc91dSDouglas Gilbert } 67140c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 67150c4bc91dSDouglas Gilbert 671682069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6717d986788bSMartin Pitt { 6718773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6719d986788bSMartin Pitt } 672082069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 672182069379SAkinobu Mita size_t count) 6722d986788bSMartin Pitt { 6723d986788bSMartin Pitt int n; 6724d986788bSMartin Pitt 6725d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6726773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6727d986788bSMartin Pitt return count; 6728d986788bSMartin Pitt } 6729d986788bSMartin Pitt return -EINVAL; 6730d986788bSMartin Pitt } 673182069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6732d986788bSMartin Pitt 6733cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6734cbf67842SDouglas Gilbert { 6735773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6736cbf67842SDouglas Gilbert } 6737185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6738cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6739cbf67842SDouglas Gilbert size_t count) 6740cbf67842SDouglas Gilbert { 6741185dd232SDouglas Gilbert int n; 6742cbf67842SDouglas Gilbert 6743cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6744185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6745185dd232SDouglas Gilbert return count; 6746cbf67842SDouglas Gilbert } 6747cbf67842SDouglas Gilbert return -EINVAL; 6748cbf67842SDouglas Gilbert } 6749cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6750cbf67842SDouglas Gilbert 6751c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6752c2248fc9SDouglas Gilbert { 6753773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6754c2248fc9SDouglas Gilbert } 6755c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6756c2248fc9SDouglas Gilbert size_t count) 6757c2248fc9SDouglas Gilbert { 6758c2248fc9SDouglas Gilbert int n; 6759c2248fc9SDouglas Gilbert 6760c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6761773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6762c2248fc9SDouglas Gilbert return count; 6763c2248fc9SDouglas Gilbert } 6764c2248fc9SDouglas Gilbert return -EINVAL; 6765c2248fc9SDouglas Gilbert } 6766c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6767c2248fc9SDouglas Gilbert 676809ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 676909ba24c1SDouglas Gilbert { 677009ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 677109ba24c1SDouglas Gilbert } 677209ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 677309ba24c1SDouglas Gilbert 67749b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 67759b760fd8SDouglas Gilbert { 67769b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 67779b760fd8SDouglas Gilbert } 67789b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 67799b760fd8SDouglas Gilbert size_t count) 67809b760fd8SDouglas Gilbert { 67819b760fd8SDouglas Gilbert int ret, n; 67829b760fd8SDouglas Gilbert 67839b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 67849b760fd8SDouglas Gilbert if (ret) 67859b760fd8SDouglas Gilbert return ret; 67869b760fd8SDouglas Gilbert sdebug_cdb_len = n; 67879b760fd8SDouglas Gilbert all_config_cdb_len(); 67889b760fd8SDouglas Gilbert return count; 67899b760fd8SDouglas Gilbert } 67909b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 67919b760fd8SDouglas Gilbert 67929267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 67939267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 67949267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 67959267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 67969267e0ebSDouglas Gilbert }; 67979267e0ebSDouglas Gilbert 67989267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 67999267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 68009267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 68019267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 68029267e0ebSDouglas Gilbert }; 68039267e0ebSDouglas Gilbert 68049267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 68059267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 68069267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 68079267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 68089267e0ebSDouglas Gilbert }; 68099267e0ebSDouglas Gilbert 68109267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 68119267e0ebSDouglas Gilbert { 68129267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 68139267e0ebSDouglas Gilbert 68149267e0ebSDouglas Gilbert if (res < 0) { 68159267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 68169267e0ebSDouglas Gilbert if (res < 0) { 68179267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 681847742bdeSDan Carpenter if (res < 0) 68199267e0ebSDouglas Gilbert return -EINVAL; 68209267e0ebSDouglas Gilbert } 68219267e0ebSDouglas Gilbert } 68229267e0ebSDouglas Gilbert return res; 68239267e0ebSDouglas Gilbert } 68249267e0ebSDouglas Gilbert 68259267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 68269267e0ebSDouglas Gilbert { 68279267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 68289267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 68299267e0ebSDouglas Gilbert } 68309267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6831cbf67842SDouglas Gilbert 6832fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6833fc13638aSDouglas Gilbert { 6834fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6835fc13638aSDouglas Gilbert } 6836fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6837fc13638aSDouglas Gilbert 683882069379SAkinobu Mita /* Note: The following array creates attribute files in the 683923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 684023183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 684123183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 684287c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 684323183910SDouglas Gilbert */ 68446ecaff7fSRandy Dunlap 684582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 684682069379SAkinobu Mita &driver_attr_delay.attr, 684782069379SAkinobu Mita &driver_attr_opts.attr, 684882069379SAkinobu Mita &driver_attr_ptype.attr, 684982069379SAkinobu Mita &driver_attr_dsense.attr, 685082069379SAkinobu Mita &driver_attr_fake_rw.attr, 6851c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 685282069379SAkinobu Mita &driver_attr_no_lun_0.attr, 685382069379SAkinobu Mita &driver_attr_num_tgts.attr, 685482069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 685582069379SAkinobu Mita &driver_attr_num_parts.attr, 685682069379SAkinobu Mita &driver_attr_every_nth.attr, 6857ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 685882069379SAkinobu Mita &driver_attr_max_luns.attr, 685982069379SAkinobu Mita &driver_attr_max_queue.attr, 68607109f370SDouglas Gilbert &driver_attr_no_rwlock.attr, 686182069379SAkinobu Mita &driver_attr_no_uld.attr, 686282069379SAkinobu Mita &driver_attr_scsi_level.attr, 686382069379SAkinobu Mita &driver_attr_virtual_gb.attr, 686482069379SAkinobu Mita &driver_attr_add_host.attr, 686587c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 686682069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 686782069379SAkinobu Mita &driver_attr_sector_size.attr, 6868c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6869c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 687082069379SAkinobu Mita &driver_attr_dix.attr, 687182069379SAkinobu Mita &driver_attr_dif.attr, 687282069379SAkinobu Mita &driver_attr_guard.attr, 687382069379SAkinobu Mita &driver_attr_ato.attr, 687482069379SAkinobu Mita &driver_attr_map.attr, 68750c4bc91dSDouglas Gilbert &driver_attr_random.attr, 687682069379SAkinobu Mita &driver_attr_removable.attr, 6877cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6878cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6879c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 688009ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 68819b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6882fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 68839267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 688482069379SAkinobu Mita NULL, 688582069379SAkinobu Mita }; 688682069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 68871da177e4SLinus Torvalds 688811ddcecaSAkinobu Mita static struct device *pseudo_primary; 68898dea0d02SFUJITA Tomonori 68901da177e4SLinus Torvalds static int __init scsi_debug_init(void) 68911da177e4SLinus Torvalds { 689287c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 68935f2578e5SFUJITA Tomonori unsigned long sz; 689487c715dcSDouglas Gilbert int k, ret, hosts_to_add; 689587c715dcSDouglas Gilbert int idx = -1; 68961da177e4SLinus Torvalds 689787c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 689887c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6899cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6900cbf67842SDouglas Gilbert 6901773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6902c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6903773642d9SDouglas Gilbert sdebug_ndelay = 0; 6904773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6905c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6906cbf67842SDouglas Gilbert 6907773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6908597136abSMartin K. Petersen case 512: 6909597136abSMartin K. Petersen case 1024: 6910597136abSMartin K. Petersen case 2048: 6911597136abSMartin K. Petersen case 4096: 6912597136abSMartin K. Petersen break; 6913597136abSMartin K. Petersen default: 6914773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6915597136abSMartin K. Petersen return -EINVAL; 6916597136abSMartin K. Petersen } 6917597136abSMartin K. Petersen 6918773642d9SDouglas Gilbert switch (sdebug_dif) { 69198475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6920f46eb0e9SDouglas Gilbert break; 69218475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 69228475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 69238475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6924f46eb0e9SDouglas Gilbert have_dif_prot = true; 6925c6a44287SMartin K. Petersen break; 6926c6a44287SMartin K. Petersen 6927c6a44287SMartin K. Petersen default: 6928c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6929c6a44287SMartin K. Petersen return -EINVAL; 6930c6a44287SMartin K. Petersen } 6931c6a44287SMartin K. Petersen 6932aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6933aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6934aa5334c4SMaurizio Lombardi return -EINVAL; 6935aa5334c4SMaurizio Lombardi } 6936aa5334c4SMaurizio Lombardi 6937773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6938c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6939c6a44287SMartin K. Petersen return -EINVAL; 6940c6a44287SMartin K. Petersen } 6941c6a44287SMartin K. Petersen 6942773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6943c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6944c6a44287SMartin K. Petersen return -EINVAL; 6945c6a44287SMartin K. Petersen } 6946c6a44287SMartin K. Petersen 6947773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6948773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6949ea61fca5SMartin K. Petersen return -EINVAL; 6950ea61fca5SMartin K. Petersen } 6951ad0c7775SDouglas Gilbert 6952ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6953ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6954ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6955ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6956ad0c7775SDouglas Gilbert } 6957ad0c7775SDouglas Gilbert 69588d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6959ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6960ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 69618d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 69628d039e22SDouglas Gilbert } 6963ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6964ad0c7775SDouglas Gilbert } 6965ea61fca5SMartin K. Petersen 6966773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6967773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6968ea61fca5SMartin K. Petersen return -EINVAL; 6969ea61fca5SMartin K. Petersen } 6970ea61fca5SMartin K. Petersen 6971c4837394SDouglas Gilbert if (submit_queues < 1) { 6972c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6973c4837394SDouglas Gilbert return -EINVAL; 6974c4837394SDouglas Gilbert } 6975c87bf24cSJohn Garry 6976c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6977c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6978c87bf24cSJohn Garry return -EINVAL; 6979c87bf24cSJohn Garry } 6980c87bf24cSJohn Garry 6981c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6982c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6983c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6984c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6985c10fa55fSJohn Garry return -EINVAL; 6986c10fa55fSJohn Garry } 6987c10fa55fSJohn Garry 6988c10fa55fSJohn Garry if (sdebug_host_max_queue && 6989c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6990c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6991c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6992c10fa55fSJohn Garry sdebug_max_queue); 6993c10fa55fSJohn Garry } 6994c10fa55fSJohn Garry 6995c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6996c4837394SDouglas Gilbert GFP_KERNEL); 6997c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6998c4837394SDouglas Gilbert return -ENOMEM; 6999c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 7000c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 7001c4837394SDouglas Gilbert 7002f0d1cf93SDouglas Gilbert /* 70039267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 70049267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 7005f0d1cf93SDouglas Gilbert */ 70069267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 70079267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 70089267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 70099267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 70109267e0ebSDouglas Gilbert if (k < 0) { 70119267e0ebSDouglas Gilbert ret = k; 70123b01d7eaSDinghao Liu goto free_q_arr; 70139267e0ebSDouglas Gilbert } 70149267e0ebSDouglas Gilbert sdeb_zbc_model = k; 70159267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 70169267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 701764e14eceSDamien Le Moal case BLK_ZONED_HA: 70189267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 70199267e0ebSDouglas Gilbert break; 70209267e0ebSDouglas Gilbert case BLK_ZONED_HM: 70219267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 70229267e0ebSDouglas Gilbert break; 70239267e0ebSDouglas Gilbert default: 70249267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 70253b01d7eaSDinghao Liu ret = -EINVAL; 70263b01d7eaSDinghao Liu goto free_q_arr; 70279267e0ebSDouglas Gilbert } 70289267e0ebSDouglas Gilbert } 70299267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 7030f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 70319267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70329267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 70339267e0ebSDouglas Gilbert } 7034f0d1cf93SDouglas Gilbert 70359267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70369267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 7037773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 7038773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 7039773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 7040773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 704128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 70421da177e4SLinus Torvalds 70431da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 70441da177e4SLinus Torvalds sdebug_heads = 8; 70451da177e4SLinus Torvalds sdebug_sectors_per = 32; 7046773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 70471da177e4SLinus Torvalds sdebug_heads = 64; 7048773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 7049fa785f0aSAndy Shevchenko sdebug_heads = 32; 70501da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70511da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70521da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 70531da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 70541da177e4SLinus Torvalds sdebug_heads = 255; 70551da177e4SLinus Torvalds sdebug_sectors_per = 63; 70561da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70571da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70581da177e4SLinus Torvalds } 70595b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 7060773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 7061773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 70626014759cSMartin K. Petersen 7063773642d9SDouglas Gilbert sdebug_unmap_max_desc = 7064773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 70656014759cSMartin K. Petersen 7066773642d9SDouglas Gilbert sdebug_unmap_granularity = 7067773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 70686014759cSMartin K. Petersen 7069773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 7070773642d9SDouglas Gilbert sdebug_unmap_granularity <= 7071773642d9SDouglas Gilbert sdebug_unmap_alignment) { 7072c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 7073c4837394SDouglas Gilbert ret = -EINVAL; 707487c715dcSDouglas Gilbert goto free_q_arr; 707544d92694SMartin K. Petersen } 707644d92694SMartin K. Petersen } 707787c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 707887c715dcSDouglas Gilbert if (want_store) { 707987c715dcSDouglas Gilbert idx = sdebug_add_store(); 708087c715dcSDouglas Gilbert if (idx < 0) { 708187c715dcSDouglas Gilbert ret = idx; 708287c715dcSDouglas Gilbert goto free_q_arr; 708387c715dcSDouglas Gilbert } 708444d92694SMartin K. Petersen } 708544d92694SMartin K. Petersen 70869b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 70879b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 7088c1287970STomas Winkler pr_warn("root_device_register() error\n"); 70899b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 70906ecaff7fSRandy Dunlap goto free_vm; 70916ecaff7fSRandy Dunlap } 70926ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 70936ecaff7fSRandy Dunlap if (ret < 0) { 7094c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 70956ecaff7fSRandy Dunlap goto dev_unreg; 70966ecaff7fSRandy Dunlap } 70976ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 70986ecaff7fSRandy Dunlap if (ret < 0) { 7099c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 71006ecaff7fSRandy Dunlap goto bus_unreg; 71016ecaff7fSRandy Dunlap } 71021da177e4SLinus Torvalds 710387c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 7104773642d9SDouglas Gilbert sdebug_add_host = 0; 71051da177e4SLinus Torvalds 710687c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 710787c715dcSDouglas Gilbert if (want_store && k == 0) { 710887c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 710987c715dcSDouglas Gilbert if (ret < 0) { 711087c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 711187c715dcSDouglas Gilbert k, -ret); 711287c715dcSDouglas Gilbert break; 711387c715dcSDouglas Gilbert } 711487c715dcSDouglas Gilbert } else { 711587c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 711687c715dcSDouglas Gilbert sdebug_per_host_store); 711787c715dcSDouglas Gilbert if (ret < 0) { 711887c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 71191da177e4SLinus Torvalds break; 71201da177e4SLinus Torvalds } 71211da177e4SLinus Torvalds } 712287c715dcSDouglas Gilbert } 7123773642d9SDouglas Gilbert if (sdebug_verbose) 7124f19fe8f3SBart Van Assche pr_info("built %d host(s)\n", sdebug_num_hosts); 7125c1287970STomas Winkler 71261da177e4SLinus Torvalds return 0; 71276ecaff7fSRandy Dunlap 71286ecaff7fSRandy Dunlap bus_unreg: 71296ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 71306ecaff7fSRandy Dunlap dev_unreg: 71319b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71326ecaff7fSRandy Dunlap free_vm: 713387c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 7134c4837394SDouglas Gilbert free_q_arr: 7135c4837394SDouglas Gilbert kfree(sdebug_q_arr); 71366ecaff7fSRandy Dunlap return ret; 71371da177e4SLinus Torvalds } 71381da177e4SLinus Torvalds 71391da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 71401da177e4SLinus Torvalds { 7141f19fe8f3SBart Van Assche int k = sdebug_num_hosts; 71421da177e4SLinus Torvalds 7143f19fe8f3SBart Van Assche stop_all_queued(); 7144f19fe8f3SBart Van Assche for (; k; k--) 714587c715dcSDouglas Gilbert sdebug_do_remove_host(true); 714652ab9768SLuis Henriques free_all_queued(); 71471da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 71481da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 71499b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71501da177e4SLinus Torvalds 715187c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 715287c715dcSDouglas Gilbert xa_destroy(per_store_ap); 7153f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 71541da177e4SLinus Torvalds } 71551da177e4SLinus Torvalds 71561da177e4SLinus Torvalds device_initcall(scsi_debug_init); 71571da177e4SLinus Torvalds module_exit(scsi_debug_exit); 71581da177e4SLinus Torvalds 71591da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 71601da177e4SLinus Torvalds { 71611da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71621da177e4SLinus Torvalds 71631da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 71641da177e4SLinus Torvalds kfree(sdbg_host); 71651da177e4SLinus Torvalds } 71661da177e4SLinus Torvalds 716787c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 716887c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 71691da177e4SLinus Torvalds { 717087c715dcSDouglas Gilbert if (idx < 0) 717187c715dcSDouglas Gilbert return; 717287c715dcSDouglas Gilbert if (!sip) { 717387c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 717487c715dcSDouglas Gilbert return; 717587c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 717687c715dcSDouglas Gilbert if (!sip) 717787c715dcSDouglas Gilbert return; 717887c715dcSDouglas Gilbert } 717987c715dcSDouglas Gilbert vfree(sip->map_storep); 718087c715dcSDouglas Gilbert vfree(sip->dif_storep); 718187c715dcSDouglas Gilbert vfree(sip->storep); 718287c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 718387c715dcSDouglas Gilbert kfree(sip); 718487c715dcSDouglas Gilbert } 718587c715dcSDouglas Gilbert 718687c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 718787c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 718887c715dcSDouglas Gilbert { 718987c715dcSDouglas Gilbert unsigned long idx; 719087c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 719187c715dcSDouglas Gilbert 719287c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 719387c715dcSDouglas Gilbert if (apart_from_first) 719487c715dcSDouglas Gilbert apart_from_first = false; 719587c715dcSDouglas Gilbert else 719687c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 719787c715dcSDouglas Gilbert } 719887c715dcSDouglas Gilbert if (apart_from_first) 719987c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 720087c715dcSDouglas Gilbert } 720187c715dcSDouglas Gilbert 720287c715dcSDouglas Gilbert /* 720387c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 720487c715dcSDouglas Gilbert * Limit the number of stores to 65536. 720587c715dcSDouglas Gilbert */ 720687c715dcSDouglas Gilbert static int sdebug_add_store(void) 720787c715dcSDouglas Gilbert { 720887c715dcSDouglas Gilbert int res; 720987c715dcSDouglas Gilbert u32 n_idx; 721087c715dcSDouglas Gilbert unsigned long iflags; 721187c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 721287c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 721387c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 721487c715dcSDouglas Gilbert 721587c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 721687c715dcSDouglas Gilbert if (!sip) 721787c715dcSDouglas Gilbert return -ENOMEM; 721887c715dcSDouglas Gilbert 721987c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 722087c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 722187c715dcSDouglas Gilbert if (unlikely(res < 0)) { 722287c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 722387c715dcSDouglas Gilbert kfree(sip); 722487c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 722587c715dcSDouglas Gilbert return res; 722687c715dcSDouglas Gilbert } 722787c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 722887c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 722987c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 723087c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 723187c715dcSDouglas Gilbert 723287c715dcSDouglas Gilbert res = -ENOMEM; 723387c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 723487c715dcSDouglas Gilbert if (!sip->storep) { 723587c715dcSDouglas Gilbert pr_err("user data oom\n"); 723687c715dcSDouglas Gilbert goto err; 723787c715dcSDouglas Gilbert } 723887c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 723987c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 724087c715dcSDouglas Gilbert 724187c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 724287c715dcSDouglas Gilbert if (sdebug_dix) { 724387c715dcSDouglas Gilbert int dif_size; 724487c715dcSDouglas Gilbert 724587c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 724687c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 724787c715dcSDouglas Gilbert 724887c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 724987c715dcSDouglas Gilbert sip->dif_storep); 725087c715dcSDouglas Gilbert 725187c715dcSDouglas Gilbert if (!sip->dif_storep) { 725287c715dcSDouglas Gilbert pr_err("DIX oom\n"); 725387c715dcSDouglas Gilbert goto err; 725487c715dcSDouglas Gilbert } 725587c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 725687c715dcSDouglas Gilbert } 725787c715dcSDouglas Gilbert /* Logical Block Provisioning */ 725887c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 725987c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 726087c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 726187c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 726287c715dcSDouglas Gilbert 726387c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 726487c715dcSDouglas Gilbert 726587c715dcSDouglas Gilbert if (!sip->map_storep) { 726687c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 726787c715dcSDouglas Gilbert goto err; 726887c715dcSDouglas Gilbert } 726987c715dcSDouglas Gilbert 727087c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 727187c715dcSDouglas Gilbert 727287c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 727387c715dcSDouglas Gilbert if (sdebug_num_parts) 727487c715dcSDouglas Gilbert map_region(sip, 0, 2); 727587c715dcSDouglas Gilbert } 727687c715dcSDouglas Gilbert 727787c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 727887c715dcSDouglas Gilbert return (int)n_idx; 727987c715dcSDouglas Gilbert err: 728087c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 728187c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 728287c715dcSDouglas Gilbert return res; 728387c715dcSDouglas Gilbert } 728487c715dcSDouglas Gilbert 728587c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 728687c715dcSDouglas Gilbert { 728787c715dcSDouglas Gilbert int k, devs_per_host, idx; 728887c715dcSDouglas Gilbert int error = -ENOMEM; 72891da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72908b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 72911da177e4SLinus Torvalds 729224669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 729387c715dcSDouglas Gilbert if (!sdbg_host) 72941da177e4SLinus Torvalds return -ENOMEM; 729587c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 729687c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 729787c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 729887c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 72991da177e4SLinus Torvalds 73001da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 73011da177e4SLinus Torvalds 7302773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 73031da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 73045cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 730587c715dcSDouglas Gilbert if (!sdbg_devinfo) 73061da177e4SLinus Torvalds goto clean; 73071da177e4SLinus Torvalds } 73081da177e4SLinus Torvalds 73091da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73101da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 73111da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73121da177e4SLinus Torvalds 73131da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 73149b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 73151da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 7316f19fe8f3SBart Van Assche dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 73171da177e4SLinus Torvalds 73181da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 73191da177e4SLinus Torvalds if (error) 73201da177e4SLinus Torvalds goto clean; 73211da177e4SLinus Torvalds 7322f19fe8f3SBart Van Assche ++sdebug_num_hosts; 732387c715dcSDouglas Gilbert return 0; 73241da177e4SLinus Torvalds 73251da177e4SLinus Torvalds clean: 73268b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 73278b40228fSFUJITA Tomonori dev_list) { 73281da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7329f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 73301da177e4SLinus Torvalds kfree(sdbg_devinfo); 73311da177e4SLinus Torvalds } 73321da177e4SLinus Torvalds kfree(sdbg_host); 733387c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 73341da177e4SLinus Torvalds return error; 73351da177e4SLinus Torvalds } 73361da177e4SLinus Torvalds 733787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 73381da177e4SLinus Torvalds { 733987c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 734087c715dcSDouglas Gilbert 734187c715dcSDouglas Gilbert if (mk_new_store) { 734287c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 734387c715dcSDouglas Gilbert if (ph_idx < 0) 734487c715dcSDouglas Gilbert return ph_idx; 734587c715dcSDouglas Gilbert } 734687c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 734787c715dcSDouglas Gilbert } 734887c715dcSDouglas Gilbert 734987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 735087c715dcSDouglas Gilbert { 735187c715dcSDouglas Gilbert int idx = -1; 73521da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 735387c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 73541da177e4SLinus Torvalds 73551da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 73561da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 73571da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 73581da177e4SLinus Torvalds struct sdebug_host_info, host_list); 735987c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 73601da177e4SLinus Torvalds } 736187c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 736287c715dcSDouglas Gilbert bool unique = true; 736387c715dcSDouglas Gilbert 736487c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 736587c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 736687c715dcSDouglas Gilbert continue; 736787c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 736887c715dcSDouglas Gilbert unique = false; 736987c715dcSDouglas Gilbert break; 737087c715dcSDouglas Gilbert } 737187c715dcSDouglas Gilbert } 737287c715dcSDouglas Gilbert if (unique) { 737387c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 737487c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 737587c715dcSDouglas Gilbert --sdeb_most_recent_idx; 737687c715dcSDouglas Gilbert } 737787c715dcSDouglas Gilbert } 737887c715dcSDouglas Gilbert if (sdbg_host) 737987c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 73801da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 73811da177e4SLinus Torvalds 73821da177e4SLinus Torvalds if (!sdbg_host) 73831da177e4SLinus Torvalds return; 73841da177e4SLinus Torvalds 73851da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 7386f19fe8f3SBart Van Assche --sdebug_num_hosts; 73871da177e4SLinus Torvalds } 73881da177e4SLinus Torvalds 7389fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7390cbf67842SDouglas Gilbert { 7391cbf67842SDouglas Gilbert int num_in_q = 0; 7392cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7393cbf67842SDouglas Gilbert 7394f19fe8f3SBart Van Assche block_unblock_all_queues(true); 7395cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7396cbf67842SDouglas Gilbert if (NULL == devip) { 7397f19fe8f3SBart Van Assche block_unblock_all_queues(false); 7398cbf67842SDouglas Gilbert return -ENODEV; 7399cbf67842SDouglas Gilbert } 7400cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7401c40ecc12SChristoph Hellwig 7402fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7403fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7404fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7405fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7406fc09acb7SDouglas Gilbert } 7407cbf67842SDouglas Gilbert if (qdepth < 1) 7408cbf67842SDouglas Gilbert qdepth = 1; 7409fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7410db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7411cbf67842SDouglas Gilbert 7412773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7413c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7414c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7415cbf67842SDouglas Gilbert } 7416f19fe8f3SBart Van Assche block_unblock_all_queues(false); 7417cbf67842SDouglas Gilbert return sdev->queue_depth; 7418cbf67842SDouglas Gilbert } 7419cbf67842SDouglas Gilbert 7420c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7421817fd66bSDouglas Gilbert { 7422c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7423773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7424773642d9SDouglas Gilbert sdebug_every_nth = -1; 7425773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7426c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7427773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7428817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7429c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7430817fd66bSDouglas Gilbert } 7431c4837394SDouglas Gilbert return false; 7432817fd66bSDouglas Gilbert } 7433817fd66bSDouglas Gilbert 7434fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7435fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7436fc13638aSDouglas Gilbert { 7437fc13638aSDouglas Gilbert int stopped_state; 7438fc13638aSDouglas Gilbert u64 diff_ns = 0; 7439fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7440fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7441fc13638aSDouglas Gilbert 7442fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7443fc13638aSDouglas Gilbert if (stopped_state == 2) { 7444fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7445fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7446fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7447fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7448fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7449fc13638aSDouglas Gilbert return 0; 7450fc13638aSDouglas Gilbert } 7451fc13638aSDouglas Gilbert } 7452fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7453fc13638aSDouglas Gilbert if (sdebug_verbose) 7454fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7455fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7456fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7457fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7458fc13638aSDouglas Gilbert 7459fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7460fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7461fc13638aSDouglas Gilbert else 7462fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7463fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7464fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7465fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7466fc13638aSDouglas Gilbert diff_ns); 7467fc13638aSDouglas Gilbert return check_condition_result; 7468fc13638aSDouglas Gilbert } 7469fc13638aSDouglas Gilbert } 7470fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7471fc13638aSDouglas Gilbert if (sdebug_verbose) 7472fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7473fc13638aSDouglas Gilbert my_name); 7474fc13638aSDouglas Gilbert return check_condition_result; 7475fc13638aSDouglas Gilbert } 7476fc13638aSDouglas Gilbert 7477a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost) 7478c4b57d89SKashyap Desai { 7479c4b57d89SKashyap Desai int i, qoff; 7480c4b57d89SKashyap Desai 7481c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7482a4e1d0b7SBart Van Assche return; 7483c4b57d89SKashyap Desai 7484c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7485c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7486c4b57d89SKashyap Desai 7487c4b57d89SKashyap Desai map->nr_queues = 0; 7488c4b57d89SKashyap Desai 7489c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7490c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7491c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7492c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7493c4b57d89SKashyap Desai 7494c4b57d89SKashyap Desai if (!map->nr_queues) { 7495c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7496c4b57d89SKashyap Desai continue; 7497c4b57d89SKashyap Desai } 7498c4b57d89SKashyap Desai 7499c4b57d89SKashyap Desai map->queue_offset = qoff; 7500c4b57d89SKashyap Desai blk_mq_map_queues(map); 7501c4b57d89SKashyap Desai 7502c4b57d89SKashyap Desai qoff += map->nr_queues; 7503c4b57d89SKashyap Desai } 7504c4b57d89SKashyap Desai } 7505c4b57d89SKashyap Desai 7506c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7507c4b57d89SKashyap Desai { 75084a0c6f43SDouglas Gilbert bool first; 75094a0c6f43SDouglas Gilbert bool retiring = false; 75104a0c6f43SDouglas Gilbert int num_entries = 0; 75114a0c6f43SDouglas Gilbert unsigned int qc_idx = 0; 7512c4b57d89SKashyap Desai unsigned long iflags; 75134a0c6f43SDouglas Gilbert ktime_t kt_from_boot = ktime_get_boottime(); 7514c4b57d89SKashyap Desai struct sdebug_queue *sqp; 7515c4b57d89SKashyap Desai struct sdebug_queued_cmd *sqcp; 7516c4b57d89SKashyap Desai struct scsi_cmnd *scp; 7517c4b57d89SKashyap Desai struct sdebug_dev_info *devip; 75184a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7519c4b57d89SKashyap Desai 7520c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 75214a0c6f43SDouglas Gilbert 7522c4b57d89SKashyap Desai spin_lock_irqsave(&sqp->qc_lock, iflags); 75234a0c6f43SDouglas Gilbert 75246a0d0ae3SDamien Le Moal qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 75256a0d0ae3SDamien Le Moal if (qc_idx >= sdebug_max_queue) 75266a0d0ae3SDamien Le Moal goto unlock; 75276a0d0ae3SDamien Le Moal 75284a0c6f43SDouglas Gilbert for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { 75294a0c6f43SDouglas Gilbert if (first) { 75304a0c6f43SDouglas Gilbert first = false; 7531b05d4e48SDouglas Gilbert if (!test_bit(qc_idx, sqp->in_use_bm)) 7532b05d4e48SDouglas Gilbert continue; 75334a0c6f43SDouglas Gilbert } else { 75344a0c6f43SDouglas Gilbert qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1); 75354a0c6f43SDouglas Gilbert } 7536b05d4e48SDouglas Gilbert if (qc_idx >= sdebug_max_queue) 75374a0c6f43SDouglas Gilbert break; 7538c4b57d89SKashyap Desai 7539c4b57d89SKashyap Desai sqcp = &sqp->qc_arr[qc_idx]; 75404a0c6f43SDouglas Gilbert sd_dp = sqcp->sd_dp; 75414a0c6f43SDouglas Gilbert if (unlikely(!sd_dp)) 75424a0c6f43SDouglas Gilbert continue; 7543c4b57d89SKashyap Desai scp = sqcp->a_cmnd; 7544c4b57d89SKashyap Desai if (unlikely(scp == NULL)) { 75454a0c6f43SDouglas Gilbert pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n", 7546c4b57d89SKashyap Desai queue_num, qc_idx, __func__); 75474a0c6f43SDouglas Gilbert break; 7548c4b57d89SKashyap Desai } 7549d9d23a5aSDouglas Gilbert if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) { 75504a0c6f43SDouglas Gilbert if (kt_from_boot < sd_dp->cmpl_ts) 75514a0c6f43SDouglas Gilbert continue; 75524a0c6f43SDouglas Gilbert 75536ce913feSChristoph Hellwig } else /* ignoring non REQ_POLLED requests */ 75544a0c6f43SDouglas Gilbert continue; 7555c4b57d89SKashyap Desai devip = (struct sdebug_dev_info *)scp->device->hostdata; 7556c4b57d89SKashyap Desai if (likely(devip)) 7557c4b57d89SKashyap Desai atomic_dec(&devip->num_in_q); 7558c4b57d89SKashyap Desai else 7559c4b57d89SKashyap Desai pr_err("devip=NULL from %s\n", __func__); 7560c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 75614a0c6f43SDouglas Gilbert retiring = true; 7562c4b57d89SKashyap Desai 7563c4b57d89SKashyap Desai sqcp->a_cmnd = NULL; 7564c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 75654a0c6f43SDouglas Gilbert pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n", 7566c4b57d89SKashyap Desai sqp, queue_num, qc_idx, __func__); 75674a0c6f43SDouglas Gilbert break; 7568c4b57d89SKashyap Desai } 7569c4b57d89SKashyap Desai if (unlikely(retiring)) { /* user has reduced max_queue */ 7570c4b57d89SKashyap Desai int k, retval; 7571c4b57d89SKashyap Desai 7572c4b57d89SKashyap Desai retval = atomic_read(&retired_max_queue); 7573c4b57d89SKashyap Desai if (qc_idx >= retval) { 7574c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 75754a0c6f43SDouglas Gilbert break; 7576c4b57d89SKashyap Desai } 7577c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7578c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7579c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7580c4b57d89SKashyap Desai else 7581c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7582c4b57d89SKashyap Desai } 7583d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 7584c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 75856c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 7586c4b57d89SKashyap Desai num_entries++; 75873fd07aecSDamien Le Moal spin_lock_irqsave(&sqp->qc_lock, iflags); 7588b05d4e48SDouglas Gilbert if (find_first_bit(sqp->in_use_bm, sdebug_max_queue) >= sdebug_max_queue) 75893fd07aecSDamien Le Moal break; 75904a0c6f43SDouglas Gilbert } 75913fd07aecSDamien Le Moal 75926a0d0ae3SDamien Le Moal unlock: 7593c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 75943fd07aecSDamien Le Moal 75954a0c6f43SDouglas Gilbert if (num_entries > 0) 75964a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7597c4b57d89SKashyap Desai return num_entries; 7598c4b57d89SKashyap Desai } 7599c4b57d89SKashyap Desai 7600fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7601fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7602c2248fc9SDouglas Gilbert { 7603c2248fc9SDouglas Gilbert u8 sdeb_i; 7604c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7605c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7606c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7607c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7608c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7609c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7610f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7611c2248fc9SDouglas Gilbert int k, na; 7612c2248fc9SDouglas Gilbert int errsts = 0; 7613ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7614c2248fc9SDouglas Gilbert u32 flags; 7615c2248fc9SDouglas Gilbert u16 sa; 7616c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7617c2248fc9SDouglas Gilbert bool has_wlun_rl; 76183a90a63dSDouglas Gilbert bool inject_now; 7619c2248fc9SDouglas Gilbert 7620c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 76213a90a63dSDouglas Gilbert if (sdebug_statistics) { 7622c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 76233a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 76243a90a63dSDouglas Gilbert } else { 76253a90a63dSDouglas Gilbert inject_now = false; 76263a90a63dSDouglas Gilbert } 7627f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7628f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7629c2248fc9SDouglas Gilbert char b[120]; 7630c2248fc9SDouglas Gilbert int n, len, sb; 7631c2248fc9SDouglas Gilbert 7632c2248fc9SDouglas Gilbert len = scp->cmd_len; 7633c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7634c2248fc9SDouglas Gilbert if (len > 32) 7635c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7636c2248fc9SDouglas Gilbert else { 7637c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7638c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7639c2248fc9SDouglas Gilbert (u32)cmd[k]); 7640c2248fc9SDouglas Gilbert } 7641458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7642a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7643c2248fc9SDouglas Gilbert } 76443a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 76457ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 764634d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7647ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7648f46eb0e9SDouglas Gilbert goto err_out; 7649c2248fc9SDouglas Gilbert 7650c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7651c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7652c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7653f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7654f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7655c2248fc9SDouglas Gilbert if (NULL == devip) 7656f46eb0e9SDouglas Gilbert goto err_out; 7657c2248fc9SDouglas Gilbert } 76583a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 76593a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 76603a90a63dSDouglas Gilbert 7661c2248fc9SDouglas Gilbert na = oip->num_attached; 7662c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7663c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7664c2248fc9SDouglas Gilbert r_oip = oip; 7665c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7666c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7667c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7668c2248fc9SDouglas Gilbert else 7669c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7670c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7671c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7672c2248fc9SDouglas Gilbert break; 7673c2248fc9SDouglas Gilbert } 7674c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7675c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7676c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7677c2248fc9SDouglas Gilbert break; 7678c2248fc9SDouglas Gilbert } 7679c2248fc9SDouglas Gilbert } 7680c2248fc9SDouglas Gilbert if (k > na) { 7681c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7682c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7683c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7684c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7685c2248fc9SDouglas Gilbert else 7686c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7687c2248fc9SDouglas Gilbert goto check_cond; 7688c2248fc9SDouglas Gilbert } 7689c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7690c2248fc9SDouglas Gilbert flags = oip->flags; 7691f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7692c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7693c2248fc9SDouglas Gilbert goto check_cond; 7694c2248fc9SDouglas Gilbert } 7695f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7696773642d9SDouglas Gilbert if (sdebug_verbose) 7697773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7698773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7699c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7700c2248fc9SDouglas Gilbert goto check_cond; 7701c2248fc9SDouglas Gilbert } 7702f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7703c2248fc9SDouglas Gilbert u8 rem; 7704c2248fc9SDouglas Gilbert int j; 7705c2248fc9SDouglas Gilbert 7706c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7707c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7708c2248fc9SDouglas Gilbert if (rem) { 7709c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7710c2248fc9SDouglas Gilbert if (0x80 & rem) 7711c2248fc9SDouglas Gilbert break; 7712c2248fc9SDouglas Gilbert } 7713c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7714c2248fc9SDouglas Gilbert goto check_cond; 7715c2248fc9SDouglas Gilbert } 7716c2248fc9SDouglas Gilbert } 7717c2248fc9SDouglas Gilbert } 7718f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7719b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7720b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7721f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7722c2248fc9SDouglas Gilbert if (errsts) 7723c2248fc9SDouglas Gilbert goto check_cond; 7724c2248fc9SDouglas Gilbert } 7725fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7726fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7727fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7728fc13638aSDouglas Gilbert if (errsts) 7729c2248fc9SDouglas Gilbert goto fini; 7730c2248fc9SDouglas Gilbert } 7731773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7732c2248fc9SDouglas Gilbert goto fini; 7733f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7734c4837394SDouglas Gilbert if (fake_timeout(scp)) 7735c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7736c2248fc9SDouglas Gilbert } 7737f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7738f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7739f66b8517SMartin Wilck else 7740f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7741c2248fc9SDouglas Gilbert 7742c2248fc9SDouglas Gilbert fini: 774367da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7744f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 774575aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 774675aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 774780c49563SDouglas Gilbert /* 774875aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 774975aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 775075aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 775175aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 775280c49563SDouglas Gilbert */ 775380c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 77544f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 775580c49563SDouglas Gilbert 77564f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7757f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 775880c49563SDouglas Gilbert } else 7759f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 776010bde980SDouglas Gilbert sdebug_ndelay); 7761c2248fc9SDouglas Gilbert check_cond: 7762f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7763f46eb0e9SDouglas Gilbert err_out: 7764f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7765c2248fc9SDouglas Gilbert } 7766c2248fc9SDouglas Gilbert 77679e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7768c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7769c8ed555aSAl Viro .write_info = scsi_debug_write_info, 77709e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 77719e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 77729e603ca0SFUJITA Tomonori .info = scsi_debug_info, 77739e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 77749e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 77759e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 77769e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7777185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7778cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7779c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7780c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 77819e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 77829e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7783cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7784cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 77859e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7786c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 77879e603ca0SFUJITA Tomonori .this_id = 7, 778865e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7789cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 77906bb5e6e7SAkinobu Mita .max_sectors = -1U, 779150c2e910SChristoph Hellwig .max_segment_size = -1U, 77929e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7793c40ecc12SChristoph Hellwig .track_queue_depth = 1, 77949e603ca0SFUJITA Tomonori }; 77959e603ca0SFUJITA Tomonori 77961da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 77971da177e4SLinus Torvalds { 77981da177e4SLinus Torvalds int error = 0; 77991da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 78001da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7801f46eb0e9SDouglas Gilbert int hprot; 78021da177e4SLinus Torvalds 78031da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 78041da177e4SLinus Torvalds 7805773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7806fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 78072a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 78084af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 78094af14d11SChristoph Hellwig 78101da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 78111da177e4SLinus Torvalds if (NULL == hpnt) { 7812c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 78131da177e4SLinus Torvalds error = -ENODEV; 78141da177e4SLinus Torvalds return error; 78151da177e4SLinus Torvalds } 7816c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 78179b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7818c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7819c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7820c4837394SDouglas Gilbert } 7821c10fa55fSJohn Garry /* 7822c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7823f7c4cdc7SJohn Garry * following should give the same answer for each host. 7824c10fa55fSJohn Garry */ 7825c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7826f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7827f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 78281da177e4SLinus Torvalds 7829c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7830c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7831c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7832c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7833c4b57d89SKashyap Desai poll_queues = 0; 7834c4b57d89SKashyap Desai } 7835c4b57d89SKashyap Desai 7836c4b57d89SKashyap Desai /* 7837c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7838c4b57d89SKashyap Desai * left over for non-polled I/O. 7839c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7840c4b57d89SKashyap Desai */ 7841c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7842fc09acb7SDouglas Gilbert if (submit_queues < 3) 7843c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7844fc09acb7SDouglas Gilbert else 7845fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7846fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7847c4b57d89SKashyap Desai poll_queues = 1; 7848c4b57d89SKashyap Desai } 7849c4b57d89SKashyap Desai if (poll_queues) 7850c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7851c4b57d89SKashyap Desai 78521da177e4SLinus Torvalds sdbg_host->shost = hpnt; 78531da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7854773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7855773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 78561da177e4SLinus Torvalds else 7857773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7858773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7859f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 78601da177e4SLinus Torvalds 7861f46eb0e9SDouglas Gilbert hprot = 0; 7862c6a44287SMartin K. Petersen 7863773642d9SDouglas Gilbert switch (sdebug_dif) { 7864c6a44287SMartin K. Petersen 78658475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7866f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7867773642d9SDouglas Gilbert if (sdebug_dix) 7868f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7869c6a44287SMartin K. Petersen break; 7870c6a44287SMartin K. Petersen 78718475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7872f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7873773642d9SDouglas Gilbert if (sdebug_dix) 7874f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7875c6a44287SMartin K. Petersen break; 7876c6a44287SMartin K. Petersen 78778475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7878f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7879773642d9SDouglas Gilbert if (sdebug_dix) 7880f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7881c6a44287SMartin K. Petersen break; 7882c6a44287SMartin K. Petersen 7883c6a44287SMartin K. Petersen default: 7884773642d9SDouglas Gilbert if (sdebug_dix) 7885f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7886c6a44287SMartin K. Petersen break; 7887c6a44287SMartin K. Petersen } 7888c6a44287SMartin K. Petersen 7889f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7890c6a44287SMartin K. Petersen 7891f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7892c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7893f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7894f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7895f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7896f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7897f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7898f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7899f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7900c6a44287SMartin K. Petersen 7901773642d9SDouglas Gilbert if (sdebug_guard == 1) 7902c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7903c6a44287SMartin K. Petersen else 7904c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7905c6a44287SMartin K. Petersen 7906773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7907773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7908c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7909c4837394SDouglas Gilbert sdebug_statistics = true; 79101da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 79111da177e4SLinus Torvalds if (error) { 7912c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 79131da177e4SLinus Torvalds error = -ENODEV; 79141da177e4SLinus Torvalds scsi_host_put(hpnt); 791587c715dcSDouglas Gilbert } else { 79161da177e4SLinus Torvalds scsi_scan_host(hpnt); 791787c715dcSDouglas Gilbert } 79181da177e4SLinus Torvalds 79191da177e4SLinus Torvalds return error; 79201da177e4SLinus Torvalds } 79211da177e4SLinus Torvalds 7922fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev) 79231da177e4SLinus Torvalds { 79241da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 79258b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 79261da177e4SLinus Torvalds 79271da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 79281da177e4SLinus Torvalds 79291da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 79301da177e4SLinus Torvalds 79318b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 79328b40228fSFUJITA Tomonori dev_list) { 79331da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7934f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 79351da177e4SLinus Torvalds kfree(sdbg_devinfo); 79361da177e4SLinus Torvalds } 79371da177e4SLinus Torvalds 79381da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 79391da177e4SLinus Torvalds } 79401da177e4SLinus Torvalds 79418dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 79428dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 79431da177e4SLinus Torvalds { 79448dea0d02SFUJITA Tomonori return 1; 79458dea0d02SFUJITA Tomonori } 79461da177e4SLinus Torvalds 79478dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 79488dea0d02SFUJITA Tomonori .name = "pseudo", 79498dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 79508dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 79518dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 795282069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 79538dea0d02SFUJITA Tomonori }; 7954