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 2531107c7b2SJohn Garry static struct kmem_cache *queued_cmd_cache; 2541107c7b2SJohn Garry 2551107c7b2SJohn Garry #define TO_QUEUED_CMD(scmd) ((void *)(scmd)->host_scribble) 2561107c7b2SJohn Garry #define ASSIGN_QUEUED_CMD(scmnd, qc) { (scmnd)->host_scribble = (void *) qc; } 2571107c7b2SJohn Garry 25864e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */ 25964e14eceSDamien Le Moal enum sdebug_z_type { 26035dbe2b9SDamien Le Moal ZBC_ZTYPE_CNV = 0x1, 26135dbe2b9SDamien Le Moal ZBC_ZTYPE_SWR = 0x2, 26235dbe2b9SDamien Le Moal ZBC_ZTYPE_SWP = 0x3, 2634a5fc1c6SDamien Le Moal /* ZBC_ZTYPE_SOBR = 0x4, */ 2644a5fc1c6SDamien Le Moal ZBC_ZTYPE_GAP = 0x5, 26564e14eceSDamien Le Moal }; 26664e14eceSDamien Le Moal 267f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 268f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 269f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 270f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 271f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 272f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 273f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 274f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 275f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 276f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 277f0d1cf93SDouglas Gilbert }; 278f0d1cf93SDouglas Gilbert 279f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 28064e14eceSDamien Le Moal enum sdebug_z_type z_type; 281f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 28264e14eceSDamien Le Moal bool z_non_seq_resource; 283f0d1cf93SDouglas Gilbert unsigned int z_size; 284f0d1cf93SDouglas Gilbert sector_t z_start; 285f0d1cf93SDouglas Gilbert sector_t z_wp; 286f0d1cf93SDouglas Gilbert }; 287fd32119bSDouglas Gilbert 288fd32119bSDouglas Gilbert struct sdebug_dev_info { 289fd32119bSDouglas Gilbert struct list_head dev_list; 290fd32119bSDouglas Gilbert unsigned int channel; 291fd32119bSDouglas Gilbert unsigned int target; 292fd32119bSDouglas Gilbert u64 lun; 293bf476433SChristoph Hellwig uuid_t lu_name; 294fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 295fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 296fc13638aSDouglas Gilbert atomic_t stopped; /* 1: by SSU, 2: device start */ 297fd32119bSDouglas Gilbert bool used; 298f0d1cf93SDouglas Gilbert 299f0d1cf93SDouglas Gilbert /* For ZBC devices */ 30064e14eceSDamien Le Moal enum blk_zoned_model zmodel; 3014a5fc1c6SDamien Le Moal unsigned int zcap; 302f0d1cf93SDouglas Gilbert unsigned int zsize; 303f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 304f0d1cf93SDouglas Gilbert unsigned int nr_zones; 305aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 3064a5fc1c6SDamien Le Moal unsigned int nr_seq_zones; 307f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 308f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 309f0d1cf93SDouglas Gilbert unsigned int nr_closed; 310f0d1cf93SDouglas Gilbert unsigned int max_open; 311fc13638aSDouglas Gilbert ktime_t create_ts; /* time since bootup that this device was created */ 312f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 313fd32119bSDouglas Gilbert }; 314fd32119bSDouglas Gilbert 315fd32119bSDouglas Gilbert struct sdebug_host_info { 316fd32119bSDouglas Gilbert struct list_head host_list; 31787c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 318fd32119bSDouglas Gilbert struct Scsi_Host *shost; 319fd32119bSDouglas Gilbert struct device dev; 320fd32119bSDouglas Gilbert struct list_head dev_info_list; 321fd32119bSDouglas Gilbert }; 322fd32119bSDouglas Gilbert 32387c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 32487c715dcSDouglas Gilbert struct sdeb_store_info { 32587c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 32687c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 32787c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 32887c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 32987c715dcSDouglas Gilbert }; 33087c715dcSDouglas Gilbert 331785d6b7cSJohn Garry #define dev_to_sdebug_host(d) \ 332fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 333fd32119bSDouglas Gilbert 334785d6b7cSJohn Garry #define shost_to_sdebug_host(shost) \ 335785d6b7cSJohn Garry dev_to_sdebug_host(shost->dma_dev) 336785d6b7cSJohn Garry 33710bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 3384a0c6f43SDouglas Gilbert SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3}; 33910bde980SDouglas Gilbert 340fd32119bSDouglas Gilbert struct sdebug_defer { 341fd32119bSDouglas Gilbert struct hrtimer hrt; 342fd32119bSDouglas Gilbert struct execute_work ew; 3434a0c6f43SDouglas Gilbert ktime_t cmpl_ts;/* time since boot to complete this cmd */ 344c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 345c10fa55fSJohn Garry int hc_idx; /* hostwide tag index */ 346c4837394SDouglas Gilbert int issuing_cpu; 3477382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 34810bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 349fd32119bSDouglas Gilbert }; 350fd32119bSDouglas Gilbert 351fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 352c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 353c4837394SDouglas Gilbert * instance indicates this slot is in use. 354c4837394SDouglas Gilbert */ 3551107c7b2SJohn Garry struct sdebug_defer sd_dp; 3561107c7b2SJohn Garry struct scsi_cmnd *scmd; 3571107c7b2SJohn Garry }; 3581107c7b2SJohn Garry 3591107c7b2SJohn Garry struct sdebug_scsi_cmd { 3601107c7b2SJohn Garry spinlock_t lock; 361fd32119bSDouglas Gilbert }; 362fd32119bSDouglas Gilbert 363c4837394SDouglas Gilbert struct sdebug_queue { 3641107c7b2SJohn Garry struct sdebug_queued_cmd *qc_arr[SDEBUG_CANQUEUE]; 365c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 366c4837394SDouglas Gilbert spinlock_t qc_lock; 367fd32119bSDouglas Gilbert }; 368fd32119bSDouglas Gilbert 369c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 370c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 371c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 372c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 3733a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending; 3744a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */ 375c4837394SDouglas Gilbert 376fd32119bSDouglas Gilbert struct opcode_info_t { 377b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 378b01f6f83SDouglas Gilbert /* for terminating element */ 379fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 380fd32119bSDouglas Gilbert u16 sa; /* service action */ 381fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 382fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 383fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3849a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3859a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 386fd32119bSDouglas Gilbert }; 387fd32119bSDouglas Gilbert 388fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 389c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 390c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 391c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 392c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 393c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 394c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 395c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 396c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 397c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 398c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 399c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 400c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 401c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 40246f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 40346f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 404c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 405c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 406c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 407481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 408c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 409c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 410c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 411c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 412c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 413c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 414c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 415c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 416c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 417c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 418c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 419ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 420f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 421f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 422f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 423c2248fc9SDouglas Gilbert }; 424c2248fc9SDouglas Gilbert 425c4837394SDouglas Gilbert 426c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 427c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 428c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 429c2248fc9SDouglas Gilbert 0, 0, 0, 0, 430c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 431c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 432c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 433c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 434c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 435c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 436c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 437c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 438ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 439c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 440c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 441c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 442c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 443c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 444c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 445c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 446fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 447c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 448c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 449c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 450c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 451c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 452c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 453c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 454f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 455f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 45646f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 457c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 458c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 459c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 46046f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 46146f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 462c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 463c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 464c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 465c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 466c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 467c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 468c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 469c2248fc9SDouglas Gilbert }; 470c2248fc9SDouglas Gilbert 47180c49563SDouglas Gilbert /* 47280c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 47380c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 47480c49563SDouglas Gilbert * command completion, they can mask their return value with 47580c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 47680c49563SDouglas Gilbert */ 47780c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 47880c49563SDouglas Gilbert 479c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 482c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 483c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 484c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 485c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 486c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 487c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 488481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 489c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 490c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 491c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 492c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 493c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 49438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 49538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 496c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 497c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 498c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 49938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 500acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 50180c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 502ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 503f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 504f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 505f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 506f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 507f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 508c2248fc9SDouglas Gilbert 50987c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 51087c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 51187c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 51287c715dcSDouglas Gilbert static int sdebug_add_store(void); 51387c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 51487c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 51587c715dcSDouglas Gilbert 5161107c7b2SJohn Garry static void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp); 5171107c7b2SJohn Garry 51846f64e70SDouglas Gilbert /* 51946f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 52046f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 52146f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 52246f64e70SDouglas Gilbert */ 52346f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 524c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 525c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 526c2248fc9SDouglas Gilbert }; 527c2248fc9SDouglas Gilbert 52846f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 529c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 530c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 531c2248fc9SDouglas Gilbert }; 532c2248fc9SDouglas Gilbert 53346f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 53446f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 535b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 536c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 53746f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 538c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 53946f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 540b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 541c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 542c2248fc9SDouglas Gilbert }; 543c2248fc9SDouglas Gilbert 54446f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 54546f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 54646f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 54746f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 54846f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 54946f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 55046f64e70SDouglas Gilbert 0, 0, 0} }, 55146f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 55246f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55346f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 554c2248fc9SDouglas Gilbert }; 555c2248fc9SDouglas Gilbert 556c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 557c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 558c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 559c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 560c3e2fe92SDouglas Gilbert }; 561c3e2fe92SDouglas Gilbert 56246f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 563c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 564c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 56546f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 566c2248fc9SDouglas Gilbert }; 567c2248fc9SDouglas Gilbert 56846f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 56946f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 570b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 571c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 572481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 573481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 574481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 575c2248fc9SDouglas Gilbert }; 576c2248fc9SDouglas Gilbert 57746f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 57838d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 579c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 58046f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 58138d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 582c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 58346f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 584c2248fc9SDouglas Gilbert }; 585c2248fc9SDouglas Gilbert 58646f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 58746f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 588c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 58946f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 590c2248fc9SDouglas Gilbert }; 591c2248fc9SDouglas Gilbert 59246f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 593c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 594c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 595c2248fc9SDouglas Gilbert }; 596c2248fc9SDouglas Gilbert 59746f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 598c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 599c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 600c2248fc9SDouglas Gilbert }; 601c2248fc9SDouglas Gilbert 60280c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 6034f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 60480c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 60580c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 60680c49563SDouglas Gilbert }; 60780c49563SDouglas Gilbert 608ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 609b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 610ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 611ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 612ed9f3e25SDouglas Gilbert }; 613ed9f3e25SDouglas Gilbert 614f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 615b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 616f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 617f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 618b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 619f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 620f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 621b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 622f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 623f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 624f0d1cf93SDouglas Gilbert }; 625f0d1cf93SDouglas Gilbert 626f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 627b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 628f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 629f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 630f0d1cf93SDouglas Gilbert }; 631f0d1cf93SDouglas Gilbert 632c2248fc9SDouglas Gilbert 633c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 634c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 635c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 636ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 637c2248fc9SDouglas Gilbert /* 0 */ 63846f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 639c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 64046f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 641c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 642c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 643c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 64446f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 645c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 646c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 647c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 648c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 64946f64e70SDouglas Gilbert /* 5 */ 65046f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 65146f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 65246f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 65346f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 65446f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 65546f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 65646f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 657c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 658c2248fc9SDouglas Gilbert 0, 0, 0} }, 65946f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 660c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 661c2248fc9SDouglas Gilbert 0, 0} }, 66246f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 66346f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 66446f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 665c2248fc9SDouglas Gilbert /* 10 */ 66646f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 66746f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 66846f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66980c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6704f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 671c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 67246f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 67346f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 67446f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 67546f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 676481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 677481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 678481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 67946f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 68046f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 68146f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 68246f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 68346f64e70SDouglas Gilbert /* 15 */ 684c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 685c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 686c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 687c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 688c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 689c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 69046f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 69146f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 69246f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 69346f64e70SDouglas Gilbert 0xff, 0xff} }, 69446f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 69546f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 696c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 697c2248fc9SDouglas Gilbert 0} }, 69846f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 69946f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 700c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 701c2248fc9SDouglas Gilbert 0} }, 702c2248fc9SDouglas Gilbert /* 20 */ 703f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 704f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 705c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 706c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 707c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 708c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 709c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 710c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 71146f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 712b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 71346f64e70SDouglas Gilbert /* 25 */ 714acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 715acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 716acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 71746f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 71846f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 71946f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 72046f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7214f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 72280c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 723b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 72480c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 72546f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 726c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 727b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 728b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 729ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 730ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 731ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 732c2248fc9SDouglas Gilbert 733ed9f3e25SDouglas Gilbert /* 30 */ 734b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 735f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 736f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 737f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 738b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 739f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 740f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 741f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 742f0d1cf93SDouglas Gilbert /* sentinel */ 743c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 744c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 745c2248fc9SDouglas Gilbert }; 746c2248fc9SDouglas Gilbert 747f19fe8f3SBart Van Assche static int sdebug_num_hosts; 74887c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 749773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7509b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 751c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7529267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 753773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 754773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 755773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 756773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 757773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 758773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 759c10fa55fSJohn Garry static int sdebug_host_max_queue; /* per host */ 760773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 761773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 762c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 763d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 764d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 765cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 766c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 767773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 768773642d9SDouglas Gilbert static int sdebug_no_uld; 769773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 770773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 771773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 772773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 773773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 77486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 775b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 776773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 777773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 778fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY; 779773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 780773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 781773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 782773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 783773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 784773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 785773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 786773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 787773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 788773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 789773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 79009ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7910c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 79287c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 793773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 794773642d9SDouglas Gilbert static bool sdebug_clustering; 795773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 796773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 797817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 7987109f370SDouglas Gilbert static bool sdebug_no_rwlock; 799773642d9SDouglas Gilbert static bool sdebug_verbose; 800f46eb0e9SDouglas Gilbert static bool have_dif_prot; 8014f2c8bf6SDouglas Gilbert static bool write_since_sync; 802c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 8039447b6ceSMartin K. Petersen static bool sdebug_wp; 8049267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 8059267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 8069267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 8071da177e4SLinus Torvalds 808ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0, 809ad0c7775SDouglas Gilbert SAM_LUN_AM_FLAT = 0x1, 810ad0c7775SDouglas Gilbert SAM_LUN_AM_LOGICAL_UNIT = 0x2, 811ad0c7775SDouglas Gilbert SAM_LUN_AM_EXTENDED = 0x3}; 812ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 813ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL; 814ad0c7775SDouglas Gilbert 815c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8161da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8171da177e4SLinus Torvalds 8181da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8191da177e4SLinus Torvalds may still need them */ 8201da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8211da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8221da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8231da177e4SLinus Torvalds 8241da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8250aaa3fadSJohn Garry static DEFINE_MUTEX(sdebug_host_list_mutex); 8261da177e4SLinus Torvalds 82787c715dcSDouglas Gilbert static struct xarray per_store_arr; 82887c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 82987c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 83087c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 83187c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8321da177e4SLinus Torvalds 83344d92694SMartin K. Petersen static unsigned long map_size; 834cbf67842SDouglas Gilbert static int num_aborts; 835cbf67842SDouglas Gilbert static int num_dev_resets; 836cbf67842SDouglas Gilbert static int num_target_resets; 837cbf67842SDouglas Gilbert static int num_bus_resets; 838cbf67842SDouglas Gilbert static int num_host_resets; 839c6a44287SMartin K. Petersen static int dix_writes; 840c6a44287SMartin K. Petersen static int dix_reads; 841c6a44287SMartin K. Petersen static int dif_errors; 8421da177e4SLinus Torvalds 843f0d1cf93SDouglas Gilbert /* ZBC global data */ 84464e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 8454a5fc1c6SDamien Le Moal static int sdeb_zbc_zone_cap_mb; 84698e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 847380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 848aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 849f0d1cf93SDouglas Gilbert 850c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 851c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/ 852c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 853fd32119bSDouglas Gilbert 8541da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 85587c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 85687c715dcSDouglas Gilbert 85787c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8581da177e4SLinus Torvalds 859cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 860cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8611da177e4SLinus Torvalds 8621da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8631da177e4SLinus Torvalds 8641da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8651da177e4SLinus Torvalds .name = sdebug_proc_name, 8661da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8671da177e4SLinus Torvalds }; 8681da177e4SLinus Torvalds 8691da177e4SLinus Torvalds static const int check_condition_result = 870464a00c9SHannes Reinecke SAM_STAT_CHECK_CONDITION; 8711da177e4SLinus Torvalds 872c6a44287SMartin K. Petersen static const int illegal_condition_result = 873464a00c9SHannes Reinecke (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 874c6a44287SMartin K. Petersen 875cbf67842SDouglas Gilbert static const int device_qfull_result = 8767d5a129bSDouglas Gilbert (DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL; 877cbf67842SDouglas Gilbert 878ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 879ed9f3e25SDouglas Gilbert 880fd32119bSDouglas Gilbert 881760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 882760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 883760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 884760f3b03SDouglas Gilbert */ 885760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 886fd32119bSDouglas Gilbert { 887fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 888fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 889fd32119bSDouglas Gilbert } 890c65b1445SDouglas Gilbert 89187c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 89287c715dcSDouglas Gilbert unsigned long long lba) 89314faa944SAkinobu Mita { 89487c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 89514faa944SAkinobu Mita 89687c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 89787c715dcSDouglas Gilbert if (!sip || !sip->storep) { 89887c715dcSDouglas Gilbert WARN_ON_ONCE(true); 89987c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 90087c715dcSDouglas Gilbert } 90187c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 90214faa944SAkinobu Mita } 90314faa944SAkinobu Mita 90487c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 90587c715dcSDouglas Gilbert sector_t sector) 90614faa944SAkinobu Mita { 90749413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 90814faa944SAkinobu Mita 90987c715dcSDouglas Gilbert return sip->dif_storep + sector; 91014faa944SAkinobu Mita } 91114faa944SAkinobu Mita 9128dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 9138dea0d02SFUJITA Tomonori { 9148dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 9158dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9168dea0d02SFUJITA Tomonori 9170aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 9188dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9198dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9208dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 921773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 922773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9238dea0d02SFUJITA Tomonori else 924773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 925773642d9SDouglas Gilbert /* sdebug_max_luns; */ 926f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9278dea0d02SFUJITA Tomonori } 9280aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 9298dea0d02SFUJITA Tomonori } 9308dea0d02SFUJITA Tomonori 93122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 93222017ed2SDouglas Gilbert 93322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 934fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 935fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 93622017ed2SDouglas Gilbert int in_byte, int in_bit) 93722017ed2SDouglas Gilbert { 93822017ed2SDouglas Gilbert unsigned char *sbuff; 93922017ed2SDouglas Gilbert u8 sks[4]; 94022017ed2SDouglas Gilbert int sl, asc; 94122017ed2SDouglas Gilbert 94222017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 94322017ed2SDouglas Gilbert if (!sbuff) { 94422017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 94522017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 94622017ed2SDouglas Gilbert return; 94722017ed2SDouglas Gilbert } 94822017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 94922017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 950f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0); 95122017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 95222017ed2SDouglas Gilbert sks[0] = 0x80; 95322017ed2SDouglas Gilbert if (c_d) 95422017ed2SDouglas Gilbert sks[0] |= 0x40; 95522017ed2SDouglas Gilbert if (in_bit >= 0) { 95622017ed2SDouglas Gilbert sks[0] |= 0x8; 95722017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 95822017ed2SDouglas Gilbert } 95922017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 960773642d9SDouglas Gilbert if (sdebug_dsense) { 96122017ed2SDouglas Gilbert sl = sbuff[7] + 8; 96222017ed2SDouglas Gilbert sbuff[7] = sl; 96322017ed2SDouglas Gilbert sbuff[sl] = 0x2; 96422017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 96522017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 96622017ed2SDouglas Gilbert } else 96722017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 968773642d9SDouglas Gilbert if (sdebug_verbose) 96922017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 97022017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 97122017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 97222017ed2SDouglas Gilbert } 97322017ed2SDouglas Gilbert 974cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9758dea0d02SFUJITA Tomonori { 976f2b1e9c6SHannes Reinecke if (!scp->sense_buffer) { 977cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 978cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 979cbf67842SDouglas Gilbert return; 980cbf67842SDouglas Gilbert } 981f2b1e9c6SHannes Reinecke memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 9828dea0d02SFUJITA Tomonori 983f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, key, asc, asq); 9848dea0d02SFUJITA Tomonori 985773642d9SDouglas Gilbert if (sdebug_verbose) 986cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 987cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 988cbf67842SDouglas Gilbert my_name, key, asc, asq); 9898dea0d02SFUJITA Tomonori } 9901da177e4SLinus Torvalds 991fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 99222017ed2SDouglas Gilbert { 99322017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 99422017ed2SDouglas Gilbert } 99522017ed2SDouglas Gilbert 9966f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9976f4e626fSNathan Chancellor void __user *arg) 9981da177e4SLinus Torvalds { 999773642d9SDouglas Gilbert if (sdebug_verbose) { 1000cbf67842SDouglas Gilbert if (0x1261 == cmd) 1001cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 1002cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 1003cbf67842SDouglas Gilbert else if (0x5331 == cmd) 1004cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 1005cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 1006cbf67842SDouglas Gilbert __func__); 1007cbf67842SDouglas Gilbert else 1008cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 1009cbf67842SDouglas Gilbert __func__, cmd); 10101da177e4SLinus Torvalds } 10111da177e4SLinus Torvalds return -EINVAL; 10121da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds 10159b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10169b760fd8SDouglas Gilbert { 10179b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10189b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10199b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10209b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10219b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10229b760fd8SDouglas Gilbert break; 10239b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10249b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10259b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10269b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10279b760fd8SDouglas Gilbert break; 10289b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10299b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10309b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10319b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10329b760fd8SDouglas Gilbert break; 10339b760fd8SDouglas Gilbert case 16: 10349b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10359b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10369b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10379b760fd8SDouglas Gilbert break; 10389b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10399b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10409b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10419b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10429b760fd8SDouglas Gilbert break; 10439b760fd8SDouglas Gilbert default: 10449b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10459b760fd8SDouglas Gilbert sdebug_cdb_len); 10469b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10479b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10489b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10499b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10509b760fd8SDouglas Gilbert break; 10519b760fd8SDouglas Gilbert } 10529b760fd8SDouglas Gilbert } 10539b760fd8SDouglas Gilbert 10549b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10559b760fd8SDouglas Gilbert { 10569b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10579b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10589b760fd8SDouglas Gilbert struct scsi_device *sdev; 10599b760fd8SDouglas Gilbert 10600aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 10619b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10629b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10639b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10649b760fd8SDouglas Gilbert config_cdb_len(sdev); 10659b760fd8SDouglas Gilbert } 10669b760fd8SDouglas Gilbert } 10670aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 10689b760fd8SDouglas Gilbert } 10699b760fd8SDouglas Gilbert 107019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 107119c8ead7SEwan D. Milne { 107200f9d622SJohn Garry struct sdebug_host_info *sdhp = devip->sdbg_host; 107319c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 107419c8ead7SEwan D. Milne 107519c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 107619c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 107700f9d622SJohn Garry (devip->target == dp->target)) { 107819c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 107919c8ead7SEwan D. Milne } 108019c8ead7SEwan D. Milne } 108119c8ead7SEwan D. Milne } 108219c8ead7SEwan D. Milne 1083f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10841da177e4SLinus Torvalds { 1085cbf67842SDouglas Gilbert int k; 1086cbf67842SDouglas Gilbert 1087cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1088cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1089cbf67842SDouglas Gilbert const char *cp = NULL; 1090cbf67842SDouglas Gilbert 1091cbf67842SDouglas Gilbert switch (k) { 1092cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1093f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1094f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1095773642d9SDouglas Gilbert if (sdebug_verbose) 1096cbf67842SDouglas Gilbert cp = "power on reset"; 1097cbf67842SDouglas Gilbert break; 1098500d0d24SDouglas Gilbert case SDEBUG_UA_POOCCUR: 1099500d0d24SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1100500d0d24SDouglas Gilbert POWER_ON_OCCURRED_ASCQ); 1101500d0d24SDouglas Gilbert if (sdebug_verbose) 1102500d0d24SDouglas Gilbert cp = "power on occurred"; 1103500d0d24SDouglas Gilbert break; 1104cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1105f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1106f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1107773642d9SDouglas Gilbert if (sdebug_verbose) 1108cbf67842SDouglas Gilbert cp = "bus reset"; 1109cbf67842SDouglas Gilbert break; 1110cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1111f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1112f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1113773642d9SDouglas Gilbert if (sdebug_verbose) 1114cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1115cbf67842SDouglas Gilbert break; 11160d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1117f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1118f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1119773642d9SDouglas Gilbert if (sdebug_verbose) 11200d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1121f49accf1SEwan D. Milne break; 1122acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1123f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1124b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1125b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1126773642d9SDouglas Gilbert if (sdebug_verbose) 1127acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1128acafd0b9SEwan D. Milne break; 1129acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1130f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1131acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1132acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1133773642d9SDouglas Gilbert if (sdebug_verbose) 1134acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1135acafd0b9SEwan D. Milne break; 113619c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 113719c8ead7SEwan D. Milne /* 113819c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 113919c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 114019c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 114119c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1142773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 114319c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 114419c8ead7SEwan D. Milne */ 1145773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 114619c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1147f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 114819c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 114919c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1150773642d9SDouglas Gilbert if (sdebug_verbose) 115119c8ead7SEwan D. Milne cp = "reported luns data has changed"; 115219c8ead7SEwan D. Milne break; 1153cbf67842SDouglas Gilbert default: 1154773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1155773642d9SDouglas Gilbert if (sdebug_verbose) 1156cbf67842SDouglas Gilbert cp = "unknown"; 1157cbf67842SDouglas Gilbert break; 1158cbf67842SDouglas Gilbert } 1159cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1160773642d9SDouglas Gilbert if (sdebug_verbose) 1161f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1162cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1163cbf67842SDouglas Gilbert my_name, cp); 11641da177e4SLinus Torvalds return check_condition_result; 11651da177e4SLinus Torvalds } 11661da177e4SLinus Torvalds return 0; 11671da177e4SLinus Torvalds } 11681da177e4SLinus Torvalds 1169fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11701da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11711da177e4SLinus Torvalds int arr_len) 11721da177e4SLinus Torvalds { 117321a61829SFUJITA Tomonori int act_len; 1174ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11751da177e4SLinus Torvalds 1176072d0bb3SFUJITA Tomonori if (!sdb->length) 11771da177e4SLinus Torvalds return 0; 1178ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1179773642d9SDouglas Gilbert return DID_ERROR << 16; 118021a61829SFUJITA Tomonori 118121a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 118221a61829SFUJITA Tomonori arr, arr_len); 118342d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 118421a61829SFUJITA Tomonori 11851da177e4SLinus Torvalds return 0; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 1188fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1189fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1190fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1191fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1192fb0cc8d1SDouglas Gilbert */ 1193fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1194fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1195fb0cc8d1SDouglas Gilbert { 11969237f04eSDamien Le Moal unsigned int act_len, n; 1197ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1198fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1199fb0cc8d1SDouglas Gilbert 1200fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1201fb0cc8d1SDouglas Gilbert return 0; 1202ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1203fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1204fb0cc8d1SDouglas Gilbert 1205fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1206fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1207fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 120842d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 120942d387beSBart Van Assche scsi_get_resid(scp)); 12109237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 121136e07d7eSGeorge Kennedy scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); 1212fb0cc8d1SDouglas Gilbert return 0; 1213fb0cc8d1SDouglas Gilbert } 1214fb0cc8d1SDouglas Gilbert 1215fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1216fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1217fb0cc8d1SDouglas Gilbert */ 12181da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 121921a61829SFUJITA Tomonori int arr_len) 12201da177e4SLinus Torvalds { 122121a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12221da177e4SLinus Torvalds return 0; 1223ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12241da177e4SLinus Torvalds return -1; 122521a61829SFUJITA Tomonori 122621a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12271da177e4SLinus Torvalds } 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds 1230e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1231e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12329b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12331b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12341b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12351b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12361b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12371da177e4SLinus Torvalds 1238cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1239760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12405a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 124109ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1242bf476433SChristoph Hellwig const uuid_t *lu_name) 12431da177e4SLinus Torvalds { 1244c65b1445SDouglas Gilbert int num, port_a; 1245c65b1445SDouglas Gilbert char b[32]; 12461da177e4SLinus Torvalds 1247c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12481da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12491da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12501da177e4SLinus Torvalds arr[1] = 0x1; 12511da177e4SLinus Torvalds arr[2] = 0x0; 1252e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1253e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12541da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12551da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12561da177e4SLinus Torvalds arr[3] = num; 12571da177e4SLinus Torvalds num += 4; 1258c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 125909ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 126009ba24c1SDouglas Gilbert /* Locally assigned UUID */ 126109ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 126209ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 126309ba24c1SDouglas Gilbert arr[num++] = 0x0; 126409ba24c1SDouglas Gilbert arr[num++] = 0x12; 126509ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 126609ba24c1SDouglas Gilbert arr[num++] = 0x0; 126709ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 126809ba24c1SDouglas Gilbert num += 16; 126909ba24c1SDouglas Gilbert } else { 12701b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1271c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1272c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1273c65b1445SDouglas Gilbert arr[num++] = 0x0; 1274c65b1445SDouglas Gilbert arr[num++] = 0x8; 12751b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1276773642d9SDouglas Gilbert num += 8; 127709ba24c1SDouglas Gilbert } 1278c65b1445SDouglas Gilbert /* Target relative port number */ 1279c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1280c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1281c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1282c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1283c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1284c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1285c65b1445SDouglas Gilbert arr[num++] = 0x0; 1286c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1287c65b1445SDouglas Gilbert } 12881b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1289c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1290c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1291c65b1445SDouglas Gilbert arr[num++] = 0x0; 1292c65b1445SDouglas Gilbert arr[num++] = 0x8; 12931b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1294773642d9SDouglas Gilbert num += 8; 12951b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12965a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12975a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12985a09e398SHannes Reinecke arr[num++] = 0x0; 12995a09e398SHannes Reinecke arr[num++] = 0x4; 13005a09e398SHannes Reinecke arr[num++] = 0; 13015a09e398SHannes Reinecke arr[num++] = 0; 1302773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1303773642d9SDouglas Gilbert num += 2; 13041b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1305c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1306c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1307c65b1445SDouglas Gilbert arr[num++] = 0x0; 1308c65b1445SDouglas Gilbert arr[num++] = 0x8; 13091b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1310773642d9SDouglas Gilbert num += 8; 1311c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1312c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1313c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1314c65b1445SDouglas Gilbert arr[num++] = 0x0; 1315c65b1445SDouglas Gilbert arr[num++] = 24; 13161b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1317c65b1445SDouglas Gilbert num += 12; 1318c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1319c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1320c65b1445SDouglas Gilbert num += 8; 1321c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1322c65b1445SDouglas Gilbert num += 4; 1323c65b1445SDouglas Gilbert return num; 1324c65b1445SDouglas Gilbert } 1325c65b1445SDouglas Gilbert 1326c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1327c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1328c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1329c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1330c65b1445SDouglas Gilbert }; 1331c65b1445SDouglas Gilbert 1332cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1333760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1334c65b1445SDouglas Gilbert { 1335c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1336c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1337c65b1445SDouglas Gilbert } 1338c65b1445SDouglas Gilbert 1339cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1340760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1341c65b1445SDouglas Gilbert { 1342c65b1445SDouglas Gilbert int num = 0; 1343c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1344c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1345c65b1445SDouglas Gilbert int plen, olen; 1346c65b1445SDouglas Gilbert 1347c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1348c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1349c65b1445SDouglas Gilbert arr[num++] = 0x0; 1350c65b1445SDouglas Gilbert olen = strlen(na1); 1351c65b1445SDouglas Gilbert plen = olen + 1; 1352c65b1445SDouglas Gilbert if (plen % 4) 1353c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1354c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1355c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1356c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1357c65b1445SDouglas Gilbert num += plen; 1358c65b1445SDouglas Gilbert 1359c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1360c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1361c65b1445SDouglas Gilbert arr[num++] = 0x0; 1362c65b1445SDouglas Gilbert olen = strlen(na2); 1363c65b1445SDouglas Gilbert plen = olen + 1; 1364c65b1445SDouglas Gilbert if (plen % 4) 1365c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1366c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1367c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1368c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1369c65b1445SDouglas Gilbert num += plen; 1370c65b1445SDouglas Gilbert 1371c65b1445SDouglas Gilbert return num; 1372c65b1445SDouglas Gilbert } 1373c65b1445SDouglas Gilbert 1374c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1375760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1376c65b1445SDouglas Gilbert { 1377c65b1445SDouglas Gilbert int num = 0; 1378c65b1445SDouglas Gilbert int port_a, port_b; 1379c65b1445SDouglas Gilbert 1380c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1381c65b1445SDouglas Gilbert port_b = port_a + 1; 1382c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1383c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1384c65b1445SDouglas Gilbert arr[num++] = 0x0; 1385c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1386c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1387c65b1445SDouglas Gilbert num += 6; 1388c65b1445SDouglas Gilbert arr[num++] = 0x0; 1389c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1390c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1391c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1392c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1393c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1394c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13951b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1396773642d9SDouglas Gilbert num += 8; 1397c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1398c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1399c65b1445SDouglas Gilbert arr[num++] = 0x0; 1400c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1401c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1402c65b1445SDouglas Gilbert num += 6; 1403c65b1445SDouglas Gilbert arr[num++] = 0x0; 1404c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1405c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1406c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1407c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1408c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1409c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 14101b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1411773642d9SDouglas Gilbert num += 8; 1412c65b1445SDouglas Gilbert 1413c65b1445SDouglas Gilbert return num; 1414c65b1445SDouglas Gilbert } 1415c65b1445SDouglas Gilbert 1416c65b1445SDouglas Gilbert 1417c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1418c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1419c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1420c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1421c65b1445SDouglas Gilbert '1','2','3','4', 1422c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1423c65b1445SDouglas Gilbert 0xec,0,0,0, 1424c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1425c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1426c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1427c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1428c65b1445SDouglas Gilbert 0x53,0x41, 1429c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1430c65b1445SDouglas Gilbert 0x20,0x20, 1431c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1432c65b1445SDouglas Gilbert 0x10,0x80, 1433c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1434c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1435c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1437c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1438c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1440c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1441c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1442c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1443c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1444c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1445c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1446c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0, 1454c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1455c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1456c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1457c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1458c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1459c65b1445SDouglas Gilbert }; 1460c65b1445SDouglas Gilbert 1461cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1462760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1463c65b1445SDouglas Gilbert { 1464c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1465c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1466c65b1445SDouglas Gilbert } 1467c65b1445SDouglas Gilbert 1468c65b1445SDouglas Gilbert 1469c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14701e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14711e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14721e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14731e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1474c65b1445SDouglas Gilbert }; 1475c65b1445SDouglas Gilbert 1476cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1477760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1478c65b1445SDouglas Gilbert { 1479ea61fca5SMartin K. Petersen unsigned int gran; 1480ea61fca5SMartin K. Petersen 1481c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1482e308b3d1SMartin K. Petersen 1483e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 148486e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 148586e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 148686e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 148786e6828aSLukas Herbolt else 1488773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1489773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1490e308b3d1SMartin K. Petersen 1491e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1492773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1493773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 149444d92694SMartin K. Petersen 1495e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1496773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1497e308b3d1SMartin K. Petersen 1498773642d9SDouglas Gilbert if (sdebug_lbpu) { 1499e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1500773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1501e308b3d1SMartin K. Petersen 1502e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1503773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 150444d92694SMartin K. Petersen } 150544d92694SMartin K. Petersen 1506e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1507773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1508773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 150944d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 151044d92694SMartin K. Petersen } 151144d92694SMartin K. Petersen 1512e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1513773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 15146014759cSMartin K. Petersen 15155b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1516773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 15175b94e232SMartin K. Petersen 15185b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 15191da177e4SLinus Torvalds } 15201da177e4SLinus Torvalds 15211e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 152264e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1523eac6e8e4SMatthew Wilcox { 1524eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1525eac6e8e4SMatthew Wilcox arr[0] = 0; 15261e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15271e49f785SDouglas Gilbert arr[2] = 0; 15281e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 152964e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 153064e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1531eac6e8e4SMatthew Wilcox 1532eac6e8e4SMatthew Wilcox return 0x3c; 1533eac6e8e4SMatthew Wilcox } 15341da177e4SLinus Torvalds 1535760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1536760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15376014759cSMartin K. Petersen { 15383f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15396014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1540773642d9SDouglas Gilbert if (sdebug_lbpu) 15416014759cSMartin K. Petersen arr[1] = 1 << 7; 1542773642d9SDouglas Gilbert if (sdebug_lbpws) 15436014759cSMartin K. Petersen arr[1] |= 1 << 6; 1544773642d9SDouglas Gilbert if (sdebug_lbpws10) 15455b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1546760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1547760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1548760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1549760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1550760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15513f0bc3b3SMartin K. Petersen return 0x4; 15526014759cSMartin K. Petersen } 15536014759cSMartin K. Petersen 1554d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1555f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1556d36da305SDouglas Gilbert { 1557d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1558d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1559d36da305SDouglas Gilbert /* 1560d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1561d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1562f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1563f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1564d36da305SDouglas Gilbert */ 1565d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1566d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 156764e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1568f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1569f0d1cf93SDouglas Gilbert else 1570d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 15714a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) { 15724a5fc1c6SDamien Le Moal arr[19] = ZBC_CONSTANT_ZONE_START_OFFSET; 15734a5fc1c6SDamien Le Moal put_unaligned_be64(devip->zsize, &arr[20]); 15744a5fc1c6SDamien Le Moal } else { 15754a5fc1c6SDamien Le Moal arr[19] = 0; 15764a5fc1c6SDamien Le Moal } 1577d36da305SDouglas Gilbert return 0x3c; 1578d36da305SDouglas Gilbert } 1579d36da305SDouglas Gilbert 15801da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1581c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15821da177e4SLinus Torvalds 1583c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15841da177e4SLinus Torvalds { 15851da177e4SLinus Torvalds unsigned char pq_pdt; 15865a09e398SHannes Reinecke unsigned char *arr; 158701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 158836e07d7eSGeorge Kennedy u32 alloc_len, n; 158936e07d7eSGeorge Kennedy int ret; 1590d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15911da177e4SLinus Torvalds 1592773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15936f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15946f3cbf55SDouglas Gilbert if (! arr) 15956f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1596760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 159764e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1598d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1599b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1600c2248fc9SDouglas Gilbert if (have_wlun) 1601b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1602b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1603b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1604c65b1445SDouglas Gilbert else 1605773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 16061da177e4SLinus Torvalds arr[0] = pq_pdt; 16071da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 160822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 16095a09e398SHannes Reinecke kfree(arr); 16101da177e4SLinus Torvalds return check_condition_result; 16111da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 161236e07d7eSGeorge Kennedy int lu_id_num, port_group_id, target_dev_id; 161336e07d7eSGeorge Kennedy u32 len; 1614c65b1445SDouglas Gilbert char lu_id_str[6]; 1615c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 16161da177e4SLinus Torvalds 16175a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 16185a09e398SHannes Reinecke (devip->channel & 0x7f); 1619b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 162023183910SDouglas Gilbert host_no = 0; 1621c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1622c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1623c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1624c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1625c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16261da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1627c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1628c65b1445SDouglas Gilbert n = 4; 1629c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1630c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1631c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1632c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1633c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1634c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1635c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1636c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1637d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1638c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1639760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1640760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1641d36da305SDouglas Gilbert if (is_disk) 1642d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 164364e14eceSDamien Le Moal if (is_zbc) 1644d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1645760f3b03SDouglas Gilbert } 1646c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16471da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1648c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16491da177e4SLinus Torvalds arr[3] = len; 1650c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16511da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1652c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1653760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16545a09e398SHannes Reinecke target_dev_id, lu_id_num, 165509ba24c1SDouglas Gilbert lu_id_str, len, 165609ba24c1SDouglas Gilbert &devip->lu_name); 1657c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1658c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1659760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1660c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1661c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1662760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1663c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1664c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1665c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16668475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1667c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1668760f3b03SDouglas Gilbert else if (have_dif_prot) 1669c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1670c6a44287SMartin K. Petersen else 1671c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1672c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1673c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1674c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1675c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1676c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1677c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1678c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1679c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1680c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1681c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1682760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1683d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1684c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1685760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1686773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1687d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1688c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1689760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1690d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1691eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 169264e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1693760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16946014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1695760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1696d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1697d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1698f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16991da177e4SLinus Torvalds } else { 170022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 17015a09e398SHannes Reinecke kfree(arr); 17021da177e4SLinus Torvalds return check_condition_result; 17031da177e4SLinus Torvalds } 170436e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 17055a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 170636e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 17075a09e398SHannes Reinecke kfree(arr); 17085a09e398SHannes Reinecke return ret; 17091da177e4SLinus Torvalds } 17101da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1711773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1712773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 17131da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 17141da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1715f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1716b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 171770bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1718c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 17191da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1720c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1721e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1722e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1723e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 17249b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17259b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17261da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1727760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1728760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1729c65b1445SDouglas Gilbert n = 62; 1730760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1731760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1732760f3b03SDouglas Gilbert n += 2; 1733760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1734760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1735760f3b03SDouglas Gilbert n += 2; 1736d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1737d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1738d36da305SDouglas Gilbert n += 2; 17391da177e4SLinus Torvalds } 1740760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17415a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 174236e07d7eSGeorge Kennedy min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ)); 17435a09e398SHannes Reinecke kfree(arr); 17445a09e398SHannes Reinecke return ret; 17451da177e4SLinus Torvalds } 17461da177e4SLinus Torvalds 174784905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */ 1748fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1749fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1750fd32119bSDouglas Gilbert 17511da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17521da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17531da177e4SLinus Torvalds { 175401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 175584905d34SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ 175684905d34SDouglas Gilbert bool dsense = !!(cmd[1] & 1); 175736e07d7eSGeorge Kennedy u32 alloc_len = cmd[4]; 175836e07d7eSGeorge Kennedy u32 len = 18; 175984905d34SDouglas Gilbert int stopped_state = atomic_read(&devip->stopped); 17601da177e4SLinus Torvalds 1761c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 176284905d34SDouglas Gilbert if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ 176384905d34SDouglas Gilbert if (dsense) { 176484905d34SDouglas Gilbert arr[0] = 0x72; 176584905d34SDouglas Gilbert arr[1] = NOT_READY; 176684905d34SDouglas Gilbert arr[2] = LOGICAL_UNIT_NOT_READY; 176784905d34SDouglas Gilbert arr[3] = (stopped_state == 2) ? 0x1 : 0x2; 176884905d34SDouglas Gilbert len = 8; 176984905d34SDouglas Gilbert } else { 177084905d34SDouglas Gilbert arr[0] = 0x70; 177184905d34SDouglas Gilbert arr[2] = NOT_READY; /* NO_SENSE in sense_key */ 177284905d34SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 177384905d34SDouglas Gilbert arr[12] = LOGICAL_UNIT_NOT_READY; 177484905d34SDouglas Gilbert arr[13] = (stopped_state == 2) ? 0x1 : 0x2; 177584905d34SDouglas Gilbert } 177684905d34SDouglas Gilbert } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 177784905d34SDouglas Gilbert /* Information exceptions control mode page: TEST=1, MRIE=6 */ 1778c2248fc9SDouglas Gilbert if (dsense) { 1779c65b1445SDouglas Gilbert arr[0] = 0x72; 1780c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1781c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 178284905d34SDouglas Gilbert arr[3] = 0xff; /* Failure prediction(false) */ 1783c2248fc9SDouglas Gilbert len = 8; 1784c65b1445SDouglas Gilbert } else { 1785c65b1445SDouglas Gilbert arr[0] = 0x70; 1786c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1787c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1788c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 178984905d34SDouglas Gilbert arr[13] = 0xff; /* Failure prediction(false) */ 1790c65b1445SDouglas Gilbert } 179184905d34SDouglas Gilbert } else { /* nothing to report */ 1792c2248fc9SDouglas Gilbert if (dsense) { 1793c2248fc9SDouglas Gilbert len = 8; 179484905d34SDouglas Gilbert memset(arr, 0, len); 179584905d34SDouglas Gilbert arr[0] = 0x72; 1796c2248fc9SDouglas Gilbert } else { 179784905d34SDouglas Gilbert memset(arr, 0, len); 1798c2248fc9SDouglas Gilbert arr[0] = 0x70; 1799c2248fc9SDouglas Gilbert arr[7] = 0xa; 1800c2248fc9SDouglas Gilbert } 1801c65b1445SDouglas Gilbert } 180236e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len)); 18031da177e4SLinus Torvalds } 18041da177e4SLinus Torvalds 1805fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 1806c65b1445SDouglas Gilbert { 180701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1808fc13638aSDouglas Gilbert int power_cond, want_stop, stopped_state; 18094f2c8bf6SDouglas Gilbert bool changing; 1810c65b1445SDouglas Gilbert 1811c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1812c65b1445SDouglas Gilbert if (power_cond) { 181322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1814c65b1445SDouglas Gilbert return check_condition_result; 1815c65b1445SDouglas Gilbert } 1816fc13638aSDouglas Gilbert want_stop = !(cmd[4] & 1); 1817fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 1818fc13638aSDouglas Gilbert if (stopped_state == 2) { 1819fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 1820fc13638aSDouglas Gilbert 1821fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 1822fc13638aSDouglas Gilbert u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 1823fc13638aSDouglas Gilbert 1824fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 1825fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 1826fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 1827fc13638aSDouglas Gilbert stopped_state = 0; 1828fc13638aSDouglas Gilbert } 1829fc13638aSDouglas Gilbert } 1830fc13638aSDouglas Gilbert if (stopped_state == 2) { 1831fc13638aSDouglas Gilbert if (want_stop) { 1832fc13638aSDouglas Gilbert stopped_state = 1; /* dummy up success */ 1833fc13638aSDouglas Gilbert } else { /* Disallow tur_ms_to_ready delay to be overridden */ 1834fc13638aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */); 1835fc13638aSDouglas Gilbert return check_condition_result; 1836fc13638aSDouglas Gilbert } 1837fc13638aSDouglas Gilbert } 1838fc13638aSDouglas Gilbert } 1839fc13638aSDouglas Gilbert changing = (stopped_state != want_stop); 1840fc13638aSDouglas Gilbert if (changing) 1841fc13638aSDouglas Gilbert atomic_xchg(&devip->stopped, want_stop); 1842fc13638aSDouglas Gilbert if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ 18434f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18444f2c8bf6SDouglas Gilbert else 18454f2c8bf6SDouglas Gilbert return 0; 1846c65b1445SDouglas Gilbert } 1847c65b1445SDouglas Gilbert 184828898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 184928898873SFUJITA Tomonori { 1850773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1851773642d9SDouglas Gilbert 1852773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1853773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1854773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 185528898873SFUJITA Tomonori else 185628898873SFUJITA Tomonori return sdebug_store_sectors; 185728898873SFUJITA Tomonori } 185828898873SFUJITA Tomonori 18591da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18601da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18611da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18621da177e4SLinus Torvalds { 18631da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1864c65b1445SDouglas Gilbert unsigned int capac; 18651da177e4SLinus Torvalds 1866c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 186728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18681da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1869c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1870c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1871773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1872773642d9SDouglas Gilbert } else 1873773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1874773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18751da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18761da177e4SLinus Torvalds } 18771da177e4SLinus Torvalds 1878c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1879c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1880c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1881c65b1445SDouglas Gilbert { 188201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1883c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 18844e3ace00SYe Bin u32 alloc_len; 1885c65b1445SDouglas Gilbert 1886773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1887c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 188828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1889c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1890773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1891773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1892773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1893773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 189444d92694SMartin K. Petersen 1895be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18965b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1897760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1898760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1899760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1900760f3b03SDouglas Gilbert */ 1901760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1902760f3b03SDouglas Gilbert arr[14] |= 0x40; 1903be1dd78dSEric Sandeen } 190444d92694SMartin K. Petersen 1905ecb8c258SBart Van Assche /* 1906ecb8c258SBart Van Assche * Since the scsi_debug READ CAPACITY implementation always reports the 1907ecb8c258SBart Van Assche * total disk capacity, set RC BASIS = 1 for host-managed ZBC devices. 1908ecb8c258SBart Van Assche */ 1909ecb8c258SBart Van Assche if (devip->zmodel == BLK_ZONED_HM) 1910ecb8c258SBart Van Assche arr[12] |= 1 << 4; 1911ecb8c258SBart Van Assche 1912773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1913c6a44287SMartin K. Petersen 1914760f3b03SDouglas Gilbert if (have_dif_prot) { 1915773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1916c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1917c6a44287SMartin K. Petersen } 1918c6a44287SMartin K. Petersen 1919c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 19204e3ace00SYe Bin min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1921c65b1445SDouglas Gilbert } 1922c65b1445SDouglas Gilbert 19235a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 19245a09e398SHannes Reinecke 19255a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 19265a09e398SHannes Reinecke struct sdebug_dev_info *devip) 19275a09e398SHannes Reinecke { 192801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19295a09e398SHannes Reinecke unsigned char *arr; 19305a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 19315a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 1932f347c268SYe Bin u32 alen, n, rlen; 1933f347c268SYe Bin int ret; 19345a09e398SHannes Reinecke 1935773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19366f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19376f3cbf55SDouglas Gilbert if (! arr) 19386f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19395a09e398SHannes Reinecke /* 19405a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19415a09e398SHannes Reinecke * real and a fake port with no device connected. 19425a09e398SHannes Reinecke * So we create two port groups with one port each 19435a09e398SHannes Reinecke * and set the group with port B to unavailable. 19445a09e398SHannes Reinecke */ 19455a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19465a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19475a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19485a09e398SHannes Reinecke (devip->channel & 0x7f); 19495a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19505a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19515a09e398SHannes Reinecke 19525a09e398SHannes Reinecke /* 19535a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19545a09e398SHannes Reinecke */ 19555a09e398SHannes Reinecke n = 4; 1956b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19575a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19585a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19595a09e398SHannes Reinecke } else { 19605a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1961773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19625a09e398SHannes Reinecke } 1963773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1964773642d9SDouglas Gilbert n += 2; 19655a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19665a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19675a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19685a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19695a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19705a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1971773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1972773642d9SDouglas Gilbert n += 2; 19735a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19745a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1975773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1976773642d9SDouglas Gilbert n += 2; 19775a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19785a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19795a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19805a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19815a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19825a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1983773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1984773642d9SDouglas Gilbert n += 2; 19855a09e398SHannes Reinecke 19865a09e398SHannes Reinecke rlen = n - 4; 1987773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19885a09e398SHannes Reinecke 19895a09e398SHannes Reinecke /* 19905a09e398SHannes Reinecke * Return the smallest value of either 19915a09e398SHannes Reinecke * - The allocated length 19925a09e398SHannes Reinecke * - The constructed command length 19935a09e398SHannes Reinecke * - The maximum array size 19945a09e398SHannes Reinecke */ 1995f347c268SYe Bin rlen = min(alen, n); 19965a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1997f347c268SYe Bin min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19985a09e398SHannes Reinecke kfree(arr); 19995a09e398SHannes Reinecke return ret; 20005a09e398SHannes Reinecke } 20015a09e398SHannes Reinecke 2002fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 2003fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 200438d5c833SDouglas Gilbert { 200538d5c833SDouglas Gilbert bool rctd; 200638d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 200738d5c833SDouglas Gilbert u16 req_sa, u; 200838d5c833SDouglas Gilbert u32 alloc_len, a_len; 200938d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 201038d5c833SDouglas Gilbert const struct opcode_info_t *oip; 201138d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 201238d5c833SDouglas Gilbert u8 *arr; 201338d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 201438d5c833SDouglas Gilbert 201538d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 201638d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 201738d5c833SDouglas Gilbert req_opcode = cmd[3]; 201838d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 201938d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 20206d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 202138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 202238d5c833SDouglas Gilbert return check_condition_result; 202338d5c833SDouglas Gilbert } 202438d5c833SDouglas Gilbert if (alloc_len > 8192) 202538d5c833SDouglas Gilbert a_len = 8192; 202638d5c833SDouglas Gilbert else 202738d5c833SDouglas Gilbert a_len = alloc_len; 202899531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 202938d5c833SDouglas Gilbert if (NULL == arr) { 203038d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 203138d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 203238d5c833SDouglas Gilbert return check_condition_result; 203338d5c833SDouglas Gilbert } 203438d5c833SDouglas Gilbert switch (reporting_opts) { 203538d5c833SDouglas Gilbert case 0: /* all commands */ 203638d5c833SDouglas Gilbert /* count number of commands */ 203738d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 203838d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 203938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 204038d5c833SDouglas Gilbert continue; 204138d5c833SDouglas Gilbert count += (oip->num_attached + 1); 204238d5c833SDouglas Gilbert } 204338d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 204438d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 204538d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 204638d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 204738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 204838d5c833SDouglas Gilbert continue; 204938d5c833SDouglas Gilbert na = oip->num_attached; 205038d5c833SDouglas Gilbert arr[offset] = oip->opcode; 205138d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 205238d5c833SDouglas Gilbert if (rctd) 205338d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 205438d5c833SDouglas Gilbert if (FF_SA & oip->flags) 205538d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 205638d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 205738d5c833SDouglas Gilbert if (rctd) 205838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 205938d5c833SDouglas Gilbert r_oip = oip; 206038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 206138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 206238d5c833SDouglas Gilbert continue; 206338d5c833SDouglas Gilbert offset += bump; 206438d5c833SDouglas Gilbert arr[offset] = oip->opcode; 206538d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 206638d5c833SDouglas Gilbert if (rctd) 206738d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 206838d5c833SDouglas Gilbert if (FF_SA & oip->flags) 206938d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 207038d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 207138d5c833SDouglas Gilbert arr + offset + 6); 207238d5c833SDouglas Gilbert if (rctd) 207338d5c833SDouglas Gilbert put_unaligned_be16(0xa, 207438d5c833SDouglas Gilbert arr + offset + 8); 207538d5c833SDouglas Gilbert } 207638d5c833SDouglas Gilbert oip = r_oip; 207738d5c833SDouglas Gilbert offset += bump; 207838d5c833SDouglas Gilbert } 207938d5c833SDouglas Gilbert break; 208038d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 208138d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 208238d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 208338d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 208438d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 208538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 208638d5c833SDouglas Gilbert supp = 1; 208738d5c833SDouglas Gilbert offset = 4; 208838d5c833SDouglas Gilbert } else { 208938d5c833SDouglas Gilbert if (1 == reporting_opts) { 209038d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 209138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 209238d5c833SDouglas Gilbert 2, 2); 209338d5c833SDouglas Gilbert kfree(arr); 209438d5c833SDouglas Gilbert return check_condition_result; 209538d5c833SDouglas Gilbert } 209638d5c833SDouglas Gilbert req_sa = 0; 209738d5c833SDouglas Gilbert } else if (2 == reporting_opts && 209838d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 209938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 210038d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 210138d5c833SDouglas Gilbert return check_condition_result; 210238d5c833SDouglas Gilbert } 210338d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 210438d5c833SDouglas Gilbert req_opcode == oip->opcode) 210538d5c833SDouglas Gilbert supp = 3; 210638d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 210738d5c833SDouglas Gilbert na = oip->num_attached; 210838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 210938d5c833SDouglas Gilbert ++k, ++oip) { 211038d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 211138d5c833SDouglas Gilbert break; 211238d5c833SDouglas Gilbert } 211338d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 211438d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 211538d5c833SDouglas Gilbert na = oip->num_attached; 211638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 211738d5c833SDouglas Gilbert ++k, ++oip) { 211838d5c833SDouglas Gilbert if (req_sa == oip->sa) 211938d5c833SDouglas Gilbert break; 212038d5c833SDouglas Gilbert } 212138d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 212238d5c833SDouglas Gilbert } else 212338d5c833SDouglas Gilbert supp = 3; 212438d5c833SDouglas Gilbert if (3 == supp) { 212538d5c833SDouglas Gilbert u = oip->len_mask[0]; 212638d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 212738d5c833SDouglas Gilbert arr[4] = oip->opcode; 212838d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 212938d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 213038d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 213138d5c833SDouglas Gilbert offset = 4 + u; 213238d5c833SDouglas Gilbert } else 213338d5c833SDouglas Gilbert offset = 4; 213438d5c833SDouglas Gilbert } 213538d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 213638d5c833SDouglas Gilbert if (rctd) { 213738d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 213838d5c833SDouglas Gilbert offset += 12; 213938d5c833SDouglas Gilbert } 214038d5c833SDouglas Gilbert break; 214138d5c833SDouglas Gilbert default: 214238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 214338d5c833SDouglas Gilbert kfree(arr); 214438d5c833SDouglas Gilbert return check_condition_result; 214538d5c833SDouglas Gilbert } 214638d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 214738d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 214838d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 214938d5c833SDouglas Gilbert kfree(arr); 215038d5c833SDouglas Gilbert return errsts; 215138d5c833SDouglas Gilbert } 215238d5c833SDouglas Gilbert 2153fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2154fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 215538d5c833SDouglas Gilbert { 215638d5c833SDouglas Gilbert bool repd; 215738d5c833SDouglas Gilbert u32 alloc_len, len; 215838d5c833SDouglas Gilbert u8 arr[16]; 215938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 216038d5c833SDouglas Gilbert 216138d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 216238d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 216338d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 216438d5c833SDouglas Gilbert if (alloc_len < 4) { 216538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 216638d5c833SDouglas Gilbert return check_condition_result; 216738d5c833SDouglas Gilbert } 216838d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 216938d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 217038d5c833SDouglas Gilbert if (repd) { 217138d5c833SDouglas Gilbert arr[3] = 0xc; 217238d5c833SDouglas Gilbert len = 16; 217338d5c833SDouglas Gilbert } else 217438d5c833SDouglas Gilbert len = 4; 217538d5c833SDouglas Gilbert 217638d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 217738d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 217838d5c833SDouglas Gilbert } 217938d5c833SDouglas Gilbert 21801da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21811da177e4SLinus Torvalds 21821da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21831da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21841da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21851da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21881da177e4SLinus Torvalds if (1 == pcontrol) 21891da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21901da177e4SLinus Torvalds return sizeof(err_recov_pg); 21911da177e4SLinus Torvalds } 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21941da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21951da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21961da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21971da177e4SLinus Torvalds 21981da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21991da177e4SLinus Torvalds if (1 == pcontrol) 22001da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 22011da177e4SLinus Torvalds return sizeof(disconnect_pg); 22021da177e4SLinus Torvalds } 22031da177e4SLinus Torvalds 22041da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 22051da177e4SLinus Torvalds { /* Format device page for mode_sense */ 22061da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 22071da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 22081da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 22091da177e4SLinus Torvalds 22101da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2211773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2212773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2213773642d9SDouglas Gilbert if (sdebug_removable) 22141da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 22151da177e4SLinus Torvalds if (1 == pcontrol) 22161da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 22171da177e4SLinus Torvalds return sizeof(format_pg); 22181da177e4SLinus Torvalds } 22191da177e4SLinus Torvalds 2220fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2221fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2222fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2223fd32119bSDouglas Gilbert 22241da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 22251da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2226cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2227cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2228cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 22291da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 22301da177e4SLinus Torvalds 2231773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2232cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22331da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22341da177e4SLinus Torvalds if (1 == pcontrol) 2235cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2236cbf67842SDouglas Gilbert else if (2 == pcontrol) 2237cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22381da177e4SLinus Torvalds return sizeof(caching_pg); 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds 2241fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2242fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2243fd32119bSDouglas Gilbert 22441da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22451da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2246c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2247c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2248c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22491da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22501da177e4SLinus Torvalds 2251773642d9SDouglas Gilbert if (sdebug_dsense) 22521da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2253c65b1445SDouglas Gilbert else 2254c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2255c6a44287SMartin K. Petersen 2256773642d9SDouglas Gilbert if (sdebug_ato) 2257c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2258c6a44287SMartin K. Petersen 22591da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22601da177e4SLinus Torvalds if (1 == pcontrol) 2261c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2262c65b1445SDouglas Gilbert else if (2 == pcontrol) 2263c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22641da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22651da177e4SLinus Torvalds } 22661da177e4SLinus Torvalds 2267c65b1445SDouglas Gilbert 22681da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22691da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2270c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22711da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2272c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2273c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2274c65b1445SDouglas Gilbert 22751da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22761da177e4SLinus Torvalds if (1 == pcontrol) 2277c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2278c65b1445SDouglas Gilbert else if (2 == pcontrol) 2279c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22801da177e4SLinus Torvalds return sizeof(iec_m_pg); 22811da177e4SLinus Torvalds } 22821da177e4SLinus Torvalds 2283c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2284c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2285c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2286c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2287c65b1445SDouglas Gilbert 2288c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2289c65b1445SDouglas Gilbert if (1 == pcontrol) 2290c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2291c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2292c65b1445SDouglas Gilbert } 2293c65b1445SDouglas Gilbert 2294c65b1445SDouglas Gilbert 2295c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2296c65b1445SDouglas Gilbert int target_dev_id) 2297c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2298c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2299c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2300773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2301773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2302c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2303c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2304c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2305c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2306773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2307773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2308c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2309c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2310c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2311c65b1445SDouglas Gilbert }; 2312c65b1445SDouglas Gilbert int port_a, port_b; 2313c65b1445SDouglas Gilbert 23141b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 23151b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 23161b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 23171b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2318c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2319c65b1445SDouglas Gilbert port_b = port_a + 1; 2320c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2321773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2322773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2323c65b1445SDouglas Gilbert if (1 == pcontrol) 2324c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2325c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2326c65b1445SDouglas Gilbert } 2327c65b1445SDouglas Gilbert 2328c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2329c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2330c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2331c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2332c65b1445SDouglas Gilbert }; 2333c65b1445SDouglas Gilbert 2334c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2335c65b1445SDouglas Gilbert if (1 == pcontrol) 2336c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2337c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2338c65b1445SDouglas Gilbert } 2339c65b1445SDouglas Gilbert 23401da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23411da177e4SLinus Torvalds 2342fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2343fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23441da177e4SLinus Torvalds { 234523183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23461da177e4SLinus Torvalds unsigned char dev_spec; 234736e07d7eSGeorge Kennedy u32 alloc_len, offset, len; 234836e07d7eSGeorge Kennedy int target_dev_id; 2349c2248fc9SDouglas Gilbert int target = scp->device->id; 23501da177e4SLinus Torvalds unsigned char *ap; 23511da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 235201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2353d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23541da177e4SLinus Torvalds 2355760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23561da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23571da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23581da177e4SLinus Torvalds subpcode = cmd[3]; 23591da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2360760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2361760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 236264e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2363d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 236423183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 236523183910SDouglas Gilbert else 236623183910SDouglas Gilbert bd_len = 0; 2367773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23681da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23691da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2370cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23711da177e4SLinus Torvalds return check_condition_result; 23721da177e4SLinus Torvalds } 2373c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2374c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2375d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2376d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2377b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23789447b6ceSMartin K. Petersen if (sdebug_wp) 23799447b6ceSMartin K. Petersen dev_spec |= 0x80; 23809447b6ceSMartin K. Petersen } else 238123183910SDouglas Gilbert dev_spec = 0x0; 23821da177e4SLinus Torvalds if (msense_6) { 23831da177e4SLinus Torvalds arr[2] = dev_spec; 238423183910SDouglas Gilbert arr[3] = bd_len; 23851da177e4SLinus Torvalds offset = 4; 23861da177e4SLinus Torvalds } else { 23871da177e4SLinus Torvalds arr[3] = dev_spec; 238823183910SDouglas Gilbert if (16 == bd_len) 238923183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 239023183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23911da177e4SLinus Torvalds offset = 8; 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds ap = arr + offset; 239428898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 239528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 239628898873SFUJITA Tomonori 239723183910SDouglas Gilbert if (8 == bd_len) { 2398773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2399773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2400773642d9SDouglas Gilbert else 2401773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2402773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 240323183910SDouglas Gilbert offset += bd_len; 240423183910SDouglas Gilbert ap = arr + offset; 240523183910SDouglas Gilbert } else if (16 == bd_len) { 2406773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2407773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 240823183910SDouglas Gilbert offset += bd_len; 240923183910SDouglas Gilbert ap = arr + offset; 241023183910SDouglas Gilbert } 24111da177e4SLinus Torvalds 2412c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2413c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 241422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 24151da177e4SLinus Torvalds return check_condition_result; 24161da177e4SLinus Torvalds } 2417760f3b03SDouglas Gilbert bad_pcode = false; 2418760f3b03SDouglas Gilbert 24191da177e4SLinus Torvalds switch (pcode) { 24201da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 24211da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24221da177e4SLinus Torvalds offset += len; 24231da177e4SLinus Torvalds break; 24241da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 24251da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 24261da177e4SLinus Torvalds offset += len; 24271da177e4SLinus Torvalds break; 24281da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2429760f3b03SDouglas Gilbert if (is_disk) { 24301da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 24311da177e4SLinus Torvalds offset += len; 2432760f3b03SDouglas Gilbert } else 2433760f3b03SDouglas Gilbert bad_pcode = true; 24341da177e4SLinus Torvalds break; 24351da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2436d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24371da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24381da177e4SLinus Torvalds offset += len; 2439760f3b03SDouglas Gilbert } else 2440760f3b03SDouglas Gilbert bad_pcode = true; 24411da177e4SLinus Torvalds break; 24421da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24431da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24441da177e4SLinus Torvalds offset += len; 24451da177e4SLinus Torvalds break; 2446c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2447c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 244822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2449c65b1445SDouglas Gilbert return check_condition_result; 2450c65b1445SDouglas Gilbert } 2451c65b1445SDouglas Gilbert len = 0; 2452c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2453c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2454c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2455c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2456c65b1445SDouglas Gilbert target_dev_id); 2457c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2458c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2459c65b1445SDouglas Gilbert offset += len; 2460c65b1445SDouglas Gilbert break; 24611da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24621da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24631da177e4SLinus Torvalds offset += len; 24641da177e4SLinus Torvalds break; 24651da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2466c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24671da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24681da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2469760f3b03SDouglas Gilbert if (is_disk) { 2470760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2471760f3b03SDouglas Gilbert target); 2472760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2473760f3b03SDouglas Gilbert target); 2474d36da305SDouglas Gilbert } else if (is_zbc) { 2475d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2476d36da305SDouglas Gilbert target); 2477760f3b03SDouglas Gilbert } 24781da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2479c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2480c65b1445SDouglas Gilbert if (0xff == subpcode) { 2481c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2482c65b1445SDouglas Gilbert target, target_dev_id); 2483c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2484c65b1445SDouglas Gilbert } 24851da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2486760f3b03SDouglas Gilbert offset += len; 2487c65b1445SDouglas Gilbert } else { 248822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2489c65b1445SDouglas Gilbert return check_condition_result; 2490c65b1445SDouglas Gilbert } 24911da177e4SLinus Torvalds break; 24921da177e4SLinus Torvalds default: 2493760f3b03SDouglas Gilbert bad_pcode = true; 2494760f3b03SDouglas Gilbert break; 2495760f3b03SDouglas Gilbert } 2496760f3b03SDouglas Gilbert if (bad_pcode) { 249722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24981da177e4SLinus Torvalds return check_condition_result; 24991da177e4SLinus Torvalds } 25001da177e4SLinus Torvalds if (msense_6) 25011da177e4SLinus Torvalds arr[0] = offset - 1; 2502773642d9SDouglas Gilbert else 2503773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 250436e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 25051da177e4SLinus Torvalds } 25061da177e4SLinus Torvalds 2507c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2508c65b1445SDouglas Gilbert 2509fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2510fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2511c65b1445SDouglas Gilbert { 2512c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2513c2248fc9SDouglas Gilbert int param_len, res, mpage; 2514c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 251501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2516c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2517c65b1445SDouglas Gilbert 2518c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2519c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2520c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2521773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2522c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 252322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2524c65b1445SDouglas Gilbert return check_condition_result; 2525c65b1445SDouglas Gilbert } 2526c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2527c65b1445SDouglas Gilbert if (-1 == res) 2528773642d9SDouglas Gilbert return DID_ERROR << 16; 2529773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2530cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2531cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2532cbf67842SDouglas Gilbert __func__, param_len, res); 2533773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2534773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 2535e0a2c28dSGeorge Kennedy off = bd_len + (mselect6 ? 4 : 8); 2536e0a2c28dSGeorge Kennedy if (md_len > 2 || off >= res) { 253722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2538c65b1445SDouglas Gilbert return check_condition_result; 2539c65b1445SDouglas Gilbert } 2540c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2541c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2542c65b1445SDouglas Gilbert if (ps) { 254322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2544c65b1445SDouglas Gilbert return check_condition_result; 2545c65b1445SDouglas Gilbert } 2546c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2547773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2548c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2549c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2550cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2551c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2552c65b1445SDouglas Gilbert return check_condition_result; 2553c65b1445SDouglas Gilbert } 2554c65b1445SDouglas Gilbert switch (mpage) { 2555cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2556cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2557cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2558cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2559cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2560cbf67842SDouglas Gilbert } 2561cbf67842SDouglas Gilbert break; 2562c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2563c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2564c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2565c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25669447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25679447b6ceSMartin K. Petersen sdebug_wp = true; 25689447b6ceSMartin K. Petersen else 25699447b6ceSMartin K. Petersen sdebug_wp = false; 2570773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2571cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2572c65b1445SDouglas Gilbert } 2573c65b1445SDouglas Gilbert break; 2574c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2575c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2576c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2577c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2578cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2579c65b1445SDouglas Gilbert } 2580c65b1445SDouglas Gilbert break; 2581c65b1445SDouglas Gilbert default: 2582c65b1445SDouglas Gilbert break; 2583c65b1445SDouglas Gilbert } 258422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2585c65b1445SDouglas Gilbert return check_condition_result; 2586cbf67842SDouglas Gilbert set_mode_changed_ua: 2587cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2588cbf67842SDouglas Gilbert return 0; 2589c65b1445SDouglas Gilbert } 2590c65b1445SDouglas Gilbert 2591c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2592c65b1445SDouglas Gilbert { 2593c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2594c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2595c65b1445SDouglas Gilbert }; 2596c65b1445SDouglas Gilbert 2597c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2598c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2599c65b1445SDouglas Gilbert } 2600c65b1445SDouglas Gilbert 2601c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2602c65b1445SDouglas Gilbert { 2603c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2604c65b1445SDouglas Gilbert }; 2605c65b1445SDouglas Gilbert 2606c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2607c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2608c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2609c65b1445SDouglas Gilbert arr[5] = 0xff; 2610c65b1445SDouglas Gilbert } 2611c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2612c65b1445SDouglas Gilbert } 2613c65b1445SDouglas Gilbert 26140790797aSDouglas Gilbert static int resp_env_rep_l_spg(unsigned char *arr) 26150790797aSDouglas Gilbert { 26160790797aSDouglas Gilbert unsigned char env_rep_l_spg[] = {0x0, 0x0, 0x23, 0x8, 26170790797aSDouglas Gilbert 0x0, 40, 72, 0xff, 45, 18, 0, 0, 26180790797aSDouglas Gilbert 0x1, 0x0, 0x23, 0x8, 26190790797aSDouglas Gilbert 0x0, 55, 72, 35, 55, 45, 0, 0, 26200790797aSDouglas Gilbert }; 26210790797aSDouglas Gilbert 26220790797aSDouglas Gilbert memcpy(arr, env_rep_l_spg, sizeof(env_rep_l_spg)); 26230790797aSDouglas Gilbert return sizeof(env_rep_l_spg); 26240790797aSDouglas Gilbert } 26250790797aSDouglas Gilbert 2626c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2627c65b1445SDouglas Gilbert 2628c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2629c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2630c65b1445SDouglas Gilbert { 263136e07d7eSGeorge Kennedy int ppc, sp, pcode, subpcode; 263236e07d7eSGeorge Kennedy u32 alloc_len, len, n; 2633c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 263401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2635c65b1445SDouglas Gilbert 2636c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2637c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2638c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2639c65b1445SDouglas Gilbert if (ppc || sp) { 264022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2641c65b1445SDouglas Gilbert return check_condition_result; 2642c65b1445SDouglas Gilbert } 2643c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 264423183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2645773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2646c65b1445SDouglas Gilbert arr[0] = pcode; 264723183910SDouglas Gilbert if (0 == subpcode) { 2648c65b1445SDouglas Gilbert switch (pcode) { 2649c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2650c65b1445SDouglas Gilbert n = 4; 2651c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2652c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2653c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2654c65b1445SDouglas Gilbert arr[3] = n - 4; 2655c65b1445SDouglas Gilbert break; 2656c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2657c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2658c65b1445SDouglas Gilbert break; 2659c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2660c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2661c65b1445SDouglas Gilbert break; 2662c65b1445SDouglas Gilbert default: 266322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2664c65b1445SDouglas Gilbert return check_condition_result; 2665c65b1445SDouglas Gilbert } 266623183910SDouglas Gilbert } else if (0xff == subpcode) { 266723183910SDouglas Gilbert arr[0] |= 0x40; 266823183910SDouglas Gilbert arr[1] = subpcode; 266923183910SDouglas Gilbert switch (pcode) { 267023183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 267123183910SDouglas Gilbert n = 4; 267223183910SDouglas Gilbert arr[n++] = 0x0; 267323183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 267423183910SDouglas Gilbert arr[n++] = 0x0; 267523183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 267623183910SDouglas Gilbert arr[n++] = 0xd; 267723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26780790797aSDouglas Gilbert arr[n++] = 0xd; 26790790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26800790797aSDouglas Gilbert arr[n++] = 0xd; 26810790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0xd subpages */ 268223183910SDouglas Gilbert arr[n++] = 0x2f; 268323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 26840790797aSDouglas Gilbert arr[n++] = 0x2f; 26850790797aSDouglas Gilbert arr[n++] = 0xff; /* all 0x2f subpages */ 268623183910SDouglas Gilbert arr[3] = n - 4; 268723183910SDouglas Gilbert break; 268823183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 268923183910SDouglas Gilbert n = 4; 269023183910SDouglas Gilbert arr[n++] = 0xd; 269123183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 26920790797aSDouglas Gilbert arr[n++] = 0xd; 26930790797aSDouglas Gilbert arr[n++] = 0x1; /* Environment reporting */ 26940790797aSDouglas Gilbert arr[n++] = 0xd; 26950790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 269623183910SDouglas Gilbert arr[3] = n - 4; 269723183910SDouglas Gilbert break; 269823183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 269923183910SDouglas Gilbert n = 4; 270023183910SDouglas Gilbert arr[n++] = 0x2f; 270123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 27020790797aSDouglas Gilbert arr[n++] = 0x2f; 27030790797aSDouglas Gilbert arr[n++] = 0xff; /* these subpages */ 270423183910SDouglas Gilbert arr[3] = n - 4; 270523183910SDouglas Gilbert break; 270623183910SDouglas Gilbert default: 270722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 270823183910SDouglas Gilbert return check_condition_result; 270923183910SDouglas Gilbert } 27100790797aSDouglas Gilbert } else if (subpcode > 0) { 27110790797aSDouglas Gilbert arr[0] |= 0x40; 27120790797aSDouglas Gilbert arr[1] = subpcode; 27130790797aSDouglas Gilbert if (pcode == 0xd && subpcode == 1) 27140790797aSDouglas Gilbert arr[3] = resp_env_rep_l_spg(arr + 4); 27150790797aSDouglas Gilbert else { 27160790797aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 27170790797aSDouglas Gilbert return check_condition_result; 27180790797aSDouglas Gilbert } 271923183910SDouglas Gilbert } else { 272022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 272123183910SDouglas Gilbert return check_condition_result; 272223183910SDouglas Gilbert } 272336e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 2724c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 272536e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 2726c65b1445SDouglas Gilbert } 2727c65b1445SDouglas Gilbert 2728f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2729f0d1cf93SDouglas Gilbert { 2730f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2731f0d1cf93SDouglas Gilbert } 2732f0d1cf93SDouglas Gilbert 2733f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2734f0d1cf93SDouglas Gilbert unsigned long long lba) 2735f0d1cf93SDouglas Gilbert { 27364a5fc1c6SDamien Le Moal u32 zno = lba >> devip->zsize_shift; 27374a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp; 27384a5fc1c6SDamien Le Moal 27394a5fc1c6SDamien Le Moal if (devip->zcap == devip->zsize || zno < devip->nr_conv_zones) 27404a5fc1c6SDamien Le Moal return &devip->zstate[zno]; 27414a5fc1c6SDamien Le Moal 27424a5fc1c6SDamien Le Moal /* 27434a5fc1c6SDamien Le Moal * If the zone capacity is less than the zone size, adjust for gap 27444a5fc1c6SDamien Le Moal * zones. 27454a5fc1c6SDamien Le Moal */ 27464a5fc1c6SDamien Le Moal zno = 2 * zno - devip->nr_conv_zones; 27474a5fc1c6SDamien Le Moal WARN_ONCE(zno >= devip->nr_zones, "%u > %u\n", zno, devip->nr_zones); 27484a5fc1c6SDamien Le Moal zsp = &devip->zstate[zno]; 27494a5fc1c6SDamien Le Moal if (lba >= zsp->z_start + zsp->z_size) 27504a5fc1c6SDamien Le Moal zsp++; 27514a5fc1c6SDamien Le Moal WARN_ON_ONCE(lba >= zsp->z_start + zsp->z_size); 27524a5fc1c6SDamien Le Moal return zsp; 2753f0d1cf93SDouglas Gilbert } 2754f0d1cf93SDouglas Gilbert 2755f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2756f0d1cf93SDouglas Gilbert { 275735dbe2b9SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_CNV; 2758f0d1cf93SDouglas Gilbert } 2759f0d1cf93SDouglas Gilbert 27604a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_gap(struct sdeb_zone_state *zsp) 27614a5fc1c6SDamien Le Moal { 27624a5fc1c6SDamien Le Moal return zsp->z_type == ZBC_ZTYPE_GAP; 27634a5fc1c6SDamien Le Moal } 27644a5fc1c6SDamien Le Moal 27654a5fc1c6SDamien Le Moal static inline bool zbc_zone_is_seq(struct sdeb_zone_state *zsp) 27664a5fc1c6SDamien Le Moal { 27674a5fc1c6SDamien Le Moal return !zbc_zone_is_conv(zsp) && !zbc_zone_is_gap(zsp); 27684a5fc1c6SDamien Le Moal } 27694a5fc1c6SDamien Le Moal 2770f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2771f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2772f0d1cf93SDouglas Gilbert { 2773f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2774f0d1cf93SDouglas Gilbert 27754a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2776f0d1cf93SDouglas Gilbert return; 2777f0d1cf93SDouglas Gilbert 2778f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2779f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2780f0d1cf93SDouglas Gilbert return; 2781f0d1cf93SDouglas Gilbert 2782f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2783f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2784f0d1cf93SDouglas Gilbert else 2785f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2786f0d1cf93SDouglas Gilbert 2787f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2788f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2789f0d1cf93SDouglas Gilbert } else { 2790f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2791f0d1cf93SDouglas Gilbert devip->nr_closed++; 2792f0d1cf93SDouglas Gilbert } 2793f0d1cf93SDouglas Gilbert } 2794f0d1cf93SDouglas Gilbert 2795f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2796f0d1cf93SDouglas Gilbert { 2797f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2798f0d1cf93SDouglas Gilbert unsigned int i; 2799f0d1cf93SDouglas Gilbert 2800f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2801f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2802f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2803f0d1cf93SDouglas Gilbert return; 2804f0d1cf93SDouglas Gilbert } 2805f0d1cf93SDouglas Gilbert } 2806f0d1cf93SDouglas Gilbert } 2807f0d1cf93SDouglas Gilbert 2808f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2809f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2810f0d1cf93SDouglas Gilbert { 2811f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2812f0d1cf93SDouglas Gilbert 28134a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2814f0d1cf93SDouglas Gilbert return; 2815f0d1cf93SDouglas Gilbert 2816f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2817f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2818f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2819f0d1cf93SDouglas Gilbert return; 2820f0d1cf93SDouglas Gilbert 2821f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2822f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2823f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2824f0d1cf93SDouglas Gilbert else if (devip->max_open && 2825f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2826f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2827f0d1cf93SDouglas Gilbert 2828f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2829f0d1cf93SDouglas Gilbert devip->nr_closed--; 2830f0d1cf93SDouglas Gilbert if (explicit) { 2831f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2832f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2833f0d1cf93SDouglas Gilbert } else { 2834f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2835f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2836f0d1cf93SDouglas Gilbert } 2837f0d1cf93SDouglas Gilbert } 2838f0d1cf93SDouglas Gilbert 2839566d3c57SDamien Le Moal static inline void zbc_set_zone_full(struct sdebug_dev_info *devip, 2840566d3c57SDamien Le Moal struct sdeb_zone_state *zsp) 2841566d3c57SDamien Le Moal { 2842566d3c57SDamien Le Moal switch (zsp->z_cond) { 2843566d3c57SDamien Le Moal case ZC2_IMPLICIT_OPEN: 2844566d3c57SDamien Le Moal devip->nr_imp_open--; 2845566d3c57SDamien Le Moal break; 2846566d3c57SDamien Le Moal case ZC3_EXPLICIT_OPEN: 2847566d3c57SDamien Le Moal devip->nr_exp_open--; 2848566d3c57SDamien Le Moal break; 2849566d3c57SDamien Le Moal default: 2850566d3c57SDamien Le Moal WARN_ONCE(true, "Invalid zone %llu condition %x\n", 2851566d3c57SDamien Le Moal zsp->z_start, zsp->z_cond); 2852566d3c57SDamien Le Moal break; 2853566d3c57SDamien Le Moal } 2854566d3c57SDamien Le Moal zsp->z_cond = ZC5_FULL; 2855566d3c57SDamien Le Moal } 2856566d3c57SDamien Le Moal 2857f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2858f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2859f0d1cf93SDouglas Gilbert { 2860f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 286164e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2862f0d1cf93SDouglas Gilbert 28634a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 2864f0d1cf93SDouglas Gilbert return; 2865f0d1cf93SDouglas Gilbert 286635dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2867f0d1cf93SDouglas Gilbert zsp->z_wp += num; 286864e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2869566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 287064e14eceSDamien Le Moal return; 287164e14eceSDamien Le Moal } 287264e14eceSDamien Le Moal 287364e14eceSDamien Le Moal while (num) { 287464e14eceSDamien Le Moal if (lba != zsp->z_wp) 287564e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 287664e14eceSDamien Le Moal 287764e14eceSDamien Le Moal end = lba + num; 287864e14eceSDamien Le Moal if (end >= zend) { 287964e14eceSDamien Le Moal n = zend - lba; 288064e14eceSDamien Le Moal zsp->z_wp = zend; 288164e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 288264e14eceSDamien Le Moal n = num; 288364e14eceSDamien Le Moal zsp->z_wp = end; 288464e14eceSDamien Le Moal } else { 288564e14eceSDamien Le Moal n = num; 288664e14eceSDamien Le Moal } 288764e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2888566d3c57SDamien Le Moal zbc_set_zone_full(devip, zsp); 288964e14eceSDamien Le Moal 289064e14eceSDamien Le Moal num -= n; 289164e14eceSDamien Le Moal lba += n; 289264e14eceSDamien Le Moal if (num) { 289364e14eceSDamien Le Moal zsp++; 289464e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 289564e14eceSDamien Le Moal } 289664e14eceSDamien Le Moal } 2897f0d1cf93SDouglas Gilbert } 2898f0d1cf93SDouglas Gilbert 2899f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 29009447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 29011da177e4SLinus Torvalds { 2902f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2903f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2904f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2905f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2906f0d1cf93SDouglas Gilbert 2907f0d1cf93SDouglas Gilbert if (!write) { 290864e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 290964e14eceSDamien Le Moal return 0; 291064e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 29114a5fc1c6SDamien Le Moal if (zsp->z_type != zsp_end->z_type) { 2912f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2913f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2914f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2915f0d1cf93SDouglas Gilbert return check_condition_result; 2916f0d1cf93SDouglas Gilbert } 2917f0d1cf93SDouglas Gilbert return 0; 2918f0d1cf93SDouglas Gilbert } 2919f0d1cf93SDouglas Gilbert 29204a5fc1c6SDamien Le Moal /* Writing into a gap zone is not allowed */ 29214a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) { 29224a5fc1c6SDamien Le Moal mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 29234a5fc1c6SDamien Le Moal ATTEMPT_ACCESS_GAP); 29244a5fc1c6SDamien Le Moal return check_condition_result; 29254a5fc1c6SDamien Le Moal } 29264a5fc1c6SDamien Le Moal 2927f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2928f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2929f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2930f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2931f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2932f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2933f0d1cf93SDouglas Gilbert return check_condition_result; 2934f0d1cf93SDouglas Gilbert } 2935f0d1cf93SDouglas Gilbert return 0; 2936f0d1cf93SDouglas Gilbert } 2937f0d1cf93SDouglas Gilbert 293835dbe2b9SDamien Le Moal if (zsp->z_type == ZBC_ZTYPE_SWR) { 2939f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2940f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2941f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2942f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2943f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2944f0d1cf93SDouglas Gilbert return check_condition_result; 2945f0d1cf93SDouglas Gilbert } 2946f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2947f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2948f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2949f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2950f0d1cf93SDouglas Gilbert return check_condition_result; 2951f0d1cf93SDouglas Gilbert } 2952f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2953f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2954f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2955f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2956f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2957f0d1cf93SDouglas Gilbert return check_condition_result; 2958f0d1cf93SDouglas Gilbert } 295964e14eceSDamien Le Moal } 2960f0d1cf93SDouglas Gilbert 2961f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2962f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2963f0d1cf93SDouglas Gilbert if (devip->max_open && 2964f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2965f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2966f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2967f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2968f0d1cf93SDouglas Gilbert return check_condition_result; 2969f0d1cf93SDouglas Gilbert } 2970f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2971f0d1cf93SDouglas Gilbert } 2972f0d1cf93SDouglas Gilbert 2973f0d1cf93SDouglas Gilbert return 0; 2974f0d1cf93SDouglas Gilbert } 2975f0d1cf93SDouglas Gilbert 2976f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2977f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2978f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2979f0d1cf93SDouglas Gilbert { 2980f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2981f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2982f0d1cf93SDouglas Gilbert 2983c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 298422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 29851da177e4SLinus Torvalds return check_condition_result; 29861da177e4SLinus Torvalds } 2987c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2988c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 298922017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2990cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2991c65b1445SDouglas Gilbert return check_condition_result; 2992c65b1445SDouglas Gilbert } 29939447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 29949447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 29959447b6ceSMartin K. Petersen return check_condition_result; 29969447b6ceSMartin K. Petersen } 2997f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2998f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2999f0d1cf93SDouglas Gilbert 300019789100SFUJITA Tomonori return 0; 300119789100SFUJITA Tomonori } 300219789100SFUJITA Tomonori 3003b6ff8ca7SDouglas Gilbert /* 3004b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 3005b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 3006b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 3007b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 3008b6ff8ca7SDouglas Gilbert */ 3009b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 3010b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 301187c715dcSDouglas Gilbert { 3012b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 3013b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 3014b6ff8ca7SDouglas Gilbert return NULL; 3015b6ff8ca7SDouglas Gilbert } 3016b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 301787c715dcSDouglas Gilbert } 301887c715dcSDouglas Gilbert 3019a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 302087c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 302187c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 302219789100SFUJITA Tomonori { 302319789100SFUJITA Tomonori int ret; 3024c2248fc9SDouglas Gilbert u64 block, rest = 0; 3025a4517511SAkinobu Mita enum dma_data_direction dir; 302687c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 302787c715dcSDouglas Gilbert u8 *fsp; 302819789100SFUJITA Tomonori 3029c2248fc9SDouglas Gilbert if (do_write) { 3030a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 30314f2c8bf6SDouglas Gilbert write_since_sync = true; 3032a4517511SAkinobu Mita } else { 3033a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 3034a4517511SAkinobu Mita } 3035a4517511SAkinobu Mita 303687c715dcSDouglas Gilbert if (!sdb->length || !sip) 3037a4517511SAkinobu Mita return 0; 303887c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 3039a4517511SAkinobu Mita return -1; 304087c715dcSDouglas Gilbert fsp = sip->storep; 304119789100SFUJITA Tomonori 304219789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 304319789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 304419789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 304519789100SFUJITA Tomonori 3046386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 304787c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 30480a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 3049773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 3050a4517511SAkinobu Mita return ret; 3051a4517511SAkinobu Mita 3052a4517511SAkinobu Mita if (rest) { 3053386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 305487c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 30550a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 30560a7e69c7SDouglas Gilbert do_write); 3057a4517511SAkinobu Mita } 305819789100SFUJITA Tomonori 305919789100SFUJITA Tomonori return ret; 306019789100SFUJITA Tomonori } 306119789100SFUJITA Tomonori 306287c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 306387c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 306487c715dcSDouglas Gilbert { 306587c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 306687c715dcSDouglas Gilbert 306787c715dcSDouglas Gilbert if (!sdb->length) 306887c715dcSDouglas Gilbert return 0; 306987c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 307087c715dcSDouglas Gilbert return -1; 307187c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 307287c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 307387c715dcSDouglas Gilbert } 307487c715dcSDouglas Gilbert 307587c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 307687c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 307738d5c833SDouglas Gilbert * return false. */ 307887c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 3079c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 308038d5c833SDouglas Gilbert { 308138d5c833SDouglas Gilbert bool res; 308238d5c833SDouglas Gilbert u64 block, rest = 0; 308338d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 3084773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 308587c715dcSDouglas Gilbert u8 *fsp = sip->storep; 308638d5c833SDouglas Gilbert 308738d5c833SDouglas Gilbert block = do_div(lba, store_blks); 308838d5c833SDouglas Gilbert if (block + num > store_blks) 308938d5c833SDouglas Gilbert rest = block + num - store_blks; 309038d5c833SDouglas Gilbert 309187c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 309238d5c833SDouglas Gilbert if (!res) 309338d5c833SDouglas Gilbert return res; 309438d5c833SDouglas Gilbert if (rest) 309587c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 309638d5c833SDouglas Gilbert rest * lb_size); 309738d5c833SDouglas Gilbert if (!res) 309838d5c833SDouglas Gilbert return res; 3099c3e2fe92SDouglas Gilbert if (compare_only) 3100c3e2fe92SDouglas Gilbert return true; 310138d5c833SDouglas Gilbert arr += num * lb_size; 310287c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 310338d5c833SDouglas Gilbert if (rest) 310487c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 310538d5c833SDouglas Gilbert return res; 310638d5c833SDouglas Gilbert } 310738d5c833SDouglas Gilbert 310851d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 3109beb40ea4SAkinobu Mita { 311051d648afSAkinobu Mita __be16 csum; 3111beb40ea4SAkinobu Mita 3112773642d9SDouglas Gilbert if (sdebug_guard) 311351d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 311451d648afSAkinobu Mita else 3115beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 311651d648afSAkinobu Mita 3117beb40ea4SAkinobu Mita return csum; 3118beb40ea4SAkinobu Mita } 3119beb40ea4SAkinobu Mita 31206ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3121beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3122beb40ea4SAkinobu Mita { 3123773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3124beb40ea4SAkinobu Mita 3125beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3126c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3127beb40ea4SAkinobu Mita (unsigned long)sector, 3128beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3129beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3130beb40ea4SAkinobu Mita return 0x01; 3131beb40ea4SAkinobu Mita } 31328475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3133beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3134c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3135c1287970STomas Winkler (unsigned long)sector); 3136beb40ea4SAkinobu Mita return 0x03; 3137beb40ea4SAkinobu Mita } 31388475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3139beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3140c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3141c1287970STomas Winkler (unsigned long)sector); 3142beb40ea4SAkinobu Mita return 0x03; 3143beb40ea4SAkinobu Mita } 3144beb40ea4SAkinobu Mita return 0; 3145beb40ea4SAkinobu Mita } 3146beb40ea4SAkinobu Mita 314787c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 314865f72f2aSAkinobu Mita unsigned int sectors, bool read) 3149c6a44287SMartin K. Petersen { 3150be4e11beSAkinobu Mita size_t resid; 3151c6a44287SMartin K. Petersen void *paddr; 315287c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3153b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 315487c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 315514faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3156be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3157c6a44287SMartin K. Petersen 3158e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3159e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3160c6a44287SMartin K. Petersen 316187c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 316287c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3163be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3164be4e11beSAkinobu Mita 3165be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 316687c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 316787c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3168be4e11beSAkinobu Mita size_t rest = 0; 316914faa944SAkinobu Mita 317014faa944SAkinobu Mita if (dif_store_end < start + len) 317114faa944SAkinobu Mita rest = start + len - dif_store_end; 3172c6a44287SMartin K. Petersen 3173be4e11beSAkinobu Mita paddr = miter.addr; 317414faa944SAkinobu Mita 317565f72f2aSAkinobu Mita if (read) 317665f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 317765f72f2aSAkinobu Mita else 317865f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 317965f72f2aSAkinobu Mita 318065f72f2aSAkinobu Mita if (rest) { 318165f72f2aSAkinobu Mita if (read) 318214faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 318365f72f2aSAkinobu Mita else 318465f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 318565f72f2aSAkinobu Mita } 3186c6a44287SMartin K. Petersen 3187e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3188c6a44287SMartin K. Petersen resid -= len; 3189c6a44287SMartin K. Petersen } 3190be4e11beSAkinobu Mita sg_miter_stop(&miter); 3191bb8c063cSAkinobu Mita } 3192c6a44287SMartin K. Petersen 319387c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3194bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3195bb8c063cSAkinobu Mita { 3196f7be6772SMartin K. Petersen int ret = 0; 3197bb8c063cSAkinobu Mita unsigned int i; 3198bb8c063cSAkinobu Mita sector_t sector; 319987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3200b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 320187c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3202bb8c063cSAkinobu Mita 3203c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3204bb8c063cSAkinobu Mita sector = start_sec + i; 320587c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3206bb8c063cSAkinobu Mita 320751d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3208bb8c063cSAkinobu Mita continue; 3209bb8c063cSAkinobu Mita 3210f7be6772SMartin K. Petersen /* 3211f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3212f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3213f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3214f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3215f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3216f7be6772SMartin K. Petersen */ 3217f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3218f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3219f7be6772SMartin K. Petersen sector, ei_lba); 3220bb8c063cSAkinobu Mita if (ret) { 3221bb8c063cSAkinobu Mita dif_errors++; 3222f7be6772SMartin K. Petersen break; 3223f7be6772SMartin K. Petersen } 3224bb8c063cSAkinobu Mita } 3225bb8c063cSAkinobu Mita } 3226bb8c063cSAkinobu Mita 322787c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3228c6a44287SMartin K. Petersen dix_reads++; 3229c6a44287SMartin K. Petersen 3230f7be6772SMartin K. Petersen return ret; 3231c6a44287SMartin K. Petersen } 3232c6a44287SMartin K. Petersen 32337109f370SDouglas Gilbert static inline void 32347109f370SDouglas Gilbert sdeb_read_lock(struct sdeb_store_info *sip) 32357109f370SDouglas Gilbert { 3236e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3237e9c47801SDamien Le Moal if (sip) 3238e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3239e9c47801SDamien Le Moal else 3240e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3241e9c47801SDamien Le Moal } else { 32427109f370SDouglas Gilbert if (sip) 32437109f370SDouglas Gilbert read_lock(&sip->macc_lck); 32447109f370SDouglas Gilbert else 32457109f370SDouglas Gilbert read_lock(&sdeb_fake_rw_lck); 32467109f370SDouglas Gilbert } 3247e9c47801SDamien Le Moal } 32487109f370SDouglas Gilbert 32497109f370SDouglas Gilbert static inline void 32507109f370SDouglas Gilbert sdeb_read_unlock(struct sdeb_store_info *sip) 32517109f370SDouglas Gilbert { 3252e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3253e9c47801SDamien Le Moal if (sip) 3254e9c47801SDamien Le Moal __release(&sip->macc_lck); 3255e9c47801SDamien Le Moal else 3256e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3257e9c47801SDamien Le Moal } else { 32587109f370SDouglas Gilbert if (sip) 32597109f370SDouglas Gilbert read_unlock(&sip->macc_lck); 32607109f370SDouglas Gilbert else 32617109f370SDouglas Gilbert read_unlock(&sdeb_fake_rw_lck); 32627109f370SDouglas Gilbert } 3263e9c47801SDamien Le Moal } 32647109f370SDouglas Gilbert 32657109f370SDouglas Gilbert static inline void 32667109f370SDouglas Gilbert sdeb_write_lock(struct sdeb_store_info *sip) 32677109f370SDouglas Gilbert { 3268e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3269e9c47801SDamien Le Moal if (sip) 3270e9c47801SDamien Le Moal __acquire(&sip->macc_lck); 3271e9c47801SDamien Le Moal else 3272e9c47801SDamien Le Moal __acquire(&sdeb_fake_rw_lck); 3273e9c47801SDamien Le Moal } else { 32747109f370SDouglas Gilbert if (sip) 32757109f370SDouglas Gilbert write_lock(&sip->macc_lck); 32767109f370SDouglas Gilbert else 32777109f370SDouglas Gilbert write_lock(&sdeb_fake_rw_lck); 32787109f370SDouglas Gilbert } 3279e9c47801SDamien Le Moal } 32807109f370SDouglas Gilbert 32817109f370SDouglas Gilbert static inline void 32827109f370SDouglas Gilbert sdeb_write_unlock(struct sdeb_store_info *sip) 32837109f370SDouglas Gilbert { 3284e9c47801SDamien Le Moal if (sdebug_no_rwlock) { 3285e9c47801SDamien Le Moal if (sip) 3286e9c47801SDamien Le Moal __release(&sip->macc_lck); 3287e9c47801SDamien Le Moal else 3288e9c47801SDamien Le Moal __release(&sdeb_fake_rw_lck); 3289e9c47801SDamien Le Moal } else { 32907109f370SDouglas Gilbert if (sip) 32917109f370SDouglas Gilbert write_unlock(&sip->macc_lck); 32927109f370SDouglas Gilbert else 32937109f370SDouglas Gilbert write_unlock(&sdeb_fake_rw_lck); 32947109f370SDouglas Gilbert } 3295e9c47801SDamien Le Moal } 32967109f370SDouglas Gilbert 3297fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 329819789100SFUJITA Tomonori { 329987c715dcSDouglas Gilbert bool check_prot; 3300c2248fc9SDouglas Gilbert u32 num; 3301c2248fc9SDouglas Gilbert u32 ei_lba; 330219789100SFUJITA Tomonori int ret; 330387c715dcSDouglas Gilbert u64 lba; 3304b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 330587c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 330619789100SFUJITA Tomonori 3307c2248fc9SDouglas Gilbert switch (cmd[0]) { 3308c2248fc9SDouglas Gilbert case READ_16: 3309c2248fc9SDouglas Gilbert ei_lba = 0; 3310c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3311c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3312c2248fc9SDouglas Gilbert check_prot = true; 3313c2248fc9SDouglas Gilbert break; 3314c2248fc9SDouglas Gilbert case READ_10: 3315c2248fc9SDouglas Gilbert ei_lba = 0; 3316c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3317c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3318c2248fc9SDouglas Gilbert check_prot = true; 3319c2248fc9SDouglas Gilbert break; 3320c2248fc9SDouglas Gilbert case READ_6: 3321c2248fc9SDouglas Gilbert ei_lba = 0; 3322c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3323c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3324c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3325c2248fc9SDouglas Gilbert check_prot = true; 3326c2248fc9SDouglas Gilbert break; 3327c2248fc9SDouglas Gilbert case READ_12: 3328c2248fc9SDouglas Gilbert ei_lba = 0; 3329c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3330c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3331c2248fc9SDouglas Gilbert check_prot = true; 3332c2248fc9SDouglas Gilbert break; 3333c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3334c2248fc9SDouglas Gilbert ei_lba = 0; 3335c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3336c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3337c2248fc9SDouglas Gilbert check_prot = false; 3338c2248fc9SDouglas Gilbert break; 3339c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3340c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3341c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3342c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3343c2248fc9SDouglas Gilbert check_prot = false; 3344c2248fc9SDouglas Gilbert break; 3345c2248fc9SDouglas Gilbert } 3346f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 33478475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3348c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3349c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3350c2248fc9SDouglas Gilbert return check_condition_result; 3351c2248fc9SDouglas Gilbert } 33528475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 33538475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3354c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3355c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3356c2248fc9SDouglas Gilbert "to DIF device\n"); 3357c2248fc9SDouglas Gilbert } 33583a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 33593a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3360c2248fc9SDouglas Gilbert num /= 2; 33613a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3362c2248fc9SDouglas Gilbert } 3363c2248fc9SDouglas Gilbert 33649447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 33659447b6ceSMartin K. Petersen if (ret) 33669447b6ceSMartin K. Petersen return ret; 3367f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3368d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3369d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3370c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3371c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3372c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3373c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3374c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 337532f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 337632f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3377c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3378c65b1445SDouglas Gilbert } 3379c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 33801da177e4SLinus Torvalds return check_condition_result; 33811da177e4SLinus Torvalds } 3382c6a44287SMartin K. Petersen 33837109f370SDouglas Gilbert sdeb_read_lock(sip); 33846c78cc06SAkinobu Mita 3385c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3386f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3387f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3388f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3389f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 33907109f370SDouglas Gilbert sdeb_read_unlock(sip); 3391f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3392f7be6772SMartin K. Petersen return check_condition_result; 3393f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 33947109f370SDouglas Gilbert sdeb_read_unlock(sip); 3395f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3396c6a44287SMartin K. Petersen return illegal_condition_result; 3397c6a44287SMartin K. Petersen } 3398f7be6772SMartin K. Petersen break; 3399f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3400f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 34017109f370SDouglas Gilbert sdeb_read_unlock(sip); 3402f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3403f7be6772SMartin K. Petersen return check_condition_result; 3404f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 34057109f370SDouglas Gilbert sdeb_read_unlock(sip); 3406f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3407f7be6772SMartin K. Petersen return illegal_condition_result; 3408f7be6772SMartin K. Petersen } 3409f7be6772SMartin K. Petersen break; 3410f7be6772SMartin K. Petersen } 3411c6a44287SMartin K. Petersen } 3412c6a44287SMartin K. Petersen 341387c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 34147109f370SDouglas Gilbert sdeb_read_unlock(sip); 3415f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3416a4517511SAkinobu Mita return DID_ERROR << 16; 3417a4517511SAkinobu Mita 341842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3419a4517511SAkinobu Mita 34203a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 34213a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 34223a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 34233a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 34243a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3425c2248fc9SDouglas Gilbert return check_condition_result; 34263a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3427c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3428c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 34293a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3430c2248fc9SDouglas Gilbert return illegal_condition_result; 34313a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3432c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 34333a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3434c2248fc9SDouglas Gilbert return illegal_condition_result; 3435c2248fc9SDouglas Gilbert } 3436c2248fc9SDouglas Gilbert } 3437a4517511SAkinobu Mita return 0; 34381da177e4SLinus Torvalds } 34391da177e4SLinus Torvalds 3440c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3441395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3442c6a44287SMartin K. Petersen { 3443be4e11beSAkinobu Mita int ret; 34446ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3445be4e11beSAkinobu Mita void *daddr; 344665f72f2aSAkinobu Mita sector_t sector = start_sec; 3447c6a44287SMartin K. Petersen int ppage_offset; 3448be4e11beSAkinobu Mita int dpage_offset; 3449be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3450be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3451c6a44287SMartin K. Petersen 3452c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3453c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3454c6a44287SMartin K. Petersen 3455be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3456be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3457be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3458be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3459be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3460c6a44287SMartin K. Petersen 3461be4e11beSAkinobu Mita /* For each protection page */ 3462be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3463be4e11beSAkinobu Mita dpage_offset = 0; 3464be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3465be4e11beSAkinobu Mita ret = 0x01; 3466be4e11beSAkinobu Mita goto out; 3467c6a44287SMartin K. Petersen } 3468c6a44287SMartin K. Petersen 3469be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 34706ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3471be4e11beSAkinobu Mita /* If we're at the end of the current 3472be4e11beSAkinobu Mita * data page advance to the next one 3473be4e11beSAkinobu Mita */ 3474be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3475be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3476be4e11beSAkinobu Mita ret = 0x01; 3477be4e11beSAkinobu Mita goto out; 3478be4e11beSAkinobu Mita } 3479be4e11beSAkinobu Mita dpage_offset = 0; 3480be4e11beSAkinobu Mita } 3481c6a44287SMartin K. Petersen 3482be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3483be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3484be4e11beSAkinobu Mita 3485f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3486be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3487c78be80dSMartin K. Petersen if (ret) 3488395cef03SMartin K. Petersen goto out; 3489395cef03SMartin K. Petersen } 3490395cef03SMartin K. Petersen 3491c6a44287SMartin K. Petersen sector++; 3492395cef03SMartin K. Petersen ei_lba++; 3493773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3494c6a44287SMartin K. Petersen } 3495be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3496be4e11beSAkinobu Mita sg_miter_stop(&diter); 3497c6a44287SMartin K. Petersen } 3498be4e11beSAkinobu Mita sg_miter_stop(&piter); 3499c6a44287SMartin K. Petersen 350065f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3501c6a44287SMartin K. Petersen dix_writes++; 3502c6a44287SMartin K. Petersen 3503c6a44287SMartin K. Petersen return 0; 3504c6a44287SMartin K. Petersen 3505c6a44287SMartin K. Petersen out: 3506c6a44287SMartin K. Petersen dif_errors++; 3507be4e11beSAkinobu Mita sg_miter_stop(&diter); 3508be4e11beSAkinobu Mita sg_miter_stop(&piter); 3509c6a44287SMartin K. Petersen return ret; 3510c6a44287SMartin K. Petersen } 3511c6a44287SMartin K. Petersen 3512b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3513b90ebc3dSAkinobu Mita { 3514773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3515773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3516773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3517b90ebc3dSAkinobu Mita return lba; 3518b90ebc3dSAkinobu Mita } 3519b90ebc3dSAkinobu Mita 3520b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3521b90ebc3dSAkinobu Mita { 3522773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3523a027b5b9SAkinobu Mita 3524773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3525773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3526a027b5b9SAkinobu Mita return lba; 3527a027b5b9SAkinobu Mita } 3528a027b5b9SAkinobu Mita 352987c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 353087c715dcSDouglas Gilbert unsigned int *num) 353144d92694SMartin K. Petersen { 3532b90ebc3dSAkinobu Mita sector_t end; 3533b90ebc3dSAkinobu Mita unsigned int mapped; 3534b90ebc3dSAkinobu Mita unsigned long index; 3535b90ebc3dSAkinobu Mita unsigned long next; 353644d92694SMartin K. Petersen 3537b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 353887c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 353944d92694SMartin K. Petersen 354044d92694SMartin K. Petersen if (mapped) 354187c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 354244d92694SMartin K. Petersen else 354387c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 354444d92694SMartin K. Petersen 3545b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 354644d92694SMartin K. Petersen *num = end - lba; 354744d92694SMartin K. Petersen return mapped; 354844d92694SMartin K. Petersen } 354944d92694SMartin K. Petersen 355087c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 355187c715dcSDouglas Gilbert unsigned int len) 355244d92694SMartin K. Petersen { 355344d92694SMartin K. Petersen sector_t end = lba + len; 355444d92694SMartin K. Petersen 355544d92694SMartin K. Petersen while (lba < end) { 3556b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 355744d92694SMartin K. Petersen 3558b90ebc3dSAkinobu Mita if (index < map_size) 355987c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 356044d92694SMartin K. Petersen 3561b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 356244d92694SMartin K. Petersen } 356344d92694SMartin K. Petersen } 356444d92694SMartin K. Petersen 356587c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 356687c715dcSDouglas Gilbert unsigned int len) 356744d92694SMartin K. Petersen { 356844d92694SMartin K. Petersen sector_t end = lba + len; 356987c715dcSDouglas Gilbert u8 *fsp = sip->storep; 357044d92694SMartin K. Petersen 357144d92694SMartin K. Petersen while (lba < end) { 3572b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 357344d92694SMartin K. Petersen 3574b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3575773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3576b90ebc3dSAkinobu Mita index < map_size) { 357787c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3578760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 357987c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3580760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3581773642d9SDouglas Gilbert sdebug_sector_size * 3582773642d9SDouglas Gilbert sdebug_unmap_granularity); 3583be1dd78dSEric Sandeen } 358487c715dcSDouglas Gilbert if (sip->dif_storep) { 358587c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 358687c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3587773642d9SDouglas Gilbert sdebug_unmap_granularity); 3588e9926b43SAkinobu Mita } 3589b90ebc3dSAkinobu Mita } 3590b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 359144d92694SMartin K. Petersen } 359244d92694SMartin K. Petersen } 359344d92694SMartin K. Petersen 3594fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 35951da177e4SLinus Torvalds { 359687c715dcSDouglas Gilbert bool check_prot; 3597c2248fc9SDouglas Gilbert u32 num; 3598c2248fc9SDouglas Gilbert u32 ei_lba; 359919789100SFUJITA Tomonori int ret; 360087c715dcSDouglas Gilbert u64 lba; 3601b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 360287c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 36031da177e4SLinus Torvalds 3604c2248fc9SDouglas Gilbert switch (cmd[0]) { 3605c2248fc9SDouglas Gilbert case WRITE_16: 3606c2248fc9SDouglas Gilbert ei_lba = 0; 3607c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3608c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3609c2248fc9SDouglas Gilbert check_prot = true; 3610c2248fc9SDouglas Gilbert break; 3611c2248fc9SDouglas Gilbert case WRITE_10: 3612c2248fc9SDouglas Gilbert ei_lba = 0; 3613c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3614c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3615c2248fc9SDouglas Gilbert check_prot = true; 3616c2248fc9SDouglas Gilbert break; 3617c2248fc9SDouglas Gilbert case WRITE_6: 3618c2248fc9SDouglas Gilbert ei_lba = 0; 3619c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3620c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3621c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3622c2248fc9SDouglas Gilbert check_prot = true; 3623c2248fc9SDouglas Gilbert break; 3624c2248fc9SDouglas Gilbert case WRITE_12: 3625c2248fc9SDouglas Gilbert ei_lba = 0; 3626c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3627c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3628c2248fc9SDouglas Gilbert check_prot = true; 3629c2248fc9SDouglas Gilbert break; 3630c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3631c2248fc9SDouglas Gilbert ei_lba = 0; 3632c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3633c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3634c2248fc9SDouglas Gilbert check_prot = false; 3635c2248fc9SDouglas Gilbert break; 3636c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3637c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3638c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3639c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3640c2248fc9SDouglas Gilbert check_prot = false; 3641c2248fc9SDouglas Gilbert break; 3642c2248fc9SDouglas Gilbert } 3643f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 36448475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3645c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3646c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3647c2248fc9SDouglas Gilbert return check_condition_result; 3648c2248fc9SDouglas Gilbert } 36498475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 36508475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3651c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3652c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3653c2248fc9SDouglas Gilbert "to DIF device\n"); 3654c2248fc9SDouglas Gilbert } 3655f0d1cf93SDouglas Gilbert 36567109f370SDouglas Gilbert sdeb_write_lock(sip); 3657f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3658f0d1cf93SDouglas Gilbert if (ret) { 36597109f370SDouglas Gilbert sdeb_write_unlock(sip); 3660f0d1cf93SDouglas Gilbert return ret; 3661f0d1cf93SDouglas Gilbert } 36626c78cc06SAkinobu Mita 3663c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3664f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3665f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3666f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3667f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 36687109f370SDouglas Gilbert sdeb_write_unlock(sip); 3669f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3670c6a44287SMartin K. Petersen return illegal_condition_result; 3671f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36727109f370SDouglas Gilbert sdeb_write_unlock(sip); 3673f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3674f7be6772SMartin K. Petersen return check_condition_result; 3675f7be6772SMartin K. Petersen } 3676f7be6772SMartin K. Petersen break; 3677f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3678f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 36797109f370SDouglas Gilbert sdeb_write_unlock(sip); 3680f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3681f7be6772SMartin K. Petersen return illegal_condition_result; 3682f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 36837109f370SDouglas Gilbert sdeb_write_unlock(sip); 3684f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3685f7be6772SMartin K. Petersen return check_condition_result; 3686f7be6772SMartin K. Petersen } 3687f7be6772SMartin K. Petersen break; 3688c6a44287SMartin K. Petersen } 3689c6a44287SMartin K. Petersen } 3690c6a44287SMartin K. Petersen 369187c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3692f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 369387c715dcSDouglas Gilbert map_region(sip, lba, num); 3694f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3695f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3696f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 36977109f370SDouglas Gilbert sdeb_write_unlock(sip); 3698f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3699773642d9SDouglas Gilbert return DID_ERROR << 16; 3700c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3701c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3702c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3703cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3704773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 370544d92694SMartin K. Petersen 37063a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 37073a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 37083a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 37093a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 37103a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3711c2248fc9SDouglas Gilbert return check_condition_result; 37123a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3713c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3714c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 37153a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3716c2248fc9SDouglas Gilbert return illegal_condition_result; 37173a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3718c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 37193a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3720c2248fc9SDouglas Gilbert return illegal_condition_result; 3721c2248fc9SDouglas Gilbert } 3722c2248fc9SDouglas Gilbert } 37231da177e4SLinus Torvalds return 0; 37241da177e4SLinus Torvalds } 37251da177e4SLinus Torvalds 3726481b5e5cSDouglas Gilbert /* 3727481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3728481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3729481b5e5cSDouglas Gilbert */ 3730481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3731481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3732481b5e5cSDouglas Gilbert { 3733481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3734481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3735481b5e5cSDouglas Gilbert u8 *up; 3736b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3737481b5e5cSDouglas Gilbert u8 wrprotect; 3738481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3739481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3740481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3741481b5e5cSDouglas Gilbert u32 ei_lba; 3742481b5e5cSDouglas Gilbert u64 lba; 3743481b5e5cSDouglas Gilbert int ret, res; 3744481b5e5cSDouglas Gilbert bool is_16; 3745481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3746481b5e5cSDouglas Gilbert 3747481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3748481b5e5cSDouglas Gilbert is_16 = false; 3749481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3750481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3751481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3752481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3753481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3754481b5e5cSDouglas Gilbert is_16 = true; 3755481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3756481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3757481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3758481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3759481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3760481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3761481b5e5cSDouglas Gilbert wrprotect) { 3762481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3763481b5e5cSDouglas Gilbert return illegal_condition_result; 3764481b5e5cSDouglas Gilbert } 3765481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3766481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3767481b5e5cSDouglas Gilbert wrprotect == 0) 3768481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3769481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3770481b5e5cSDouglas Gilbert } 3771481b5e5cSDouglas Gilbert } 3772481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3773481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3774481b5e5cSDouglas Gilbert if (lbdof == 0) { 3775481b5e5cSDouglas Gilbert if (sdebug_verbose) 3776481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3777481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3778481b5e5cSDouglas Gilbert my_name, __func__); 3779481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3780481b5e5cSDouglas Gilbert return illegal_condition_result; 3781481b5e5cSDouglas Gilbert } 3782481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3783481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3784481b5e5cSDouglas Gilbert if (sdebug_verbose) 3785481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3786481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3787481b5e5cSDouglas Gilbert my_name, __func__); 3788481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3789481b5e5cSDouglas Gilbert return illegal_condition_result; 3790481b5e5cSDouglas Gilbert } 3791216e1797SHarshit Mogalapalli lrdp = kzalloc(lbdof_blen, GFP_ATOMIC | __GFP_NOWARN); 3792481b5e5cSDouglas Gilbert if (lrdp == NULL) 3793481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3794481b5e5cSDouglas Gilbert if (sdebug_verbose) 3795481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3796481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3797481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3798481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3799481b5e5cSDouglas Gilbert if (res == -1) { 3800481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3801481b5e5cSDouglas Gilbert goto err_out; 3802481b5e5cSDouglas Gilbert } 3803481b5e5cSDouglas Gilbert 38047109f370SDouglas Gilbert sdeb_write_lock(sip); 3805481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3806481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3807481b5e5cSDouglas Gilbert cum_lb = 0; 3808481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3809481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3810481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3811481b5e5cSDouglas Gilbert if (sdebug_verbose) 3812481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3813481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3814481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3815481b5e5cSDouglas Gilbert if (num == 0) 3816481b5e5cSDouglas Gilbert continue; 38179447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3818481b5e5cSDouglas Gilbert if (ret) 3819481b5e5cSDouglas Gilbert goto err_out_unlock; 3820481b5e5cSDouglas Gilbert num_by = num * lb_size; 3821481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3822481b5e5cSDouglas Gilbert 3823481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3824481b5e5cSDouglas Gilbert if (sdebug_verbose) 3825481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3826481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3827481b5e5cSDouglas Gilbert my_name, __func__); 3828481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3829481b5e5cSDouglas Gilbert 0); 3830481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3831481b5e5cSDouglas Gilbert goto err_out_unlock; 3832481b5e5cSDouglas Gilbert } 3833481b5e5cSDouglas Gilbert 3834481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3835481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3836481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3837481b5e5cSDouglas Gilbert ei_lba); 3838481b5e5cSDouglas Gilbert 3839481b5e5cSDouglas Gilbert if (prot_ret) { 3840481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3841481b5e5cSDouglas Gilbert prot_ret); 3842481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3843481b5e5cSDouglas Gilbert goto err_out_unlock; 3844481b5e5cSDouglas Gilbert } 3845481b5e5cSDouglas Gilbert } 3846481b5e5cSDouglas Gilbert 384787c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3848f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3849f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3850f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3851481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 385287c715dcSDouglas Gilbert map_region(sip, lba, num); 3853481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3854481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3855481b5e5cSDouglas Gilbert goto err_out_unlock; 3856481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3857481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3858481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3859481b5e5cSDouglas Gilbert my_name, num_by, ret); 3860481b5e5cSDouglas Gilbert 38613a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 38623a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 38633a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 38643a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 38653a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 38663a90a63dSDouglas Gilbert ret = check_condition_result; 3867481b5e5cSDouglas Gilbert goto err_out_unlock; 38683a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3869481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 38703a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 38713a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3872481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3873481b5e5cSDouglas Gilbert goto err_out_unlock; 38743a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 38753a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 38763a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3877481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3878481b5e5cSDouglas Gilbert goto err_out_unlock; 3879481b5e5cSDouglas Gilbert } 3880481b5e5cSDouglas Gilbert } 3881481b5e5cSDouglas Gilbert sg_off += num_by; 3882481b5e5cSDouglas Gilbert cum_lb += num; 3883481b5e5cSDouglas Gilbert } 3884481b5e5cSDouglas Gilbert ret = 0; 3885481b5e5cSDouglas Gilbert err_out_unlock: 38867109f370SDouglas Gilbert sdeb_write_unlock(sip); 3887481b5e5cSDouglas Gilbert err_out: 3888481b5e5cSDouglas Gilbert kfree(lrdp); 3889481b5e5cSDouglas Gilbert return ret; 3890481b5e5cSDouglas Gilbert } 3891481b5e5cSDouglas Gilbert 3892fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3893fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 389444d92694SMartin K. Petersen { 3895f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3896f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 389744d92694SMartin K. Petersen unsigned long long i; 389840d07b52SDouglas Gilbert u64 block, lbaa; 389987c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 390087c715dcSDouglas Gilbert int ret; 390187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3902b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 390340d07b52SDouglas Gilbert u8 *fs1p; 390487c715dcSDouglas Gilbert u8 *fsp; 390544d92694SMartin K. Petersen 39067109f370SDouglas Gilbert sdeb_write_lock(sip); 390744d92694SMartin K. Petersen 3908f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3909f0d1cf93SDouglas Gilbert if (ret) { 39107109f370SDouglas Gilbert sdeb_write_unlock(sip); 3911f0d1cf93SDouglas Gilbert return ret; 3912f0d1cf93SDouglas Gilbert } 3913f0d1cf93SDouglas Gilbert 39149ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 391587c715dcSDouglas Gilbert unmap_region(sip, lba, num); 391644d92694SMartin K. Petersen goto out; 391744d92694SMartin K. Petersen } 391840d07b52SDouglas Gilbert lbaa = lba; 391940d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3920c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 392187c715dcSDouglas Gilbert fsp = sip->storep; 392287c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3923c2248fc9SDouglas Gilbert if (ndob) { 392440d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3925c2248fc9SDouglas Gilbert ret = 0; 3926c2248fc9SDouglas Gilbert } else 392740d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 392844d92694SMartin K. Petersen 392944d92694SMartin K. Petersen if (-1 == ret) { 39307109f370SDouglas Gilbert sdeb_write_unlock(sip); 3931773642d9SDouglas Gilbert return DID_ERROR << 16; 393240d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3933c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3934e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 393540d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 393644d92694SMartin K. Petersen 393744d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 393840d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 393940d07b52SDouglas Gilbert lbaa = lba + i; 394040d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 394187c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 394240d07b52SDouglas Gilbert } 39439ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 394487c715dcSDouglas Gilbert map_region(sip, lba, num); 3945f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3946f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3947f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 394844d92694SMartin K. Petersen out: 39497109f370SDouglas Gilbert sdeb_write_unlock(sip); 395044d92694SMartin K. Petersen 395144d92694SMartin K. Petersen return 0; 395244d92694SMartin K. Petersen } 395344d92694SMartin K. Petersen 3954fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3955fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3956c2248fc9SDouglas Gilbert { 3957c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3958c2248fc9SDouglas Gilbert u32 lba; 3959c2248fc9SDouglas Gilbert u16 num; 3960c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3961c2248fc9SDouglas Gilbert bool unmap = false; 3962c2248fc9SDouglas Gilbert 3963c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3964773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3965c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3966c2248fc9SDouglas Gilbert return check_condition_result; 3967c2248fc9SDouglas Gilbert } else 3968c2248fc9SDouglas Gilbert unmap = true; 3969c2248fc9SDouglas Gilbert } 3970c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3971c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3972773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3973c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3974c2248fc9SDouglas Gilbert return check_condition_result; 3975c2248fc9SDouglas Gilbert } 3976c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3977c2248fc9SDouglas Gilbert } 3978c2248fc9SDouglas Gilbert 3979fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3980fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3981c2248fc9SDouglas Gilbert { 3982c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3983c2248fc9SDouglas Gilbert u64 lba; 3984c2248fc9SDouglas Gilbert u32 num; 3985c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3986c2248fc9SDouglas Gilbert bool unmap = false; 3987c2248fc9SDouglas Gilbert bool ndob = false; 3988c2248fc9SDouglas Gilbert 3989c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3990773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3991c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3992c2248fc9SDouglas Gilbert return check_condition_result; 3993c2248fc9SDouglas Gilbert } else 3994c2248fc9SDouglas Gilbert unmap = true; 3995c2248fc9SDouglas Gilbert } 3996c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3997c2248fc9SDouglas Gilbert ndob = true; 3998c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3999c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 4000773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 4001c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 4002c2248fc9SDouglas Gilbert return check_condition_result; 4003c2248fc9SDouglas Gilbert } 4004c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 4005c2248fc9SDouglas Gilbert } 4006c2248fc9SDouglas Gilbert 4007acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 4008acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 4009acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 4010fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 4011fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 4012acafd0b9SEwan D. Milne { 4013acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 4014acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 4015acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 4016acafd0b9SEwan D. Milne u8 mode; 4017acafd0b9SEwan D. Milne 4018acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 4019acafd0b9SEwan D. Milne switch (mode) { 4020acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 4021acafd0b9SEwan D. Milne /* set UAs on this device only */ 4022acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4023acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 4024acafd0b9SEwan D. Milne break; 4025acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 4026acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 4027acafd0b9SEwan D. Milne break; 4028acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 4029acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 4030acafd0b9SEwan D. Milne list_for_each_entry(dp, 4031acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4032acafd0b9SEwan D. Milne dev_list) 4033acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 4034acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 4035acafd0b9SEwan D. Milne if (devip != dp) 4036acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 4037acafd0b9SEwan D. Milne dp->uas_bm); 4038acafd0b9SEwan D. Milne } 4039acafd0b9SEwan D. Milne break; 4040acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 4041acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 4042acafd0b9SEwan D. Milne list_for_each_entry(dp, 4043acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 4044acafd0b9SEwan D. Milne dev_list) 4045acafd0b9SEwan D. Milne if (dp->target == sdp->id) 4046acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 4047acafd0b9SEwan D. Milne dp->uas_bm); 4048acafd0b9SEwan D. Milne break; 4049acafd0b9SEwan D. Milne default: 4050acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 4051acafd0b9SEwan D. Milne break; 4052acafd0b9SEwan D. Milne } 4053acafd0b9SEwan D. Milne return 0; 4054acafd0b9SEwan D. Milne } 4055acafd0b9SEwan D. Milne 4056fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 4057fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 405838d5c833SDouglas Gilbert { 405938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 406038d5c833SDouglas Gilbert u8 *arr; 4061b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 406238d5c833SDouglas Gilbert u64 lba; 406338d5c833SDouglas Gilbert u32 dnum; 4064773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 406538d5c833SDouglas Gilbert u8 num; 406638d5c833SDouglas Gilbert int ret; 4067d467d31fSDouglas Gilbert int retval = 0; 406838d5c833SDouglas Gilbert 4069d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 407038d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 407138d5c833SDouglas Gilbert if (0 == num) 407238d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 40738475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 407438d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 407538d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 407638d5c833SDouglas Gilbert return check_condition_result; 407738d5c833SDouglas Gilbert } 40788475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 40798475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 408038d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 408138d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 408238d5c833SDouglas Gilbert "to DIF device\n"); 40839447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 40849447b6ceSMartin K. Petersen if (ret) 40859447b6ceSMartin K. Petersen return ret; 4086d467d31fSDouglas Gilbert dnum = 2 * num; 40876396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 4088d467d31fSDouglas Gilbert if (NULL == arr) { 4089d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4090d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 4091d467d31fSDouglas Gilbert return check_condition_result; 4092d467d31fSDouglas Gilbert } 409338d5c833SDouglas Gilbert 40947109f370SDouglas Gilbert sdeb_write_lock(sip); 409538d5c833SDouglas Gilbert 409687c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 409738d5c833SDouglas Gilbert if (ret == -1) { 4098d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 4099d467d31fSDouglas Gilbert goto cleanup; 4100773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 410138d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 410238d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 410338d5c833SDouglas Gilbert dnum * lb_size, ret); 4104c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 410538d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4106d467d31fSDouglas Gilbert retval = check_condition_result; 4107d467d31fSDouglas Gilbert goto cleanup; 410838d5c833SDouglas Gilbert } 410938d5c833SDouglas Gilbert if (scsi_debug_lbp()) 411087c715dcSDouglas Gilbert map_region(sip, lba, num); 4111d467d31fSDouglas Gilbert cleanup: 41127109f370SDouglas Gilbert sdeb_write_unlock(sip); 4113d467d31fSDouglas Gilbert kfree(arr); 4114d467d31fSDouglas Gilbert return retval; 411538d5c833SDouglas Gilbert } 411638d5c833SDouglas Gilbert 411744d92694SMartin K. Petersen struct unmap_block_desc { 411844d92694SMartin K. Petersen __be64 lba; 411944d92694SMartin K. Petersen __be32 blocks; 412044d92694SMartin K. Petersen __be32 __reserved; 412144d92694SMartin K. Petersen }; 412244d92694SMartin K. Petersen 4123fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 412444d92694SMartin K. Petersen { 412544d92694SMartin K. Petersen unsigned char *buf; 412644d92694SMartin K. Petersen struct unmap_block_desc *desc; 4127b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 412844d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 412944d92694SMartin K. Petersen int ret; 413044d92694SMartin K. Petersen 4131c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 4132c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 4133c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 4134c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 413544d92694SMartin K. Petersen 413644d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 4137773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 4138c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 413944d92694SMartin K. Petersen return check_condition_result; 4140c2248fc9SDouglas Gilbert } 414144d92694SMartin K. Petersen 4142b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 4143c2248fc9SDouglas Gilbert if (!buf) { 4144c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4145c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 4146c2248fc9SDouglas Gilbert return check_condition_result; 4147c2248fc9SDouglas Gilbert } 4148c2248fc9SDouglas Gilbert 4149c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 415044d92694SMartin K. Petersen 415144d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 415244d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 415344d92694SMartin K. Petersen 415444d92694SMartin K. Petersen desc = (void *)&buf[8]; 415544d92694SMartin K. Petersen 41567109f370SDouglas Gilbert sdeb_write_lock(sip); 41576c78cc06SAkinobu Mita 415844d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 415944d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 416044d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 416144d92694SMartin K. Petersen 41629447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 416344d92694SMartin K. Petersen if (ret) 416444d92694SMartin K. Petersen goto out; 416544d92694SMartin K. Petersen 416687c715dcSDouglas Gilbert unmap_region(sip, lba, num); 416744d92694SMartin K. Petersen } 416844d92694SMartin K. Petersen 416944d92694SMartin K. Petersen ret = 0; 417044d92694SMartin K. Petersen 417144d92694SMartin K. Petersen out: 41727109f370SDouglas Gilbert sdeb_write_unlock(sip); 417344d92694SMartin K. Petersen kfree(buf); 417444d92694SMartin K. Petersen 417544d92694SMartin K. Petersen return ret; 417644d92694SMartin K. Petersen } 417744d92694SMartin K. Petersen 417844d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 417944d92694SMartin K. Petersen 4180fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4181fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 418244d92694SMartin K. Petersen { 4183c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4184c2248fc9SDouglas Gilbert u64 lba; 4185c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 418644d92694SMartin K. Petersen int ret; 418787c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 418844d92694SMartin K. Petersen 4189c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4190c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 419144d92694SMartin K. Petersen 419244d92694SMartin K. Petersen if (alloc_len < 24) 419344d92694SMartin K. Petersen return 0; 419444d92694SMartin K. Petersen 41959447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 419644d92694SMartin K. Petersen if (ret) 419744d92694SMartin K. Petersen return ret; 419844d92694SMartin K. Petersen 4199b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4200b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4201b6ff8ca7SDouglas Gilbert 420287c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4203b6ff8ca7SDouglas Gilbert } else { 4204c2248fc9SDouglas Gilbert mapped = 1; 4205c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4206c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4207c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4208c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4209c2248fc9SDouglas Gilbert else 4210c2248fc9SDouglas Gilbert num = 0xffffffff; 4211c2248fc9SDouglas Gilbert } 421244d92694SMartin K. Petersen 421344d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4214c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4215c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4216c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4217c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 421844d92694SMartin K. Petersen 4219c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 422044d92694SMartin K. Petersen } 422144d92694SMartin K. Petersen 422280c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 422380c49563SDouglas Gilbert struct sdebug_dev_info *devip) 422480c49563SDouglas Gilbert { 42254f2c8bf6SDouglas Gilbert int res = 0; 422680c49563SDouglas Gilbert u64 lba; 422780c49563SDouglas Gilbert u32 num_blocks; 422880c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 422980c49563SDouglas Gilbert 423080c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 423180c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 423280c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 423380c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 423480c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 423580c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 423680c49563SDouglas Gilbert } 423780c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 423880c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 423980c49563SDouglas Gilbert return check_condition_result; 424080c49563SDouglas Gilbert } 4241fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 42424f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 42434f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 42444f2c8bf6SDouglas Gilbert write_since_sync = false; 42454f2c8bf6SDouglas Gilbert return res; 424680c49563SDouglas Gilbert } 424780c49563SDouglas Gilbert 4248ed9f3e25SDouglas Gilbert /* 4249ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4250ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4251ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4252ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4253ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4254ed9f3e25SDouglas Gilbert */ 4255ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4256ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4257ed9f3e25SDouglas Gilbert { 4258ed9f3e25SDouglas Gilbert int res = 0; 4259ed9f3e25SDouglas Gilbert u64 lba; 4260ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4261ed9f3e25SDouglas Gilbert u32 nblks; 4262ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4263b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4264b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4265ed9f3e25SDouglas Gilbert 4266ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4267ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4268ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4269ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4270ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4271ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4272ed9f3e25SDouglas Gilbert } 4273ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4274ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4275ed9f3e25SDouglas Gilbert return check_condition_result; 4276ed9f3e25SDouglas Gilbert } 4277ed9f3e25SDouglas Gilbert if (!fsp) 4278ed9f3e25SDouglas Gilbert goto fini; 4279ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4280ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4281ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4282ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4283ed9f3e25SDouglas Gilbert 4284ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 42857109f370SDouglas Gilbert sdeb_read_lock(sip); 4286ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4287ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4288ed9f3e25SDouglas Gilbert if (rest) 4289ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 42907109f370SDouglas Gilbert sdeb_read_unlock(sip); 4291ed9f3e25SDouglas Gilbert fini: 4292ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4293ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4294ed9f3e25SDouglas Gilbert return res | condition_met_result; 4295ed9f3e25SDouglas Gilbert } 4296ed9f3e25SDouglas Gilbert 4297fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4298fb0cc8d1SDouglas Gilbert 42998d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 43008d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 43018d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 43028d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 43038d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 43048d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 43058d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 43068d039e22SDouglas Gilbert */ 43071da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 43081da177e4SLinus Torvalds struct sdebug_dev_info *devip) 43091da177e4SLinus Torvalds { 431001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 43118d039e22SDouglas Gilbert unsigned int alloc_len; 43128d039e22SDouglas Gilbert unsigned char select_report; 43138d039e22SDouglas Gilbert u64 lun; 43148d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4315fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 43168d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 43178d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 43188d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 43198d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4320fb0cc8d1SDouglas Gilbert int k, j, n, res; 4321fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4322fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 43231da177e4SLinus Torvalds 432419c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 43258d039e22SDouglas Gilbert 43268d039e22SDouglas Gilbert select_report = cmd[2]; 43278d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 43288d039e22SDouglas Gilbert 43298d039e22SDouglas Gilbert if (alloc_len < 4) { 43308d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 43318d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 43321da177e4SLinus Torvalds return check_condition_result; 43331da177e4SLinus Torvalds } 43348d039e22SDouglas Gilbert 43358d039e22SDouglas Gilbert switch (select_report) { 43368d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4337773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 43388d039e22SDouglas Gilbert wlun_cnt = 0; 43398d039e22SDouglas Gilbert break; 43408d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4341c65b1445SDouglas Gilbert lun_cnt = 0; 43428d039e22SDouglas Gilbert wlun_cnt = 1; 43438d039e22SDouglas Gilbert break; 43448d039e22SDouglas Gilbert case 2: /* all LUNs */ 43458d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 43468d039e22SDouglas Gilbert wlun_cnt = 1; 43478d039e22SDouglas Gilbert break; 43488d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 43498d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 43508d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 43518d039e22SDouglas Gilbert default: 43528d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 43538d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 43548d039e22SDouglas Gilbert return check_condition_result; 43558d039e22SDouglas Gilbert } 43568d039e22SDouglas Gilbert 43578d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4358c65b1445SDouglas Gilbert --lun_cnt; 43598d039e22SDouglas Gilbert 43608d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4361fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4362fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 43638d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 43648d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 43658d039e22SDouglas Gilbert 4366fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 43678d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4368fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4369fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4370fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4371fb0cc8d1SDouglas Gilbert if (k == 0) { 4372fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4373fb0cc8d1SDouglas Gilbert ++lun_p; 4374fb0cc8d1SDouglas Gilbert j = 1; 4375fb0cc8d1SDouglas Gilbert } 4376fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4377fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4378fb0cc8d1SDouglas Gilbert break; 4379fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4380ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4381ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4382fb0cc8d1SDouglas Gilbert } 4383fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4384fb0cc8d1SDouglas Gilbert break; 4385fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4386fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4387fb0cc8d1SDouglas Gilbert if (res) 4388fb0cc8d1SDouglas Gilbert return res; 4389fb0cc8d1SDouglas Gilbert off_rsp += n; 4390fb0cc8d1SDouglas Gilbert } 4391fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4392fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4393fb0cc8d1SDouglas Gilbert ++j; 4394fb0cc8d1SDouglas Gilbert } 4395fb0cc8d1SDouglas Gilbert if (j > 0) 4396fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 43978d039e22SDouglas Gilbert return res; 43981da177e4SLinus Torvalds } 43991da177e4SLinus Torvalds 4400c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4401c3e2fe92SDouglas Gilbert { 4402c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4403c3e2fe92SDouglas Gilbert u8 bytchk; 4404c3e2fe92SDouglas Gilbert int ret, j; 4405c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4406c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4407c3e2fe92SDouglas Gilbert u64 lba; 4408c3e2fe92SDouglas Gilbert u8 *arr; 4409c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4410b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4411c3e2fe92SDouglas Gilbert 4412c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4413c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4414c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4415c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4416c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4417c3e2fe92SDouglas Gilbert return check_condition_result; 4418c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4419c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4420c3e2fe92SDouglas Gilbert } 4421c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4422c3e2fe92SDouglas Gilbert case VERIFY_16: 4423c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4424c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4425c3e2fe92SDouglas Gilbert break; 4426c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4427c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4428c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4429c3e2fe92SDouglas Gilbert break; 4430c3e2fe92SDouglas Gilbert default: 4431c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4432c3e2fe92SDouglas Gilbert return check_condition_result; 4433c3e2fe92SDouglas Gilbert } 44343344b58bSGeorge Kennedy if (vnum == 0) 44353344b58bSGeorge Kennedy return 0; /* not an error */ 4436c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4437c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4438c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4439c3e2fe92SDouglas Gilbert if (ret) 4440c3e2fe92SDouglas Gilbert return ret; 4441c3e2fe92SDouglas Gilbert 4442ed0f17b7SHarshit Mogalapalli arr = kcalloc(lb_size, vnum, GFP_ATOMIC | __GFP_NOWARN); 4443c3e2fe92SDouglas Gilbert if (!arr) { 4444c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4445c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4446c3e2fe92SDouglas Gilbert return check_condition_result; 4447c3e2fe92SDouglas Gilbert } 4448c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 44497109f370SDouglas Gilbert sdeb_read_lock(sip); 4450c3e2fe92SDouglas Gilbert 4451c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4452c3e2fe92SDouglas Gilbert if (ret == -1) { 4453c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4454c3e2fe92SDouglas Gilbert goto cleanup; 4455c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4456c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4457c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4458c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4459c3e2fe92SDouglas Gilbert } 4460c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4461c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4462c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4463c3e2fe92SDouglas Gilbert } 4464c3e2fe92SDouglas Gilbert ret = 0; 4465c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4466c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4467c3e2fe92SDouglas Gilbert ret = check_condition_result; 4468c3e2fe92SDouglas Gilbert goto cleanup; 4469c3e2fe92SDouglas Gilbert } 4470c3e2fe92SDouglas Gilbert cleanup: 44717109f370SDouglas Gilbert sdeb_read_unlock(sip); 4472c3e2fe92SDouglas Gilbert kfree(arr); 4473c3e2fe92SDouglas Gilbert return ret; 4474c3e2fe92SDouglas Gilbert } 4475c3e2fe92SDouglas Gilbert 4476f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4477f0d1cf93SDouglas Gilbert 4478897284e8SBart Van Assche /* Report zones depending on start LBA and reporting options */ 4479f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4480f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4481f0d1cf93SDouglas Gilbert { 44824a5fc1c6SDamien Le Moal unsigned int rep_max_zones, nrz = 0; 4483f0d1cf93SDouglas Gilbert int ret = 0; 4484f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4485f0d1cf93SDouglas Gilbert bool partial; 4486f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4487f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4488f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 44894a5fc1c6SDamien Le Moal struct sdeb_zone_state *zsp = NULL; 4490b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4491f0d1cf93SDouglas Gilbert 4492f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4493f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4494f0d1cf93SDouglas Gilbert return check_condition_result; 4495f0d1cf93SDouglas Gilbert } 4496f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4497f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 44983344b58bSGeorge Kennedy if (alloc_len == 0) 44993344b58bSGeorge Kennedy return 0; /* not an error */ 4500f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4501f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4502f0d1cf93SDouglas Gilbert 4503f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4504f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4505f0d1cf93SDouglas Gilbert return check_condition_result; 4506f0d1cf93SDouglas Gilbert } 4507f0d1cf93SDouglas Gilbert 45084a5fc1c6SDamien Le Moal rep_max_zones = (alloc_len - 64) >> ilog2(RZONES_DESC_HD); 4509f0d1cf93SDouglas Gilbert 451007f2ca13SHarshit Mogalapalli arr = kzalloc(alloc_len, GFP_ATOMIC | __GFP_NOWARN); 4511f0d1cf93SDouglas Gilbert if (!arr) { 4512f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4513f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4514f0d1cf93SDouglas Gilbert return check_condition_result; 4515f0d1cf93SDouglas Gilbert } 4516f0d1cf93SDouglas Gilbert 45177109f370SDouglas Gilbert sdeb_read_lock(sip); 4518f0d1cf93SDouglas Gilbert 4519f0d1cf93SDouglas Gilbert desc = arr + 64; 45204a5fc1c6SDamien Le Moal for (lba = zs_lba; lba < sdebug_capacity; 45214a5fc1c6SDamien Le Moal lba = zsp->z_start + zsp->z_size) { 45224a5fc1c6SDamien Le Moal if (WARN_ONCE(zbc_zone(devip, lba) == zsp, "lba = %llu\n", lba)) 4523f0d1cf93SDouglas Gilbert break; 4524f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4525f0d1cf93SDouglas Gilbert switch (rep_opts) { 4526f0d1cf93SDouglas Gilbert case 0x00: 4527f0d1cf93SDouglas Gilbert /* All zones */ 4528f0d1cf93SDouglas Gilbert break; 4529f0d1cf93SDouglas Gilbert case 0x01: 4530f0d1cf93SDouglas Gilbert /* Empty zones */ 4531f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4532f0d1cf93SDouglas Gilbert continue; 4533f0d1cf93SDouglas Gilbert break; 4534f0d1cf93SDouglas Gilbert case 0x02: 4535f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4536f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4537f0d1cf93SDouglas Gilbert continue; 4538f0d1cf93SDouglas Gilbert break; 4539f0d1cf93SDouglas Gilbert case 0x03: 4540f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4541f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4542f0d1cf93SDouglas Gilbert continue; 4543f0d1cf93SDouglas Gilbert break; 4544f0d1cf93SDouglas Gilbert case 0x04: 4545f0d1cf93SDouglas Gilbert /* Closed zones */ 4546f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4547f0d1cf93SDouglas Gilbert continue; 4548f0d1cf93SDouglas Gilbert break; 4549f0d1cf93SDouglas Gilbert case 0x05: 4550f0d1cf93SDouglas Gilbert /* Full zones */ 4551f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4552f0d1cf93SDouglas Gilbert continue; 4553f0d1cf93SDouglas Gilbert break; 4554f0d1cf93SDouglas Gilbert case 0x06: 4555f0d1cf93SDouglas Gilbert case 0x07: 4556f0d1cf93SDouglas Gilbert case 0x10: 4557f0d1cf93SDouglas Gilbert /* 455864e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 455964e14eceSDamien Le Moal * not emulated: no zones to report; 4560f0d1cf93SDouglas Gilbert */ 4561f0d1cf93SDouglas Gilbert continue; 456264e14eceSDamien Le Moal case 0x11: 456364e14eceSDamien Le Moal /* non-seq-resource set */ 456464e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 456564e14eceSDamien Le Moal continue; 456664e14eceSDamien Le Moal break; 45674a5fc1c6SDamien Le Moal case 0x3e: 45684a5fc1c6SDamien Le Moal /* All zones except gap zones. */ 45694a5fc1c6SDamien Le Moal if (zbc_zone_is_gap(zsp)) 45704a5fc1c6SDamien Le Moal continue; 45714a5fc1c6SDamien Le Moal break; 4572f0d1cf93SDouglas Gilbert case 0x3f: 4573f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 45744a5fc1c6SDamien Le Moal if (zbc_zone_is_seq(zsp)) 4575f0d1cf93SDouglas Gilbert continue; 4576f0d1cf93SDouglas Gilbert break; 4577f0d1cf93SDouglas Gilbert default: 4578f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4579f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4580f0d1cf93SDouglas Gilbert ret = check_condition_result; 4581f0d1cf93SDouglas Gilbert goto fini; 4582f0d1cf93SDouglas Gilbert } 4583f0d1cf93SDouglas Gilbert 4584f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4585f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 458664e14eceSDamien Le Moal desc[0] = zsp->z_type; 4587f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 458864e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 458964e14eceSDamien Le Moal desc[1] |= 1 << 1; 4590f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4591f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4592f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4593f0d1cf93SDouglas Gilbert desc += 64; 4594f0d1cf93SDouglas Gilbert } 4595f0d1cf93SDouglas Gilbert 4596f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4597f0d1cf93SDouglas Gilbert break; 4598f0d1cf93SDouglas Gilbert 4599f0d1cf93SDouglas Gilbert nrz++; 4600f0d1cf93SDouglas Gilbert } 4601f0d1cf93SDouglas Gilbert 4602f0d1cf93SDouglas Gilbert /* Report header */ 46034a5fc1c6SDamien Le Moal /* Zone list length. */ 4604f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 46054a5fc1c6SDamien Le Moal /* Maximum LBA */ 4606f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 46074a5fc1c6SDamien Le Moal /* Zone starting LBA granularity. */ 46084a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 46094a5fc1c6SDamien Le Moal put_unaligned_be64(devip->zsize, arr + 16); 4610f0d1cf93SDouglas Gilbert 4611f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 461236e07d7eSGeorge Kennedy ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)); 4613f0d1cf93SDouglas Gilbert 4614f0d1cf93SDouglas Gilbert fini: 46157109f370SDouglas Gilbert sdeb_read_unlock(sip); 4616f0d1cf93SDouglas Gilbert kfree(arr); 4617f0d1cf93SDouglas Gilbert return ret; 4618f0d1cf93SDouglas Gilbert } 4619f0d1cf93SDouglas Gilbert 4620f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4621f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4622f0d1cf93SDouglas Gilbert { 4623f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4624f0d1cf93SDouglas Gilbert unsigned int i; 4625f0d1cf93SDouglas Gilbert 4626f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4627f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4628f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4629f0d1cf93SDouglas Gilbert } 4630f0d1cf93SDouglas Gilbert } 4631f0d1cf93SDouglas Gilbert 4632f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4633f0d1cf93SDouglas Gilbert { 4634f0d1cf93SDouglas Gilbert int res = 0; 4635f0d1cf93SDouglas Gilbert u64 z_id; 4636f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4637f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4638f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4639f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4640b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4641f0d1cf93SDouglas Gilbert 4642f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4643f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4644f0d1cf93SDouglas Gilbert return check_condition_result; 4645f0d1cf93SDouglas Gilbert } 4646f0d1cf93SDouglas Gilbert 46477109f370SDouglas Gilbert sdeb_write_lock(sip); 4648f0d1cf93SDouglas Gilbert 4649f0d1cf93SDouglas Gilbert if (all) { 4650f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4651f0d1cf93SDouglas Gilbert if (devip->max_open && 4652f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4653f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4654f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4655f0d1cf93SDouglas Gilbert res = check_condition_result; 4656f0d1cf93SDouglas Gilbert goto fini; 4657f0d1cf93SDouglas Gilbert } 4658f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4659f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4660f0d1cf93SDouglas Gilbert goto fini; 4661f0d1cf93SDouglas Gilbert } 4662f0d1cf93SDouglas Gilbert 4663f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4664f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4665f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4666f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4667f0d1cf93SDouglas Gilbert res = check_condition_result; 4668f0d1cf93SDouglas Gilbert goto fini; 4669f0d1cf93SDouglas Gilbert } 4670f0d1cf93SDouglas Gilbert 4671f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4672f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4673f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4674f0d1cf93SDouglas Gilbert res = check_condition_result; 4675f0d1cf93SDouglas Gilbert goto fini; 4676f0d1cf93SDouglas Gilbert } 4677f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4678f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4679f0d1cf93SDouglas Gilbert res = check_condition_result; 4680f0d1cf93SDouglas Gilbert goto fini; 4681f0d1cf93SDouglas Gilbert } 4682f0d1cf93SDouglas Gilbert 4683f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4684f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4685f0d1cf93SDouglas Gilbert goto fini; 4686f0d1cf93SDouglas Gilbert 4687f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4688f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4689f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4690f0d1cf93SDouglas Gilbert res = check_condition_result; 4691f0d1cf93SDouglas Gilbert goto fini; 4692f0d1cf93SDouglas Gilbert } 4693f0d1cf93SDouglas Gilbert 4694f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4695f0d1cf93SDouglas Gilbert fini: 46967109f370SDouglas Gilbert sdeb_write_unlock(sip); 4697f0d1cf93SDouglas Gilbert return res; 4698f0d1cf93SDouglas Gilbert } 4699f0d1cf93SDouglas Gilbert 4700f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4701f0d1cf93SDouglas Gilbert { 4702f0d1cf93SDouglas Gilbert unsigned int i; 4703f0d1cf93SDouglas Gilbert 4704f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4705f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4706f0d1cf93SDouglas Gilbert } 4707f0d1cf93SDouglas Gilbert 4708f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4709f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4710f0d1cf93SDouglas Gilbert { 4711f0d1cf93SDouglas Gilbert int res = 0; 4712f0d1cf93SDouglas Gilbert u64 z_id; 4713f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4714f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4715f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4716b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4717f0d1cf93SDouglas Gilbert 4718f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4719f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4720f0d1cf93SDouglas Gilbert return check_condition_result; 4721f0d1cf93SDouglas Gilbert } 4722f0d1cf93SDouglas Gilbert 47237109f370SDouglas Gilbert sdeb_write_lock(sip); 4724f0d1cf93SDouglas Gilbert 4725f0d1cf93SDouglas Gilbert if (all) { 4726f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4727f0d1cf93SDouglas Gilbert goto fini; 4728f0d1cf93SDouglas Gilbert } 4729f0d1cf93SDouglas Gilbert 4730f0d1cf93SDouglas Gilbert /* Close specified zone */ 4731f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4732f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4733f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4734f0d1cf93SDouglas Gilbert res = check_condition_result; 4735f0d1cf93SDouglas Gilbert goto fini; 4736f0d1cf93SDouglas Gilbert } 4737f0d1cf93SDouglas Gilbert 4738f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4739f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4740f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4741f0d1cf93SDouglas Gilbert res = check_condition_result; 4742f0d1cf93SDouglas Gilbert goto fini; 4743f0d1cf93SDouglas Gilbert } 4744f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4745f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4746f0d1cf93SDouglas Gilbert res = check_condition_result; 4747f0d1cf93SDouglas Gilbert goto fini; 4748f0d1cf93SDouglas Gilbert } 4749f0d1cf93SDouglas Gilbert 4750f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4751f0d1cf93SDouglas Gilbert fini: 47527109f370SDouglas Gilbert sdeb_write_unlock(sip); 4753f0d1cf93SDouglas Gilbert return res; 4754f0d1cf93SDouglas Gilbert } 4755f0d1cf93SDouglas Gilbert 4756f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4757f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4758f0d1cf93SDouglas Gilbert { 4759f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4760f0d1cf93SDouglas Gilbert 4761f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4762f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4763f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4764f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4765f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4766f0d1cf93SDouglas Gilbert devip->nr_closed--; 4767f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4768f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4769f0d1cf93SDouglas Gilbert } 4770f0d1cf93SDouglas Gilbert } 4771f0d1cf93SDouglas Gilbert 4772f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4773f0d1cf93SDouglas Gilbert { 4774f0d1cf93SDouglas Gilbert unsigned int i; 4775f0d1cf93SDouglas Gilbert 4776f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4777f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4778f0d1cf93SDouglas Gilbert } 4779f0d1cf93SDouglas Gilbert 4780f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4781f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4782f0d1cf93SDouglas Gilbert { 4783f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4784f0d1cf93SDouglas Gilbert int res = 0; 4785f0d1cf93SDouglas Gilbert u64 z_id; 4786f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4787f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4788b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4789f0d1cf93SDouglas Gilbert 4790f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4791f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4792f0d1cf93SDouglas Gilbert return check_condition_result; 4793f0d1cf93SDouglas Gilbert } 4794f0d1cf93SDouglas Gilbert 47957109f370SDouglas Gilbert sdeb_write_lock(sip); 4796f0d1cf93SDouglas Gilbert 4797f0d1cf93SDouglas Gilbert if (all) { 4798f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4799f0d1cf93SDouglas Gilbert goto fini; 4800f0d1cf93SDouglas Gilbert } 4801f0d1cf93SDouglas Gilbert 4802f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4803f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4804f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4805f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4806f0d1cf93SDouglas Gilbert res = check_condition_result; 4807f0d1cf93SDouglas Gilbert goto fini; 4808f0d1cf93SDouglas Gilbert } 4809f0d1cf93SDouglas Gilbert 4810f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4811f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4812f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4813f0d1cf93SDouglas Gilbert res = check_condition_result; 4814f0d1cf93SDouglas Gilbert goto fini; 4815f0d1cf93SDouglas Gilbert } 4816f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4817f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4818f0d1cf93SDouglas Gilbert res = check_condition_result; 4819f0d1cf93SDouglas Gilbert goto fini; 4820f0d1cf93SDouglas Gilbert } 4821f0d1cf93SDouglas Gilbert 4822f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4823f0d1cf93SDouglas Gilbert fini: 48247109f370SDouglas Gilbert sdeb_write_unlock(sip); 4825f0d1cf93SDouglas Gilbert return res; 4826f0d1cf93SDouglas Gilbert } 4827f0d1cf93SDouglas Gilbert 4828f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4829f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4830f0d1cf93SDouglas Gilbert { 4831f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 48322d62253eSShin'ichiro Kawasaki struct sdeb_store_info *sip = devip2sip(devip, false); 4833f0d1cf93SDouglas Gilbert 48344a5fc1c6SDamien Le Moal if (!zbc_zone_is_seq(zsp)) 4835f0d1cf93SDouglas Gilbert return; 4836f0d1cf93SDouglas Gilbert 4837f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4838f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4839f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4840f0d1cf93SDouglas Gilbert 4841f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4842f0d1cf93SDouglas Gilbert devip->nr_closed--; 4843f0d1cf93SDouglas Gilbert 48442d62253eSShin'ichiro Kawasaki if (zsp->z_wp > zsp->z_start) 48452d62253eSShin'ichiro Kawasaki memset(sip->storep + zsp->z_start * sdebug_sector_size, 0, 48462d62253eSShin'ichiro Kawasaki (zsp->z_wp - zsp->z_start) * sdebug_sector_size); 48472d62253eSShin'ichiro Kawasaki 484864e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4849f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4850f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4851f0d1cf93SDouglas Gilbert } 4852f0d1cf93SDouglas Gilbert 4853f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4854f0d1cf93SDouglas Gilbert { 4855f0d1cf93SDouglas Gilbert unsigned int i; 4856f0d1cf93SDouglas Gilbert 4857f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4858f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4859f0d1cf93SDouglas Gilbert } 4860f0d1cf93SDouglas Gilbert 4861f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4862f0d1cf93SDouglas Gilbert { 4863f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4864f0d1cf93SDouglas Gilbert int res = 0; 4865f0d1cf93SDouglas Gilbert u64 z_id; 4866f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4867f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4868b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4869f0d1cf93SDouglas Gilbert 4870f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4871f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4872f0d1cf93SDouglas Gilbert return check_condition_result; 4873f0d1cf93SDouglas Gilbert } 4874f0d1cf93SDouglas Gilbert 48757109f370SDouglas Gilbert sdeb_write_lock(sip); 4876f0d1cf93SDouglas Gilbert 4877f0d1cf93SDouglas Gilbert if (all) { 4878f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4879f0d1cf93SDouglas Gilbert goto fini; 4880f0d1cf93SDouglas Gilbert } 4881f0d1cf93SDouglas Gilbert 4882f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4883f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4884f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4885f0d1cf93SDouglas Gilbert res = check_condition_result; 4886f0d1cf93SDouglas Gilbert goto fini; 4887f0d1cf93SDouglas Gilbert } 4888f0d1cf93SDouglas Gilbert 4889f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4890f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4891f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4892f0d1cf93SDouglas Gilbert res = check_condition_result; 4893f0d1cf93SDouglas Gilbert goto fini; 4894f0d1cf93SDouglas Gilbert } 4895f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4896f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4897f0d1cf93SDouglas Gilbert res = check_condition_result; 4898f0d1cf93SDouglas Gilbert goto fini; 4899f0d1cf93SDouglas Gilbert } 4900f0d1cf93SDouglas Gilbert 4901f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4902f0d1cf93SDouglas Gilbert fini: 49037109f370SDouglas Gilbert sdeb_write_unlock(sip); 4904f0d1cf93SDouglas Gilbert return res; 4905f0d1cf93SDouglas Gilbert } 4906f0d1cf93SDouglas Gilbert 4907c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4908c4837394SDouglas Gilbert { 4909c10fa55fSJohn Garry u16 hwq; 4910a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4911c10fa55fSJohn Garry 4912c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4913c4837394SDouglas Gilbert 4914458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4915458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4916458df78bSBart Van Assche hwq = 0; 4917f7c4cdc7SJohn Garry 4918458df78bSBart Van Assche return sdebug_q_arr + hwq; 4919c4837394SDouglas Gilbert } 4920c4837394SDouglas Gilbert 4921c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4922c10fa55fSJohn Garry { 4923a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4924c10fa55fSJohn Garry } 4925c10fa55fSJohn Garry 4926c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4927fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 49281da177e4SLinus Torvalds { 49291107c7b2SJohn Garry struct sdebug_queued_cmd *sqcp = container_of(sd_dp, struct sdebug_queued_cmd, sd_dp); 4930c4837394SDouglas Gilbert int qc_idx; 4931cbf67842SDouglas Gilbert int retiring = 0; 49321107c7b2SJohn Garry unsigned long flags, iflags; 49331107c7b2SJohn Garry struct scsi_cmnd *scp = sqcp->scmd; 49341107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc; 49351107c7b2SJohn Garry bool aborted; 4936c4837394SDouglas Gilbert struct sdebug_queue *sqp; 49371da177e4SLinus Torvalds 49381107c7b2SJohn Garry qc_idx = sd_dp->sqa_idx; 4939c4837394SDouglas Gilbert if (sdebug_statistics) { 4940cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4941c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4942c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4943c4837394SDouglas Gilbert } 49441107c7b2SJohn Garry if (!scp) { 49451107c7b2SJohn Garry pr_err("scmd=NULL\n"); 49461107c7b2SJohn Garry goto out; 49471107c7b2SJohn Garry } 4948c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4949c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 49501107c7b2SJohn Garry goto out; 49511da177e4SLinus Torvalds } 49521107c7b2SJohn Garry 49531107c7b2SJohn Garry sdsc = scsi_cmd_priv(scp); 49541107c7b2SJohn Garry sqp = get_queue(scp); 4955c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 49561107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 49571107c7b2SJohn Garry aborted = sd_dp->aborted; 49581107c7b2SJohn Garry if (unlikely(aborted)) 49591107c7b2SJohn Garry sd_dp->aborted = false; 49601107c7b2SJohn Garry ASSIGN_QUEUED_CMD(scp, NULL); 4961151f0ec9SJohn Garry 4962f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4963cbf67842SDouglas Gilbert retiring = 1; 4964cbf67842SDouglas Gilbert 49651107c7b2SJohn Garry sqp->qc_arr[qc_idx] = NULL; 4966c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 49671107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 4968c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 49691107c7b2SJohn Garry pr_err("Unexpected completion qc_idx=%d\n", qc_idx); 49701107c7b2SJohn Garry goto out; 49711da177e4SLinus Torvalds } 49721da177e4SLinus Torvalds 4973cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4974cbf67842SDouglas Gilbert int k, retval; 4975cbf67842SDouglas Gilbert 4976cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4977c4837394SDouglas Gilbert if (qc_idx >= retval) { 49781107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 4979c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4980c1287970STomas Winkler pr_err("index %d too large\n", retval); 49811107c7b2SJohn Garry goto out; 4982cbf67842SDouglas Gilbert } 4983c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4984773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4985cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4986cbf67842SDouglas Gilbert else 4987cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4988cbf67842SDouglas Gilbert } 49891107c7b2SJohn Garry 49901107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 4991c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 49921107c7b2SJohn Garry 49931107c7b2SJohn Garry if (aborted) { 4994f037b5cbSJohn Garry pr_info("bypassing scsi_done() due to aborted cmd, kicking-off EH\n"); 4995f037b5cbSJohn Garry blk_abort_request(scsi_cmd_to_rq(scp)); 49961107c7b2SJohn Garry goto out; 49977382f9d8SDouglas Gilbert } 49981107c7b2SJohn Garry 49996c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 50001107c7b2SJohn Garry out: 50011107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 5002cbf67842SDouglas Gilbert } 5003cbf67842SDouglas Gilbert 5004cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 5005fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 5006cbf67842SDouglas Gilbert { 5007a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 5008a10bc12aSDouglas Gilbert hrt); 5009a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 5010cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 5011cbf67842SDouglas Gilbert } 50121da177e4SLinus Torvalds 5013a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 5014fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 5015a10bc12aSDouglas Gilbert { 5016a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 5017a10bc12aSDouglas Gilbert ew.work); 5018a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 5019a10bc12aSDouglas Gilbert } 5020a10bc12aSDouglas Gilbert 502109ba24c1SDouglas Gilbert static bool got_shared_uuid; 5022bf476433SChristoph Hellwig static uuid_t shared_uuid; 502309ba24c1SDouglas Gilbert 5024f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 5025f0d1cf93SDouglas Gilbert { 5026f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 5027f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 50284a5fc1c6SDamien Le Moal sector_t conv_capacity; 5029f0d1cf93SDouglas Gilbert sector_t zstart = 0; 5030f0d1cf93SDouglas Gilbert unsigned int i; 5031f0d1cf93SDouglas Gilbert 5032f0d1cf93SDouglas Gilbert /* 503398e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 503498e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 5035f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 5036f0d1cf93SDouglas Gilbert * created for the device. 5037f0d1cf93SDouglas Gilbert */ 503898e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 5039f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 5040f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5041f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 5042f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 5043f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 5044f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 5045f0d1cf93SDouglas Gilbert return -EINVAL; 5046f0d1cf93SDouglas Gilbert } 5047f0d1cf93SDouglas Gilbert } else { 5048108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 5049108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 5050108e36f0SDamien Le Moal return -EINVAL; 5051108e36f0SDamien Le Moal } 505298e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 5053f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 5054f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 5055f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 5056f0d1cf93SDouglas Gilbert return -EINVAL; 5057f0d1cf93SDouglas Gilbert } 5058f0d1cf93SDouglas Gilbert } 5059f0d1cf93SDouglas Gilbert 5060f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 5061f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 5062f0d1cf93SDouglas Gilbert 50634a5fc1c6SDamien Le Moal if (sdeb_zbc_zone_cap_mb == 0) { 50644a5fc1c6SDamien Le Moal devip->zcap = devip->zsize; 50654a5fc1c6SDamien Le Moal } else { 50664a5fc1c6SDamien Le Moal devip->zcap = (sdeb_zbc_zone_cap_mb * SZ_1M) >> 50674a5fc1c6SDamien Le Moal ilog2(sdebug_sector_size); 50684a5fc1c6SDamien Le Moal if (devip->zcap > devip->zsize) { 50694a5fc1c6SDamien Le Moal pr_err("Zone capacity too large\n"); 50704a5fc1c6SDamien Le Moal return -EINVAL; 50714a5fc1c6SDamien Le Moal } 50724a5fc1c6SDamien Le Moal } 50734a5fc1c6SDamien Le Moal 50744a5fc1c6SDamien Le Moal conv_capacity = (sector_t)sdeb_zbc_nr_conv << devip->zsize_shift; 50754a5fc1c6SDamien Le Moal if (conv_capacity >= capacity) { 5076aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 5077aa8fecf9SDamien Le Moal return -EINVAL; 5078aa8fecf9SDamien Le Moal } 5079aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 50804a5fc1c6SDamien Le Moal devip->nr_seq_zones = ALIGN(capacity - conv_capacity, devip->zsize) >> 50814a5fc1c6SDamien Le Moal devip->zsize_shift; 50824a5fc1c6SDamien Le Moal devip->nr_zones = devip->nr_conv_zones + devip->nr_seq_zones; 50834a5fc1c6SDamien Le Moal 50844a5fc1c6SDamien Le Moal /* Add gap zones if zone capacity is smaller than the zone size */ 50854a5fc1c6SDamien Le Moal if (devip->zcap < devip->zsize) 50864a5fc1c6SDamien Le Moal devip->nr_zones += devip->nr_seq_zones; 5087aa8fecf9SDamien Le Moal 508864e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 508964e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 5090380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 5091f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 5092f0d1cf93SDouglas Gilbert else 5093380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 509464e14eceSDamien Le Moal } 5095f0d1cf93SDouglas Gilbert 5096f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 5097f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 5098f0d1cf93SDouglas Gilbert if (!devip->zstate) 5099f0d1cf93SDouglas Gilbert return -ENOMEM; 5100f0d1cf93SDouglas Gilbert 5101f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 5102f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 5103f0d1cf93SDouglas Gilbert 5104f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 5105f0d1cf93SDouglas Gilbert 5106aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 510735dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_CNV; 5108f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 5109f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 51104a5fc1c6SDamien Le Moal zsp->z_size = 51114a5fc1c6SDamien Le Moal min_t(u64, devip->zsize, capacity - zstart); 51124a5fc1c6SDamien Le Moal } else if ((zstart & (devip->zsize - 1)) == 0) { 511364e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 511435dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWR; 511564e14eceSDamien Le Moal else 511635dbe2b9SDamien Le Moal zsp->z_type = ZBC_ZTYPE_SWP; 5117f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 5118f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 51194a5fc1c6SDamien Le Moal zsp->z_size = 51204a5fc1c6SDamien Le Moal min_t(u64, devip->zcap, capacity - zstart); 51214a5fc1c6SDamien Le Moal } else { 51224a5fc1c6SDamien Le Moal zsp->z_type = ZBC_ZTYPE_GAP; 51234a5fc1c6SDamien Le Moal zsp->z_cond = ZBC_NOT_WRITE_POINTER; 51244a5fc1c6SDamien Le Moal zsp->z_wp = (sector_t)-1; 51254a5fc1c6SDamien Le Moal zsp->z_size = min_t(u64, devip->zsize - devip->zcap, 51264a5fc1c6SDamien Le Moal capacity - zstart); 5127f0d1cf93SDouglas Gilbert } 5128f0d1cf93SDouglas Gilbert 51294a5fc1c6SDamien Le Moal WARN_ON_ONCE((int)zsp->z_size <= 0); 5130f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 5131f0d1cf93SDouglas Gilbert } 5132f0d1cf93SDouglas Gilbert 5133f0d1cf93SDouglas Gilbert return 0; 5134f0d1cf93SDouglas Gilbert } 5135f0d1cf93SDouglas Gilbert 5136fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 5137fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 51385cb2fc06SFUJITA Tomonori { 51395cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 51405cb2fc06SFUJITA Tomonori 51415cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 51425cb2fc06SFUJITA Tomonori if (devip) { 514309ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 5144bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 514509ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 514609ba24c1SDouglas Gilbert if (got_shared_uuid) 514709ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 514809ba24c1SDouglas Gilbert else { 5149bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 515009ba24c1SDouglas Gilbert got_shared_uuid = true; 515109ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 515209ba24c1SDouglas Gilbert } 515309ba24c1SDouglas Gilbert } 51545cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 5155f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 515664e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 5157f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 5158f0d1cf93SDouglas Gilbert kfree(devip); 5159f0d1cf93SDouglas Gilbert return NULL; 5160f0d1cf93SDouglas Gilbert } 516164e14eceSDamien Le Moal } else { 516264e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 5163f0d1cf93SDouglas Gilbert } 5164fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 5165fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 51665cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 51675cb2fc06SFUJITA Tomonori } 51685cb2fc06SFUJITA Tomonori return devip; 51695cb2fc06SFUJITA Tomonori } 51705cb2fc06SFUJITA Tomonori 5171f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 51721da177e4SLinus Torvalds { 51731da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51741da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 5175f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 51761da177e4SLinus Torvalds 5177785d6b7cSJohn Garry sdbg_host = shost_to_sdebug_host(sdev->host); 5178ad0c7775SDouglas Gilbert 51791da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 51801da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 51811da177e4SLinus Torvalds (devip->target == sdev->id) && 51821da177e4SLinus Torvalds (devip->lun == sdev->lun)) 51831da177e4SLinus Torvalds return devip; 51841da177e4SLinus Torvalds else { 51851da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 51861da177e4SLinus Torvalds open_devip = devip; 51871da177e4SLinus Torvalds } 51881da177e4SLinus Torvalds } 51895cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 51905cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 51915cb2fc06SFUJITA Tomonori if (!open_devip) { 5192c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51931da177e4SLinus Torvalds return NULL; 51941da177e4SLinus Torvalds } 51951da177e4SLinus Torvalds } 5196a75869d1SFUJITA Tomonori 51971da177e4SLinus Torvalds open_devip->channel = sdev->channel; 51981da177e4SLinus Torvalds open_devip->target = sdev->id; 51991da177e4SLinus Torvalds open_devip->lun = sdev->lun; 52001da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 5201500d0d24SDouglas Gilbert set_bit(SDEBUG_UA_POOCCUR, open_devip->uas_bm); 5202c2248fc9SDouglas Gilbert open_devip->used = true; 52031da177e4SLinus Torvalds return open_devip; 52041da177e4SLinus Torvalds } 52051da177e4SLinus Torvalds 52068dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 52071da177e4SLinus Torvalds { 5208773642d9SDouglas Gilbert if (sdebug_verbose) 5209c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 52108dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52118dea0d02SFUJITA Tomonori return 0; 52128dea0d02SFUJITA Tomonori } 52131da177e4SLinus Torvalds 52148dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 52158dea0d02SFUJITA Tomonori { 5216f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5217f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5218a34c4e98SFUJITA Tomonori 5219773642d9SDouglas Gilbert if (sdebug_verbose) 5220c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 52218dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5222b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5223b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 5224b01f6f83SDouglas Gilbert if (devip == NULL) { 5225f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5226b01f6f83SDouglas Gilbert if (devip == NULL) 52278dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5228f46eb0e9SDouglas Gilbert } 5229c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5230773642d9SDouglas Gilbert if (sdebug_no_uld) 523178d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 52329b760fd8SDouglas Gilbert config_cdb_len(sdp); 52338dea0d02SFUJITA Tomonori return 0; 52348dea0d02SFUJITA Tomonori } 52358dea0d02SFUJITA Tomonori 52368dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 52378dea0d02SFUJITA Tomonori { 52388dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 52398dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 52408dea0d02SFUJITA Tomonori 5241773642d9SDouglas Gilbert if (sdebug_verbose) 5242c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 52438dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 52448dea0d02SFUJITA Tomonori if (devip) { 524525985edcSLucas De Marchi /* make this slot available for re-use */ 5246c2248fc9SDouglas Gilbert devip->used = false; 52478dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 52488dea0d02SFUJITA Tomonori } 52498dea0d02SFUJITA Tomonori } 52508dea0d02SFUJITA Tomonori 52511107c7b2SJohn Garry /* Returns true if we require the queued memory to be freed by the caller. */ 52521107c7b2SJohn Garry static bool stop_qc_helper(struct sdebug_defer *sd_dp, 525310bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5254c4837394SDouglas Gilbert { 52551107c7b2SJohn Garry if (defer_t == SDEB_DEFER_HRT) { 52561107c7b2SJohn Garry int res = hrtimer_try_to_cancel(&sd_dp->hrt); 5257c4837394SDouglas Gilbert 52581107c7b2SJohn Garry switch (res) { 52591107c7b2SJohn Garry case 0: /* Not active, it must have already run */ 52601107c7b2SJohn Garry case -1: /* -1 It's executing the CB */ 52611107c7b2SJohn Garry return false; 52621107c7b2SJohn Garry case 1: /* Was active, we've now cancelled */ 52631107c7b2SJohn Garry default: 5264a10bc12aSDouglas Gilbert return true; 52658dea0d02SFUJITA Tomonori } 52661107c7b2SJohn Garry } else if (defer_t == SDEB_DEFER_WQ) { 52671107c7b2SJohn Garry /* Cancel if pending */ 52681107c7b2SJohn Garry if (cancel_work_sync(&sd_dp->ew.work)) 52691107c7b2SJohn Garry return true; 52701107c7b2SJohn Garry /* Was not pending, so it must have run */ 52711107c7b2SJohn Garry return false; 52721107c7b2SJohn Garry } else if (defer_t == SDEB_DEFER_POLL) { 52731107c7b2SJohn Garry return true; 5274cbf67842SDouglas Gilbert } 52751107c7b2SJohn Garry 52761107c7b2SJohn Garry return false; 52771107c7b2SJohn Garry } 52781107c7b2SJohn Garry 52791107c7b2SJohn Garry 52801107c7b2SJohn Garry static bool scsi_debug_stop_cmnd(struct scsi_cmnd *cmnd, int *sqa_idx) 52811107c7b2SJohn Garry { 52821107c7b2SJohn Garry enum sdeb_defer_type l_defer_t; 52831107c7b2SJohn Garry struct sdebug_queued_cmd *sqcp; 52841107c7b2SJohn Garry struct sdebug_defer *sd_dp; 52851107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); 52861107c7b2SJohn Garry 52871107c7b2SJohn Garry lockdep_assert_held(&sdsc->lock); 52881107c7b2SJohn Garry 52891107c7b2SJohn Garry sqcp = TO_QUEUED_CMD(cmnd); 52901107c7b2SJohn Garry if (!sqcp) 52911107c7b2SJohn Garry return false; 52921107c7b2SJohn Garry sd_dp = &sqcp->sd_dp; 52931107c7b2SJohn Garry if (sqa_idx) 52941107c7b2SJohn Garry *sqa_idx = sd_dp->sqa_idx; 52951107c7b2SJohn Garry l_defer_t = READ_ONCE(sd_dp->defer_t); 52961107c7b2SJohn Garry ASSIGN_QUEUED_CMD(cmnd, NULL); 52971107c7b2SJohn Garry 52981107c7b2SJohn Garry if (stop_qc_helper(sd_dp, l_defer_t)) 52991107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 53001107c7b2SJohn Garry 53011107c7b2SJohn Garry return true; 53021107c7b2SJohn Garry } 53031107c7b2SJohn Garry 53041107c7b2SJohn Garry /* 53051107c7b2SJohn Garry * Called from scsi_debug_abort() only, which is for timed-out cmd. 53061107c7b2SJohn Garry */ 53071107c7b2SJohn Garry static bool scsi_debug_abort_cmnd(struct scsi_cmnd *cmnd) 53081107c7b2SJohn Garry { 53091107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); 53101107c7b2SJohn Garry struct sdebug_queue *sqp = get_queue(cmnd); 53111107c7b2SJohn Garry unsigned long flags, iflags; 53121107c7b2SJohn Garry int k = -1; 53131107c7b2SJohn Garry bool res; 53141107c7b2SJohn Garry 53151107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 53161107c7b2SJohn Garry res = scsi_debug_stop_cmnd(cmnd, &k); 53171107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 53181107c7b2SJohn Garry 53191107c7b2SJohn Garry if (k >= 0) { 53201107c7b2SJohn Garry spin_lock_irqsave(&sqp->qc_lock, iflags); 53211107c7b2SJohn Garry clear_bit(k, sqp->in_use_bm); 53221107c7b2SJohn Garry sqp->qc_arr[k] = NULL; 5323c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5324c4837394SDouglas Gilbert } 53251107c7b2SJohn Garry 53261107c7b2SJohn Garry return res; 53278dea0d02SFUJITA Tomonori } 53288dea0d02SFUJITA Tomonori 5329a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 5330f19fe8f3SBart Van Assche static void stop_all_queued(void) 53318dea0d02SFUJITA Tomonori { 53321107c7b2SJohn Garry unsigned long iflags, flags; 5333c4837394SDouglas Gilbert int j, k; 5334c4837394SDouglas Gilbert struct sdebug_queue *sqp; 53358dea0d02SFUJITA Tomonori 5336c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5337c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5338c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5339c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 53401107c7b2SJohn Garry struct sdebug_queued_cmd *sqcp = sqp->qc_arr[k]; 53411107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc; 53421107c7b2SJohn Garry struct scsi_cmnd *scmd; 53431107c7b2SJohn Garry 53441107c7b2SJohn Garry if (!sqcp) 5345a10bc12aSDouglas Gilbert continue; 53461107c7b2SJohn Garry scmd = sqcp->scmd; 53471107c7b2SJohn Garry if (!scmd) 53481107c7b2SJohn Garry continue; 53491107c7b2SJohn Garry sdsc = scsi_cmd_priv(scmd); 53501107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 53511107c7b2SJohn Garry if (TO_QUEUED_CMD(scmd) != sqcp) { 53521107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 53531107c7b2SJohn Garry continue; 53541107c7b2SJohn Garry } 53551107c7b2SJohn Garry scsi_debug_stop_cmnd(scmd, NULL); 53561107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 53571107c7b2SJohn Garry sqp->qc_arr[k] = NULL; 5358c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 53598dea0d02SFUJITA Tomonori } 53608dea0d02SFUJITA Tomonori } 5361c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5362c4837394SDouglas Gilbert } 5363cbf67842SDouglas Gilbert } 5364cbf67842SDouglas Gilbert 53651da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 53661da177e4SLinus Torvalds { 53671107c7b2SJohn Garry bool ok = scsi_debug_abort_cmnd(SCpnt); 5368a10bc12aSDouglas Gilbert 53691da177e4SLinus Torvalds ++num_aborts; 537006be9fbeSJohn Garry 537106be9fbeSJohn Garry if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5372a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5373a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5374a10bc12aSDouglas Gilbert ok ? "" : " not"); 537506be9fbeSJohn Garry 53761da177e4SLinus Torvalds return SUCCESS; 53771da177e4SLinus Torvalds } 53781da177e4SLinus Torvalds 53791da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 53801da177e4SLinus Torvalds { 5381cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5382a19226f8SJohn Garry struct sdebug_dev_info *devip = sdp->hostdata; 5383a19226f8SJohn Garry 5384a19226f8SJohn Garry ++num_dev_resets; 5385cbf67842SDouglas Gilbert 5386773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5387cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 53881da177e4SLinus Torvalds if (devip) 5389cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 5390a19226f8SJohn Garry 53911da177e4SLinus Torvalds return SUCCESS; 53921da177e4SLinus Torvalds } 53931da177e4SLinus Torvalds 5394cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5395cbf67842SDouglas Gilbert { 5396a15df530SJohn Garry struct scsi_device *sdp = SCpnt->device; 5397a15df530SJohn Garry struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host); 5398cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5399cbf67842SDouglas Gilbert int k = 0; 5400cbf67842SDouglas Gilbert 5401cbf67842SDouglas Gilbert ++num_target_resets; 5402773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5403cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5404a15df530SJohn Garry 5405a15df530SJohn Garry list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 5406cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5407cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5408cbf67842SDouglas Gilbert ++k; 5409cbf67842SDouglas Gilbert } 5410cbf67842SDouglas Gilbert } 5411a15df530SJohn Garry 5412773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5413cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5414cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5415a15df530SJohn Garry 5416cbf67842SDouglas Gilbert return SUCCESS; 5417cbf67842SDouglas Gilbert } 5418cbf67842SDouglas Gilbert 54191da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 54201da177e4SLinus Torvalds { 5421519bfc14SJohn Garry struct scsi_device *sdp = SCpnt->device; 5422519bfc14SJohn Garry struct sdebug_host_info *sdbg_host = shost_to_sdebug_host(sdp->host); 5423cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5424cbf67842SDouglas Gilbert int k = 0; 54251da177e4SLinus Torvalds 54261da177e4SLinus Torvalds ++num_bus_resets; 5427519bfc14SJohn Garry 5428773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5429cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5430519bfc14SJohn Garry 5431519bfc14SJohn Garry list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 5432cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5433cbf67842SDouglas Gilbert ++k; 54341da177e4SLinus Torvalds } 5435519bfc14SJohn Garry 5436773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5437cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5438cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 54391da177e4SLinus Torvalds return SUCCESS; 54401da177e4SLinus Torvalds } 54411da177e4SLinus Torvalds 54421da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 54431da177e4SLinus Torvalds { 54441da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5445cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5446cbf67842SDouglas Gilbert int k = 0; 54471da177e4SLinus Torvalds 54481da177e4SLinus Torvalds ++num_host_resets; 54499c230382SJohn Garry if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5450cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 54510aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 54521da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5453cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5454cbf67842SDouglas Gilbert dev_list) { 5455cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5456cbf67842SDouglas Gilbert ++k; 5457cbf67842SDouglas Gilbert } 54581da177e4SLinus Torvalds } 54590aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 5460f19fe8f3SBart Van Assche stop_all_queued(); 5461773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5462cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5463cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 54641da177e4SLinus Torvalds return SUCCESS; 54651da177e4SLinus Torvalds } 54661da177e4SLinus Torvalds 546787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 54681da177e4SLinus Torvalds { 54691442f76dSChristoph Hellwig struct msdos_partition *pp; 5470979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 54711da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 54721da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 54731da177e4SLinus Torvalds 54741da177e4SLinus Torvalds /* assume partition table already zeroed */ 5475773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 54761da177e4SLinus Torvalds return; 5477773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5478773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5479c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 54801da177e4SLinus Torvalds } 54818c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 54821da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5483773642d9SDouglas Gilbert / sdebug_num_parts; 54841da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 54851da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5486979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5487979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 54881da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 54891da177e4SLinus Torvalds * heads_by_sects; 5490979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5491979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5492979e0dc3SJohn Pittman } 5493773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5494773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 54951da177e4SLinus Torvalds 54961da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 54971da177e4SLinus Torvalds ramp[511] = 0xAA; 54981442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 54991da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 55001da177e4SLinus Torvalds start_sec = starts[k]; 5501979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 55021da177e4SLinus Torvalds pp->boot_ind = 0; 55031da177e4SLinus Torvalds 55041da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 55051da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 55061da177e4SLinus Torvalds / sdebug_sectors_per; 55071da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 55081da177e4SLinus Torvalds 55091da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 55101da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 55111da177e4SLinus Torvalds / sdebug_sectors_per; 55121da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 55131da177e4SLinus Torvalds 5514150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5515150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 55161da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 55171da177e4SLinus Torvalds } 55181da177e4SLinus Torvalds } 55191da177e4SLinus Torvalds 5520f19fe8f3SBart Van Assche static void block_unblock_all_queues(bool block) 5521c4837394SDouglas Gilbert { 5522a0473bf3SJohn Garry struct sdebug_host_info *sdhp; 5523c4837394SDouglas Gilbert 552425b80b2cSJohn Garry lockdep_assert_held(&sdebug_host_list_mutex); 552525b80b2cSJohn Garry 5526a0473bf3SJohn Garry list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 5527a0473bf3SJohn Garry struct Scsi_Host *shost = sdhp->shost; 5528a0473bf3SJohn Garry 5529a0473bf3SJohn Garry if (block) 5530a0473bf3SJohn Garry scsi_block_requests(shost); 5531a0473bf3SJohn Garry else 5532a0473bf3SJohn Garry scsi_unblock_requests(shost); 5533a0473bf3SJohn Garry } 5534c4837394SDouglas Gilbert } 5535c4837394SDouglas Gilbert 5536c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5537c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5538c4837394SDouglas Gilbert */ 5539c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5540c4837394SDouglas Gilbert { 5541c4837394SDouglas Gilbert int count, modulo; 5542c4837394SDouglas Gilbert 5543c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5544c4837394SDouglas Gilbert if (modulo < 2) 5545c4837394SDouglas Gilbert return; 554625b80b2cSJohn Garry 554725b80b2cSJohn Garry mutex_lock(&sdebug_host_list_mutex); 5548f19fe8f3SBart Van Assche block_unblock_all_queues(true); 5549c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5550c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 5551f19fe8f3SBart Van Assche block_unblock_all_queues(false); 555225b80b2cSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 5553c4837394SDouglas Gilbert } 5554c4837394SDouglas Gilbert 5555c4837394SDouglas Gilbert static void clear_queue_stats(void) 5556c4837394SDouglas Gilbert { 5557c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5558c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5559c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5560c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5561c4837394SDouglas Gilbert } 5562c4837394SDouglas Gilbert 55633a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5564c4837394SDouglas Gilbert { 55653a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 55663a90a63dSDouglas Gilbert return false; 55673a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5568c4837394SDouglas Gilbert } 5569c4837394SDouglas Gilbert 5570a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5571a2aede97SDouglas Gilbert 55721107c7b2SJohn Garry 55731107c7b2SJohn Garry void sdebug_free_queued_cmd(struct sdebug_queued_cmd *sqcp) 55741107c7b2SJohn Garry { 55751107c7b2SJohn Garry if (sqcp) 55761107c7b2SJohn Garry kmem_cache_free(queued_cmd_cache, sqcp); 55771107c7b2SJohn Garry } 55781107c7b2SJohn Garry 55791107c7b2SJohn Garry static struct sdebug_queued_cmd *sdebug_alloc_queued_cmd(struct scsi_cmnd *scmd) 55801107c7b2SJohn Garry { 55811107c7b2SJohn Garry struct sdebug_queued_cmd *sqcp; 55821107c7b2SJohn Garry struct sdebug_defer *sd_dp; 55831107c7b2SJohn Garry 55841107c7b2SJohn Garry sqcp = kmem_cache_zalloc(queued_cmd_cache, GFP_ATOMIC); 55851107c7b2SJohn Garry if (!sqcp) 55861107c7b2SJohn Garry return NULL; 55871107c7b2SJohn Garry 55881107c7b2SJohn Garry sd_dp = &sqcp->sd_dp; 55891107c7b2SJohn Garry 55901107c7b2SJohn Garry hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL_PINNED); 55911107c7b2SJohn Garry sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 55921107c7b2SJohn Garry INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 55931107c7b2SJohn Garry 55941107c7b2SJohn Garry sqcp->scmd = scmd; 55951107c7b2SJohn Garry sd_dp->sqa_idx = -1; 55961107c7b2SJohn Garry 55971107c7b2SJohn Garry return sqcp; 55981107c7b2SJohn Garry } 55991107c7b2SJohn Garry 5600c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5601c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5602c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5603c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5604c4837394SDouglas Gilbert */ 5605fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5606f66b8517SMartin Wilck int scsi_result, 5607f19fe8f3SBart Van Assche int (*pfp)(struct scsi_cmnd *, 5608f19fe8f3SBart Van Assche struct sdebug_dev_info *), 5609f66b8517SMartin Wilck int delta_jiff, int ndelay) 56101da177e4SLinus Torvalds { 56111107c7b2SJohn Garry struct request *rq = scsi_cmd_to_rq(cmnd); 56121107c7b2SJohn Garry bool polled = rq->cmd_flags & REQ_POLLED; 56131107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmnd); 56141107c7b2SJohn Garry unsigned long iflags, flags; 5615a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5616c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5617c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5618299b6c07STomas Winkler struct scsi_device *sdp; 5619a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 56201107c7b2SJohn Garry int k; 56211da177e4SLinus Torvalds 5622b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5623b01f6f83SDouglas Gilbert if (scsi_result == 0) 5624f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5625f46eb0e9SDouglas Gilbert goto respond_in_thread; 56261da177e4SLinus Torvalds } 5627299b6c07STomas Winkler sdp = cmnd->device; 5628299b6c07STomas Winkler 5629f19fe8f3SBart Van Assche if (delta_jiff == 0) 5630cd62b7daSDouglas Gilbert goto respond_in_thread; 56311da177e4SLinus Torvalds 5632c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5633c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5634151f0ec9SJohn Garry 56350befb879SJohn Garry if (unlikely(sdebug_every_nth && (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5636f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5637151f0ec9SJohn Garry int num_in_q = scsi_device_busy(sdp); 5638151f0ec9SJohn Garry int qdepth = cmnd->device->queue_depth; 5639151f0ec9SJohn Garry 56406500d204SJohn Garry if ((num_in_q == qdepth) && 5641cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5642773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5643cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5644cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5645151f0ec9SJohn Garry 5646151f0ec9SJohn Garry if (unlikely(SDEBUG_OPT_Q_NOISE & sdebug_opts)) 5647151f0ec9SJohn Garry sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, <inject> status: TASK SET FULL\n", 5648151f0ec9SJohn Garry __func__, num_in_q); 56491da177e4SLinus Torvalds } 5650cbf67842SDouglas Gilbert } 5651cbf67842SDouglas Gilbert 5652c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5653f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5654c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5655cd62b7daSDouglas Gilbert if (scsi_result) 5656cd62b7daSDouglas Gilbert goto respond_in_thread; 5657cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5658773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 56597d5a129bSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n", 56607d5a129bSDouglas Gilbert __func__, sdebug_max_queue); 5661cd62b7daSDouglas Gilbert goto respond_in_thread; 56621da177e4SLinus Torvalds } 566374595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5664c4b57d89SKashyap Desai 56651107c7b2SJohn Garry sqcp = sdebug_alloc_queued_cmd(cmnd); 56661107c7b2SJohn Garry if (!sqcp) { 566774595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 56681107c7b2SJohn Garry spin_unlock_irqrestore(&sqp->qc_lock, iflags); 566910bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 567074595c04SDouglas Gilbert } 56711107c7b2SJohn Garry sd_dp = &sqcp->sd_dp; 56721107c7b2SJohn Garry sd_dp->sqa_idx = k; 56731107c7b2SJohn Garry sqp->qc_arr[k] = sqcp; 56741107c7b2SJohn Garry spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5675f66b8517SMartin Wilck 5676c10fa55fSJohn Garry /* Set the hostwide tag */ 5677c10fa55fSJohn Garry if (sdebug_host_max_queue) 5678c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5679c10fa55fSJohn Garry 56806ce913feSChristoph Hellwig if (polled) 5681a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5682a2aede97SDouglas Gilbert 5683a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 56843a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5685f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5686f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5687f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5688f66b8517SMartin Wilck } 5689f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5690f66b8517SMartin Wilck cmnd->result = scsi_result; 56913a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 56923a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 56933a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 56943a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 56953a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 56963a90a63dSDouglas Gilbert } 56973a90a63dSDouglas Gilbert } 5698f66b8517SMartin Wilck 5699f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5700f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5701f66b8517SMartin Wilck __func__, cmnd->result); 5702f66b8517SMartin Wilck 570310bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5704b333a819SDouglas Gilbert ktime_t kt; 5705cbf67842SDouglas Gilbert 5706b333a819SDouglas Gilbert if (delta_jiff > 0) { 57070c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 57080c4bc91dSDouglas Gilbert 57090c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 57108032bf12SJason A. Donenfeld ns = get_random_u32_below((u32)ns); 57110c4bc91dSDouglas Gilbert } else if (sdebug_random) { 57120c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 57130c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 57148032bf12SJason A. Donenfeld ns = get_random_u32_below((u32)ns); 57150c4bc91dSDouglas Gilbert ns <<= 12; 57160c4bc91dSDouglas Gilbert } 57170c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 57180c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 57198032bf12SJason A. Donenfeld kt = sdebug_random ? get_random_u32_below((u32)ndelay) : 57200c4bc91dSDouglas Gilbert (u32)ndelay; 5721a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5722a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5723a2aede97SDouglas Gilbert 5724a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5725223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 57261107c7b2SJohn Garry sqp->qc_arr[k] = NULL; 5727a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5728223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5729a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 57301107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 57316c2c7d6aSBart Van Assche scsi_done(cmnd); 5732a2aede97SDouglas Gilbert return 0; 5733a2aede97SDouglas Gilbert } 5734a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5735a2aede97SDouglas Gilbert kt -= d; 5736a2aede97SDouglas Gilbert } 57370c4bc91dSDouglas Gilbert } 57384a0c6f43SDouglas Gilbert if (sdebug_statistics) 57394a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 57401107c7b2SJohn Garry if (polled) { 57411107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 57421107c7b2SJohn Garry sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 57431107c7b2SJohn Garry ASSIGN_QUEUED_CMD(cmnd, sqcp); 57441107c7b2SJohn Garry WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57451107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 57461107c7b2SJohn Garry } else { 57471107c7b2SJohn Garry /* schedule the invocation of scsi_done() for a later time */ 57481107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 57491107c7b2SJohn Garry ASSIGN_QUEUED_CMD(cmnd, sqcp); 57501107c7b2SJohn Garry WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); 57511107c7b2SJohn Garry hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 57521107c7b2SJohn Garry /* 57531107c7b2SJohn Garry * The completion handler will try to grab sqcp->lock, 57541107c7b2SJohn Garry * so there is no chance that the completion handler 57551107c7b2SJohn Garry * will call scsi_done() until we release the lock 57561107c7b2SJohn Garry * here (so ok to keep referencing sdsc). 57571107c7b2SJohn Garry */ 57581107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 57591107c7b2SJohn Garry } 5760c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 57614a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 5762f037b5cbSJohn Garry atomic_read(&sdeb_inject_pending))) { 57634a0c6f43SDouglas Gilbert sd_dp->aborted = true; 5764f037b5cbSJohn Garry atomic_set(&sdeb_inject_pending, 0); 5765f037b5cbSJohn Garry sdev_printk(KERN_INFO, sdp, "abort request tag=%#x\n", 5766f037b5cbSJohn Garry blk_mq_unique_tag_to_tag(get_tag(cmnd))); 5767f037b5cbSJohn Garry } 5768f037b5cbSJohn Garry 5769c4837394SDouglas Gilbert if (sdebug_statistics) 5770c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 57711107c7b2SJohn Garry if (polled) { 57721107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 57731107c7b2SJohn Garry ASSIGN_QUEUED_CMD(cmnd, sqcp); 57741107c7b2SJohn Garry sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 57751107c7b2SJohn Garry WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 57761107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 57771107c7b2SJohn Garry } else { 57781107c7b2SJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 57791107c7b2SJohn Garry ASSIGN_QUEUED_CMD(cmnd, sqcp); 57801107c7b2SJohn Garry WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); 57811107c7b2SJohn Garry schedule_work(&sd_dp->ew.work); 57821107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 57831107c7b2SJohn Garry } 5784cbf67842SDouglas Gilbert } 5785151f0ec9SJohn Garry 57861da177e4SLinus Torvalds return 0; 5787cd62b7daSDouglas Gilbert 5788cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5789f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5790f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5791f19fe8f3SBart Van Assche if (cmnd->result == 0 && scsi_result != 0) 5792cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 57936c2c7d6aSBart Van Assche scsi_done(cmnd); 5794cd62b7daSDouglas Gilbert return 0; 57951da177e4SLinus Torvalds } 5796cbf67842SDouglas Gilbert 579723183910SDouglas Gilbert /* Note: The following macros create attribute files in the 579823183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 579923183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 580023183910SDouglas Gilbert as it can when the corresponding attribute in the 580123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 580223183910SDouglas Gilbert */ 5803773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5804773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 58059b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5806773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5807c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5808773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5809773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5810773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5811773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5812773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5813773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5814773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5815773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5816c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5817e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5818e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5819e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5820e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 58215d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 58225d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 58235d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5824773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5825773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5826773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5827773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5828ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5829773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5830773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 58315d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 58325d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 58335d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 58345d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5835773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5836773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 58377109f370SDouglas Gilbert module_param_named(no_rwlock, sdebug_no_rwlock, bool, S_IRUGO | S_IWUSR); 5838773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5839773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5840773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5841773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 58425d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5843773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 584487c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 584587c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5846773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5847773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 58480c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5849773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5850773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5851773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5852c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5853773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5854c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5855c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5856fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5857773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5858773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5859773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5860773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 586109ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 58625d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5863773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 586423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 58659447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5866773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 58675b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 58689267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 58694a5fc1c6SDamien Le Moal module_param_named(zone_cap_mb, sdeb_zbc_zone_cap_mb, int, S_IRUGO); 5870380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5871aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 587298e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 58731da177e4SLinus Torvalds 58741da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 58751da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 58761da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5877b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 58781da177e4SLinus Torvalds 58795d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 58805b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 58819b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 58820759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5883cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5884c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 58855b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 58865b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5887c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5888beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 588923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 58905b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5891185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5892c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5893c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5894e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 58959b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 58969b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 58975d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 58985d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 58995d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 59005b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 59015b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 59025b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 59035b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5904ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5905fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5906cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5907d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 59085d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5909cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5910c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 59117109f370SDouglas Gilbert MODULE_PARM_DESC(no_rwlock, "don't protect user data reads+writes (def=0)"); 591278d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 59131da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5914c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 591532c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 591686e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 59175d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 59185d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 59195d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5920fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 59211da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 59220c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5923d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5924760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5925ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5926c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5927c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5928c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5929fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 59305b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 59315b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 59326014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 59336014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 593409ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 593509ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5936c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 59375b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 59389447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 59395b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 59409267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 59414a5fc1c6SDamien Le Moal MODULE_PARM_DESC(zone_cap_mb, "Zone capacity in MiB (def=zone size)"); 5942380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5943aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 594498e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 59451da177e4SLinus Torvalds 5946760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5947760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 59481da177e4SLinus Torvalds 59491da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 59501da177e4SLinus Torvalds { 5951c4837394SDouglas Gilbert int k; 5952c4837394SDouglas Gilbert 5953760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5954760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5955760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5956c4837394SDouglas Gilbert return sdebug_info; 5957760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5958760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5959760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5960760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 59611da177e4SLinus Torvalds return sdebug_info; 59621da177e4SLinus Torvalds } 59631da177e4SLinus Torvalds 5964cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5965fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5966fd32119bSDouglas Gilbert int length) 59671da177e4SLinus Torvalds { 59681da177e4SLinus Torvalds char arr[16]; 5969c8ed555aSAl Viro int opts; 59701da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 59711da177e4SLinus Torvalds 59721da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 59731da177e4SLinus Torvalds return -EACCES; 59741da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 59751da177e4SLinus Torvalds arr[minLen] = '\0'; 5976c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 59771da177e4SLinus Torvalds return -EINVAL; 5978773642d9SDouglas Gilbert sdebug_opts = opts; 5979773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5980773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5981773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5982c4837394SDouglas Gilbert tweak_cmnd_count(); 59831da177e4SLinus Torvalds return length; 59841da177e4SLinus Torvalds } 5985c8ed555aSAl Viro 5986cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5987cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5988cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5989c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5990c8ed555aSAl Viro { 5991c4837394SDouglas Gilbert int f, j, l; 5992c4837394SDouglas Gilbert struct sdebug_queue *sqp; 599387c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5994cbf67842SDouglas Gilbert 5995c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5996c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5997c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5998c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5999c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 6000c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 6001c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 6002c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 6003c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 6004c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 6005c4837394SDouglas Gilbert num_aborts); 6006c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 6007c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 6008c4837394SDouglas Gilbert num_host_resets); 6009c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 6010c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 6011458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 6012458df78bSBart Van Assche sdebug_statistics); 60134a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 6014c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 6015c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 6016c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 60174a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 60184a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 6019cbf67842SDouglas Gilbert 6020c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 6021c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 6022c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 6023c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 6024773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 6025c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 6026c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 6027c4837394SDouglas Gilbert "first,last bits", f, l); 6028c4837394SDouglas Gilbert } 6029cbf67842SDouglas Gilbert } 603087c715dcSDouglas Gilbert 603187c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 603287c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 603387c715dcSDouglas Gilbert bool niu; 603487c715dcSDouglas Gilbert int idx; 603587c715dcSDouglas Gilbert unsigned long l_idx; 603687c715dcSDouglas Gilbert struct sdeb_store_info *sip; 603787c715dcSDouglas Gilbert 603887c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 603987c715dcSDouglas Gilbert j = 0; 604087c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 604187c715dcSDouglas Gilbert idx = sdhp->si_idx; 604287c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 604387c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 604487c715dcSDouglas Gilbert ++j; 604587c715dcSDouglas Gilbert } 604687c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 604787c715dcSDouglas Gilbert sdeb_most_recent_idx); 604887c715dcSDouglas Gilbert j = 0; 604987c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 605087c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 605187c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 605287c715dcSDouglas Gilbert idx = (int)l_idx; 605387c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 605487c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 605587c715dcSDouglas Gilbert ++j; 605687c715dcSDouglas Gilbert } 605787c715dcSDouglas Gilbert } 6058c8ed555aSAl Viro return 0; 60591da177e4SLinus Torvalds } 60601da177e4SLinus Torvalds 606182069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 60621da177e4SLinus Torvalds { 6063c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 60641da177e4SLinus Torvalds } 6065c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 6066c4837394SDouglas Gilbert * of delay is jiffies. 6067c4837394SDouglas Gilbert */ 606882069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 606982069379SAkinobu Mita size_t count) 60701da177e4SLinus Torvalds { 6071c2206098SDouglas Gilbert int jdelay, res; 60721da177e4SLinus Torvalds 6073b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 6074cbf67842SDouglas Gilbert res = count; 6075c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 6076c4837394SDouglas Gilbert int j, k; 6077c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6078cbf67842SDouglas Gilbert 607925b80b2cSJohn Garry mutex_lock(&sdebug_host_list_mutex); 6080f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6081c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6082c4837394SDouglas Gilbert ++j, ++sqp) { 6083c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6084c4837394SDouglas Gilbert sdebug_max_queue); 6085c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6086c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6087c4837394SDouglas Gilbert break; 6088c4837394SDouglas Gilbert } 6089c4837394SDouglas Gilbert } 6090c4837394SDouglas Gilbert if (res > 0) { 6091c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 6092773642d9SDouglas Gilbert sdebug_ndelay = 0; 60931da177e4SLinus Torvalds } 6094f19fe8f3SBart Van Assche block_unblock_all_queues(false); 609525b80b2cSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 6096cbf67842SDouglas Gilbert } 6097cbf67842SDouglas Gilbert return res; 60981da177e4SLinus Torvalds } 60991da177e4SLinus Torvalds return -EINVAL; 61001da177e4SLinus Torvalds } 610182069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 61021da177e4SLinus Torvalds 6103cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 6104cbf67842SDouglas Gilbert { 6105773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 6106cbf67842SDouglas Gilbert } 6107cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 6108c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 6109cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 6110cbf67842SDouglas Gilbert size_t count) 6111cbf67842SDouglas Gilbert { 6112c4837394SDouglas Gilbert int ndelay, res; 6113cbf67842SDouglas Gilbert 6114cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 6115c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 6116cbf67842SDouglas Gilbert res = count; 6117773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 6118c4837394SDouglas Gilbert int j, k; 6119c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6120c4837394SDouglas Gilbert 612125b80b2cSJohn Garry mutex_lock(&sdebug_host_list_mutex); 6122f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6123c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6124c4837394SDouglas Gilbert ++j, ++sqp) { 6125c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6126c4837394SDouglas Gilbert sdebug_max_queue); 6127c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6128c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6129c4837394SDouglas Gilbert break; 6130c4837394SDouglas Gilbert } 6131c4837394SDouglas Gilbert } 6132c4837394SDouglas Gilbert if (res > 0) { 6133773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 6134c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 6135c2206098SDouglas Gilbert : DEF_JDELAY; 6136cbf67842SDouglas Gilbert } 6137f19fe8f3SBart Van Assche block_unblock_all_queues(false); 613825b80b2cSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 6139cbf67842SDouglas Gilbert } 6140cbf67842SDouglas Gilbert return res; 6141cbf67842SDouglas Gilbert } 6142cbf67842SDouglas Gilbert return -EINVAL; 6143cbf67842SDouglas Gilbert } 6144cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 6145cbf67842SDouglas Gilbert 614682069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 61471da177e4SLinus Torvalds { 6148773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 61491da177e4SLinus Torvalds } 61501da177e4SLinus Torvalds 615182069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 615282069379SAkinobu Mita size_t count) 61531da177e4SLinus Torvalds { 61541da177e4SLinus Torvalds int opts; 61551da177e4SLinus Torvalds char work[20]; 61561da177e4SLinus Torvalds 61579a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 61589a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 61599a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 61601da177e4SLinus Torvalds goto opts_done; 61611da177e4SLinus Torvalds } else { 61629a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 61631da177e4SLinus Torvalds goto opts_done; 61641da177e4SLinus Torvalds } 61651da177e4SLinus Torvalds } 61661da177e4SLinus Torvalds return -EINVAL; 61671da177e4SLinus Torvalds opts_done: 6168773642d9SDouglas Gilbert sdebug_opts = opts; 6169773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 6170773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 6171c4837394SDouglas Gilbert tweak_cmnd_count(); 61721da177e4SLinus Torvalds return count; 61731da177e4SLinus Torvalds } 617482069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 61751da177e4SLinus Torvalds 617682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 61771da177e4SLinus Torvalds { 6178773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 61791da177e4SLinus Torvalds } 618082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 618182069379SAkinobu Mita size_t count) 61821da177e4SLinus Torvalds { 61831da177e4SLinus Torvalds int n; 61841da177e4SLinus Torvalds 6185f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 6186f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 6187f0d1cf93SDouglas Gilbert return -EINVAL; 6188f0d1cf93SDouglas Gilbert 61891da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6190f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 6191f0d1cf93SDouglas Gilbert return -EINVAL; 6192773642d9SDouglas Gilbert sdebug_ptype = n; 61931da177e4SLinus Torvalds return count; 61941da177e4SLinus Torvalds } 61951da177e4SLinus Torvalds return -EINVAL; 61961da177e4SLinus Torvalds } 619782069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 61981da177e4SLinus Torvalds 619982069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 62001da177e4SLinus Torvalds { 6201773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 62021da177e4SLinus Torvalds } 620382069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 620482069379SAkinobu Mita size_t count) 62051da177e4SLinus Torvalds { 62061da177e4SLinus Torvalds int n; 62071da177e4SLinus Torvalds 62081da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6209773642d9SDouglas Gilbert sdebug_dsense = n; 62101da177e4SLinus Torvalds return count; 62111da177e4SLinus Torvalds } 62121da177e4SLinus Torvalds return -EINVAL; 62131da177e4SLinus Torvalds } 621482069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 62151da177e4SLinus Torvalds 621682069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 621723183910SDouglas Gilbert { 6218773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 621923183910SDouglas Gilbert } 622082069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 622182069379SAkinobu Mita size_t count) 622223183910SDouglas Gilbert { 622387c715dcSDouglas Gilbert int n, idx; 622423183910SDouglas Gilbert 622523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 622687c715dcSDouglas Gilbert bool want_store = (n == 0); 622787c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 622887c715dcSDouglas Gilbert 6229cbf67842SDouglas Gilbert n = (n > 0); 6230773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 623187c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 623287c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6233cbf67842SDouglas Gilbert 623487c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 623587c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 623687c715dcSDouglas Gilbert idx = sdebug_add_store(); 623787c715dcSDouglas Gilbert if (idx < 0) 623887c715dcSDouglas Gilbert return idx; 623987c715dcSDouglas Gilbert } else { 624087c715dcSDouglas Gilbert idx = sdeb_first_idx; 624187c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 624287c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6243cbf67842SDouglas Gilbert } 624487c715dcSDouglas Gilbert /* make all hosts use same store */ 624587c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 624687c715dcSDouglas Gilbert host_list) { 624787c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 624887c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 624987c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 625087c715dcSDouglas Gilbert sdhp->si_idx = idx; 625187c715dcSDouglas Gilbert } 625287c715dcSDouglas Gilbert } 625387c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 625487c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 625587c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6256cbf67842SDouglas Gilbert } 6257773642d9SDouglas Gilbert sdebug_fake_rw = n; 625823183910SDouglas Gilbert return count; 625923183910SDouglas Gilbert } 626023183910SDouglas Gilbert return -EINVAL; 626123183910SDouglas Gilbert } 626282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 626323183910SDouglas Gilbert 626482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6265c65b1445SDouglas Gilbert { 6266773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6267c65b1445SDouglas Gilbert } 626882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 626982069379SAkinobu Mita size_t count) 6270c65b1445SDouglas Gilbert { 6271c65b1445SDouglas Gilbert int n; 6272c65b1445SDouglas Gilbert 6273c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6274773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6275c65b1445SDouglas Gilbert return count; 6276c65b1445SDouglas Gilbert } 6277c65b1445SDouglas Gilbert return -EINVAL; 6278c65b1445SDouglas Gilbert } 627982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6280c65b1445SDouglas Gilbert 628182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 62821da177e4SLinus Torvalds { 6283773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 62841da177e4SLinus Torvalds } 628582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 628682069379SAkinobu Mita size_t count) 62871da177e4SLinus Torvalds { 62881da177e4SLinus Torvalds int n; 62891da177e4SLinus Torvalds 62901da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6291773642d9SDouglas Gilbert sdebug_num_tgts = n; 62921da177e4SLinus Torvalds sdebug_max_tgts_luns(); 62931da177e4SLinus Torvalds return count; 62941da177e4SLinus Torvalds } 62951da177e4SLinus Torvalds return -EINVAL; 62961da177e4SLinus Torvalds } 629782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 62981da177e4SLinus Torvalds 629982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 63001da177e4SLinus Torvalds { 6301773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 63021da177e4SLinus Torvalds } 630382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 63041da177e4SLinus Torvalds 630587c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 630687c715dcSDouglas Gilbert { 630787c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 630887c715dcSDouglas Gilbert } 630987c715dcSDouglas Gilbert 631087c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 631187c715dcSDouglas Gilbert size_t count) 631287c715dcSDouglas Gilbert { 631387c715dcSDouglas Gilbert bool v; 631487c715dcSDouglas Gilbert 631587c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 631687c715dcSDouglas Gilbert return -EINVAL; 631787c715dcSDouglas Gilbert 631887c715dcSDouglas Gilbert sdebug_per_host_store = v; 631987c715dcSDouglas Gilbert return count; 632087c715dcSDouglas Gilbert } 632187c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 632287c715dcSDouglas Gilbert 632382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 63241da177e4SLinus Torvalds { 6325773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 63261da177e4SLinus Torvalds } 632782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 63281da177e4SLinus Torvalds 632982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 63301da177e4SLinus Torvalds { 6331773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 63321da177e4SLinus Torvalds } 633382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 633482069379SAkinobu Mita size_t count) 63351da177e4SLinus Torvalds { 63361da177e4SLinus Torvalds int nth; 63373a90a63dSDouglas Gilbert char work[20]; 63381da177e4SLinus Torvalds 63393a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 63403a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 63413a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 63423a90a63dSDouglas Gilbert goto every_nth_done; 63433a90a63dSDouglas Gilbert } else { 63443a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 63453a90a63dSDouglas Gilbert goto every_nth_done; 63463a90a63dSDouglas Gilbert } 63473a90a63dSDouglas Gilbert } 63483a90a63dSDouglas Gilbert return -EINVAL; 63493a90a63dSDouglas Gilbert 63503a90a63dSDouglas Gilbert every_nth_done: 6351773642d9SDouglas Gilbert sdebug_every_nth = nth; 6352c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6353c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6354c4837394SDouglas Gilbert sdebug_statistics = true; 6355c4837394SDouglas Gilbert } 6356c4837394SDouglas Gilbert tweak_cmnd_count(); 63571da177e4SLinus Torvalds return count; 63581da177e4SLinus Torvalds } 635982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 63601da177e4SLinus Torvalds 6361ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6362ad0c7775SDouglas Gilbert { 6363ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6364ad0c7775SDouglas Gilbert } 6365ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6366ad0c7775SDouglas Gilbert size_t count) 6367ad0c7775SDouglas Gilbert { 6368ad0c7775SDouglas Gilbert int n; 6369ad0c7775SDouglas Gilbert bool changed; 6370ad0c7775SDouglas Gilbert 6371ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6372ad0c7775SDouglas Gilbert return -EINVAL; 6373ad0c7775SDouglas Gilbert if (n >= 0) { 6374ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6375ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6376ad0c7775SDouglas Gilbert return -EINVAL; 6377ad0c7775SDouglas Gilbert } 6378ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6379ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6380ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6381ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6382ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6383ad0c7775SDouglas Gilbert 63840aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 6385ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6386ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6387ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6388ad0c7775SDouglas Gilbert } 6389ad0c7775SDouglas Gilbert } 63900aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 6391ad0c7775SDouglas Gilbert } 6392ad0c7775SDouglas Gilbert return count; 6393ad0c7775SDouglas Gilbert } 6394ad0c7775SDouglas Gilbert return -EINVAL; 6395ad0c7775SDouglas Gilbert } 6396ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6397ad0c7775SDouglas Gilbert 639882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 63991da177e4SLinus Torvalds { 6400773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 64011da177e4SLinus Torvalds } 640282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 640382069379SAkinobu Mita size_t count) 64041da177e4SLinus Torvalds { 64051da177e4SLinus Torvalds int n; 640619c8ead7SEwan D. Milne bool changed; 64071da177e4SLinus Torvalds 64081da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 64098d039e22SDouglas Gilbert if (n > 256) { 64108d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 64118d039e22SDouglas Gilbert return -EINVAL; 64128d039e22SDouglas Gilbert } 6413773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6414773642d9SDouglas Gilbert sdebug_max_luns = n; 64151da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6416773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 641719c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 641819c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 641919c8ead7SEwan D. Milne 64200aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 642119c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 642219c8ead7SEwan D. Milne host_list) { 642319c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 642419c8ead7SEwan D. Milne dev_list) { 642519c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 642619c8ead7SEwan D. Milne dp->uas_bm); 642719c8ead7SEwan D. Milne } 642819c8ead7SEwan D. Milne } 64290aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 643019c8ead7SEwan D. Milne } 64311da177e4SLinus Torvalds return count; 64321da177e4SLinus Torvalds } 64331da177e4SLinus Torvalds return -EINVAL; 64341da177e4SLinus Torvalds } 643582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 64361da177e4SLinus Torvalds 643782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 643878d4e5a0SDouglas Gilbert { 6439773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 644078d4e5a0SDouglas Gilbert } 6441cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6442cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 644382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 644482069379SAkinobu Mita size_t count) 644578d4e5a0SDouglas Gilbert { 6446c4837394SDouglas Gilbert int j, n, k, a; 6447c4837394SDouglas Gilbert struct sdebug_queue *sqp; 644878d4e5a0SDouglas Gilbert 644978d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6450c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6451c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 645225b80b2cSJohn Garry mutex_lock(&sdebug_host_list_mutex); 6453f19fe8f3SBart Van Assche block_unblock_all_queues(true); 6454c4837394SDouglas Gilbert k = 0; 6455c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6456c4837394SDouglas Gilbert ++j, ++sqp) { 6457c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6458c4837394SDouglas Gilbert if (a > k) 6459c4837394SDouglas Gilbert k = a; 6460c4837394SDouglas Gilbert } 6461773642d9SDouglas Gilbert sdebug_max_queue = n; 6462c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6463cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6464cbf67842SDouglas Gilbert else if (k >= n) 6465cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6466cbf67842SDouglas Gilbert else 6467cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6468f19fe8f3SBart Van Assche block_unblock_all_queues(false); 646925b80b2cSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 647078d4e5a0SDouglas Gilbert return count; 647178d4e5a0SDouglas Gilbert } 647278d4e5a0SDouglas Gilbert return -EINVAL; 647378d4e5a0SDouglas Gilbert } 647482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 647578d4e5a0SDouglas Gilbert 6476c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6477c10fa55fSJohn Garry { 6478c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6479c10fa55fSJohn Garry } 6480c10fa55fSJohn Garry 64817109f370SDouglas Gilbert static ssize_t no_rwlock_show(struct device_driver *ddp, char *buf) 64827109f370SDouglas Gilbert { 64837109f370SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_rwlock); 64847109f370SDouglas Gilbert } 64857109f370SDouglas Gilbert 64867109f370SDouglas Gilbert static ssize_t no_rwlock_store(struct device_driver *ddp, const char *buf, size_t count) 64877109f370SDouglas Gilbert { 64887109f370SDouglas Gilbert bool v; 64897109f370SDouglas Gilbert 64907109f370SDouglas Gilbert if (kstrtobool(buf, &v)) 64917109f370SDouglas Gilbert return -EINVAL; 64927109f370SDouglas Gilbert 64937109f370SDouglas Gilbert sdebug_no_rwlock = v; 64947109f370SDouglas Gilbert return count; 64957109f370SDouglas Gilbert } 64967109f370SDouglas Gilbert static DRIVER_ATTR_RW(no_rwlock); 64977109f370SDouglas Gilbert 6498c10fa55fSJohn Garry /* 6499c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6500c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6501c10fa55fSJohn Garry */ 6502c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6503c10fa55fSJohn Garry 650482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 650578d4e5a0SDouglas Gilbert { 6506773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 650778d4e5a0SDouglas Gilbert } 650882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 650978d4e5a0SDouglas Gilbert 651082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 65111da177e4SLinus Torvalds { 6512773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 65131da177e4SLinus Torvalds } 651482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 65151da177e4SLinus Torvalds 651682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6517c65b1445SDouglas Gilbert { 6518773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6519c65b1445SDouglas Gilbert } 652082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 652182069379SAkinobu Mita size_t count) 6522c65b1445SDouglas Gilbert { 6523c65b1445SDouglas Gilbert int n; 65240d01c5dfSDouglas Gilbert bool changed; 6525c65b1445SDouglas Gilbert 6526f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6527f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6528f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6529f0d1cf93SDouglas Gilbert 6530c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6531773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6532773642d9SDouglas Gilbert sdebug_virtual_gb = n; 653328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 65340d01c5dfSDouglas Gilbert if (changed) { 65350d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 65360d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 653728898873SFUJITA Tomonori 65380aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 65390d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 65400d01c5dfSDouglas Gilbert host_list) { 65410d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 65420d01c5dfSDouglas Gilbert dev_list) { 65430d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 65440d01c5dfSDouglas Gilbert dp->uas_bm); 65450d01c5dfSDouglas Gilbert } 65460d01c5dfSDouglas Gilbert } 65470aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 65480d01c5dfSDouglas Gilbert } 6549c65b1445SDouglas Gilbert return count; 6550c65b1445SDouglas Gilbert } 6551c65b1445SDouglas Gilbert return -EINVAL; 6552c65b1445SDouglas Gilbert } 655382069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6554c65b1445SDouglas Gilbert 655582069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 65561da177e4SLinus Torvalds { 655787c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 6558f19fe8f3SBart Van Assche return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 65591da177e4SLinus Torvalds } 65601da177e4SLinus Torvalds 656182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 656282069379SAkinobu Mita size_t count) 65631da177e4SLinus Torvalds { 6564f19fe8f3SBart Van Assche bool found; 6565f19fe8f3SBart Van Assche unsigned long idx; 6566f19fe8f3SBart Van Assche struct sdeb_store_info *sip; 6567f19fe8f3SBart Van Assche bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 65681da177e4SLinus Torvalds int delta_hosts; 65691da177e4SLinus Torvalds 6570f19fe8f3SBart Van Assche if (sscanf(buf, "%d", &delta_hosts) != 1) 65711da177e4SLinus Torvalds return -EINVAL; 65721da177e4SLinus Torvalds if (delta_hosts > 0) { 65731da177e4SLinus Torvalds do { 6574f19fe8f3SBart Van Assche found = false; 6575f19fe8f3SBart Van Assche if (want_phs) { 6576f19fe8f3SBart Van Assche xa_for_each_marked(per_store_ap, idx, sip, 6577f19fe8f3SBart Van Assche SDEB_XA_NOT_IN_USE) { 6578f19fe8f3SBart Van Assche sdeb_most_recent_idx = (int)idx; 6579f19fe8f3SBart Van Assche found = true; 658087c715dcSDouglas Gilbert break; 658187c715dcSDouglas Gilbert } 6582f19fe8f3SBart Van Assche if (found) /* re-use case */ 6583f19fe8f3SBart Van Assche sdebug_add_host_helper((int)idx); 6584f19fe8f3SBart Van Assche else 6585f19fe8f3SBart Van Assche sdebug_do_add_host(true); 6586f19fe8f3SBart Van Assche } else { 6587f19fe8f3SBart Van Assche sdebug_do_add_host(false); 6588f19fe8f3SBart Van Assche } 6589f19fe8f3SBart Van Assche } while (--delta_hosts); 6590f19fe8f3SBart Van Assche } else if (delta_hosts < 0) { 6591f19fe8f3SBart Van Assche do { 659287c715dcSDouglas Gilbert sdebug_do_remove_host(false); 65931da177e4SLinus Torvalds } while (++delta_hosts); 65941da177e4SLinus Torvalds } 65951da177e4SLinus Torvalds return count; 65961da177e4SLinus Torvalds } 659782069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 65981da177e4SLinus Torvalds 659982069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 660023183910SDouglas Gilbert { 6601773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 660223183910SDouglas Gilbert } 660382069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 660482069379SAkinobu Mita size_t count) 660523183910SDouglas Gilbert { 660623183910SDouglas Gilbert int n; 660723183910SDouglas Gilbert 660823183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6609773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 661023183910SDouglas Gilbert return count; 661123183910SDouglas Gilbert } 661223183910SDouglas Gilbert return -EINVAL; 661323183910SDouglas Gilbert } 661482069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 661523183910SDouglas Gilbert 6616c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6617c4837394SDouglas Gilbert { 6618c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6619c4837394SDouglas Gilbert } 6620c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6621c4837394SDouglas Gilbert size_t count) 6622c4837394SDouglas Gilbert { 6623c4837394SDouglas Gilbert int n; 6624c4837394SDouglas Gilbert 6625c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6626c4837394SDouglas Gilbert if (n > 0) 6627c4837394SDouglas Gilbert sdebug_statistics = true; 6628c4837394SDouglas Gilbert else { 6629c4837394SDouglas Gilbert clear_queue_stats(); 6630c4837394SDouglas Gilbert sdebug_statistics = false; 6631c4837394SDouglas Gilbert } 6632c4837394SDouglas Gilbert return count; 6633c4837394SDouglas Gilbert } 6634c4837394SDouglas Gilbert return -EINVAL; 6635c4837394SDouglas Gilbert } 6636c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6637c4837394SDouglas Gilbert 663882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6639597136abSMartin K. Petersen { 6640773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6641597136abSMartin K. Petersen } 664282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6643597136abSMartin K. Petersen 6644c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6645c4837394SDouglas Gilbert { 6646c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6647c4837394SDouglas Gilbert } 6648c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6649c4837394SDouglas Gilbert 665082069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6651c6a44287SMartin K. Petersen { 6652773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6653c6a44287SMartin K. Petersen } 665482069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6655c6a44287SMartin K. Petersen 665682069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6657c6a44287SMartin K. Petersen { 6658773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6659c6a44287SMartin K. Petersen } 666082069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6661c6a44287SMartin K. Petersen 666282069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6663c6a44287SMartin K. Petersen { 6664773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6665c6a44287SMartin K. Petersen } 666682069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6667c6a44287SMartin K. Petersen 666882069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6669c6a44287SMartin K. Petersen { 6670773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6671c6a44287SMartin K. Petersen } 667282069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6673c6a44287SMartin K. Petersen 667482069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 667544d92694SMartin K. Petersen { 667687c715dcSDouglas Gilbert ssize_t count = 0; 667744d92694SMartin K. Petersen 66785b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 667944d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 668044d92694SMartin K. Petersen sdebug_store_sectors); 668144d92694SMartin K. Petersen 668287c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 668387c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 668487c715dcSDouglas Gilbert 668587c715dcSDouglas Gilbert if (sip) 6686c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 668787c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 668887c715dcSDouglas Gilbert } 668944d92694SMartin K. Petersen buf[count++] = '\n'; 6690c7badc90STejun Heo buf[count] = '\0'; 669144d92694SMartin K. Petersen 669244d92694SMartin K. Petersen return count; 669344d92694SMartin K. Petersen } 669482069379SAkinobu Mita static DRIVER_ATTR_RO(map); 669544d92694SMartin K. Petersen 66960c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 66970c4bc91dSDouglas Gilbert { 66980c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 66990c4bc91dSDouglas Gilbert } 67000c4bc91dSDouglas Gilbert 67010c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 67020c4bc91dSDouglas Gilbert size_t count) 67030c4bc91dSDouglas Gilbert { 67040c4bc91dSDouglas Gilbert bool v; 67050c4bc91dSDouglas Gilbert 67060c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 67070c4bc91dSDouglas Gilbert return -EINVAL; 67080c4bc91dSDouglas Gilbert 67090c4bc91dSDouglas Gilbert sdebug_random = v; 67100c4bc91dSDouglas Gilbert return count; 67110c4bc91dSDouglas Gilbert } 67120c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 67130c4bc91dSDouglas Gilbert 671482069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6715d986788bSMartin Pitt { 6716773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6717d986788bSMartin Pitt } 671882069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 671982069379SAkinobu Mita size_t count) 6720d986788bSMartin Pitt { 6721d986788bSMartin Pitt int n; 6722d986788bSMartin Pitt 6723d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6724773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6725d986788bSMartin Pitt return count; 6726d986788bSMartin Pitt } 6727d986788bSMartin Pitt return -EINVAL; 6728d986788bSMartin Pitt } 672982069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6730d986788bSMartin Pitt 6731cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6732cbf67842SDouglas Gilbert { 6733773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6734cbf67842SDouglas Gilbert } 6735185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6736cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6737cbf67842SDouglas Gilbert size_t count) 6738cbf67842SDouglas Gilbert { 6739185dd232SDouglas Gilbert int n; 6740cbf67842SDouglas Gilbert 6741cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6742185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6743185dd232SDouglas Gilbert return count; 6744cbf67842SDouglas Gilbert } 6745cbf67842SDouglas Gilbert return -EINVAL; 6746cbf67842SDouglas Gilbert } 6747cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6748cbf67842SDouglas Gilbert 6749c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6750c2248fc9SDouglas Gilbert { 6751773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6752c2248fc9SDouglas Gilbert } 6753c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6754c2248fc9SDouglas Gilbert size_t count) 6755c2248fc9SDouglas Gilbert { 6756c2248fc9SDouglas Gilbert int n; 6757c2248fc9SDouglas Gilbert 6758c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6759773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6760c2248fc9SDouglas Gilbert return count; 6761c2248fc9SDouglas Gilbert } 6762c2248fc9SDouglas Gilbert return -EINVAL; 6763c2248fc9SDouglas Gilbert } 6764c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6765c2248fc9SDouglas Gilbert 676609ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 676709ba24c1SDouglas Gilbert { 676809ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 676909ba24c1SDouglas Gilbert } 677009ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 677109ba24c1SDouglas Gilbert 67729b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 67739b760fd8SDouglas Gilbert { 67749b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 67759b760fd8SDouglas Gilbert } 67769b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 67779b760fd8SDouglas Gilbert size_t count) 67789b760fd8SDouglas Gilbert { 67799b760fd8SDouglas Gilbert int ret, n; 67809b760fd8SDouglas Gilbert 67819b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 67829b760fd8SDouglas Gilbert if (ret) 67839b760fd8SDouglas Gilbert return ret; 67849b760fd8SDouglas Gilbert sdebug_cdb_len = n; 67859b760fd8SDouglas Gilbert all_config_cdb_len(); 67869b760fd8SDouglas Gilbert return count; 67879b760fd8SDouglas Gilbert } 67889b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 67899b760fd8SDouglas Gilbert 67909267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 67919267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 67929267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 67939267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 67949267e0ebSDouglas Gilbert }; 67959267e0ebSDouglas Gilbert 67969267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 67979267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 67989267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 67999267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 68009267e0ebSDouglas Gilbert }; 68019267e0ebSDouglas Gilbert 68029267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 68039267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 68049267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 68059267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 68069267e0ebSDouglas Gilbert }; 68079267e0ebSDouglas Gilbert 68089267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 68099267e0ebSDouglas Gilbert { 68109267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 68119267e0ebSDouglas Gilbert 68129267e0ebSDouglas Gilbert if (res < 0) { 68139267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 68149267e0ebSDouglas Gilbert if (res < 0) { 68159267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 681647742bdeSDan Carpenter if (res < 0) 68179267e0ebSDouglas Gilbert return -EINVAL; 68189267e0ebSDouglas Gilbert } 68199267e0ebSDouglas Gilbert } 68209267e0ebSDouglas Gilbert return res; 68219267e0ebSDouglas Gilbert } 68229267e0ebSDouglas Gilbert 68239267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 68249267e0ebSDouglas Gilbert { 68259267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 68269267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 68279267e0ebSDouglas Gilbert } 68289267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6829cbf67842SDouglas Gilbert 6830fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6831fc13638aSDouglas Gilbert { 6832fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6833fc13638aSDouglas Gilbert } 6834fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6835fc13638aSDouglas Gilbert 683682069379SAkinobu Mita /* Note: The following array creates attribute files in the 683723183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 683823183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 683923183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 684087c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 684123183910SDouglas Gilbert */ 68426ecaff7fSRandy Dunlap 684382069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 684482069379SAkinobu Mita &driver_attr_delay.attr, 684582069379SAkinobu Mita &driver_attr_opts.attr, 684682069379SAkinobu Mita &driver_attr_ptype.attr, 684782069379SAkinobu Mita &driver_attr_dsense.attr, 684882069379SAkinobu Mita &driver_attr_fake_rw.attr, 6849c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 685082069379SAkinobu Mita &driver_attr_no_lun_0.attr, 685182069379SAkinobu Mita &driver_attr_num_tgts.attr, 685282069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 685382069379SAkinobu Mita &driver_attr_num_parts.attr, 685482069379SAkinobu Mita &driver_attr_every_nth.attr, 6855ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 685682069379SAkinobu Mita &driver_attr_max_luns.attr, 685782069379SAkinobu Mita &driver_attr_max_queue.attr, 68587109f370SDouglas Gilbert &driver_attr_no_rwlock.attr, 685982069379SAkinobu Mita &driver_attr_no_uld.attr, 686082069379SAkinobu Mita &driver_attr_scsi_level.attr, 686182069379SAkinobu Mita &driver_attr_virtual_gb.attr, 686282069379SAkinobu Mita &driver_attr_add_host.attr, 686387c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 686482069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 686582069379SAkinobu Mita &driver_attr_sector_size.attr, 6866c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6867c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 686882069379SAkinobu Mita &driver_attr_dix.attr, 686982069379SAkinobu Mita &driver_attr_dif.attr, 687082069379SAkinobu Mita &driver_attr_guard.attr, 687182069379SAkinobu Mita &driver_attr_ato.attr, 687282069379SAkinobu Mita &driver_attr_map.attr, 68730c4bc91dSDouglas Gilbert &driver_attr_random.attr, 687482069379SAkinobu Mita &driver_attr_removable.attr, 6875cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6876cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6877c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 687809ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 68799b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6880fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 68819267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 688282069379SAkinobu Mita NULL, 688382069379SAkinobu Mita }; 688482069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 68851da177e4SLinus Torvalds 688611ddcecaSAkinobu Mita static struct device *pseudo_primary; 68878dea0d02SFUJITA Tomonori 68881da177e4SLinus Torvalds static int __init scsi_debug_init(void) 68891da177e4SLinus Torvalds { 689087c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 68915f2578e5SFUJITA Tomonori unsigned long sz; 689287c715dcSDouglas Gilbert int k, ret, hosts_to_add; 689387c715dcSDouglas Gilbert int idx = -1; 68941da177e4SLinus Torvalds 689587c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 689687c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6897cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6898cbf67842SDouglas Gilbert 6899773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6900c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6901773642d9SDouglas Gilbert sdebug_ndelay = 0; 6902773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6903c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6904cbf67842SDouglas Gilbert 6905773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6906597136abSMartin K. Petersen case 512: 6907597136abSMartin K. Petersen case 1024: 6908597136abSMartin K. Petersen case 2048: 6909597136abSMartin K. Petersen case 4096: 6910597136abSMartin K. Petersen break; 6911597136abSMartin K. Petersen default: 6912773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6913597136abSMartin K. Petersen return -EINVAL; 6914597136abSMartin K. Petersen } 6915597136abSMartin K. Petersen 6916773642d9SDouglas Gilbert switch (sdebug_dif) { 69178475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6918f46eb0e9SDouglas Gilbert break; 69198475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 69208475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 69218475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6922f46eb0e9SDouglas Gilbert have_dif_prot = true; 6923c6a44287SMartin K. Petersen break; 6924c6a44287SMartin K. Petersen 6925c6a44287SMartin K. Petersen default: 6926c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6927c6a44287SMartin K. Petersen return -EINVAL; 6928c6a44287SMartin K. Petersen } 6929c6a44287SMartin K. Petersen 6930aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6931aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6932aa5334c4SMaurizio Lombardi return -EINVAL; 6933aa5334c4SMaurizio Lombardi } 6934aa5334c4SMaurizio Lombardi 6935773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6936c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6937c6a44287SMartin K. Petersen return -EINVAL; 6938c6a44287SMartin K. Petersen } 6939c6a44287SMartin K. Petersen 6940773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6941c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6942c6a44287SMartin K. Petersen return -EINVAL; 6943c6a44287SMartin K. Petersen } 6944c6a44287SMartin K. Petersen 6945773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6946773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6947ea61fca5SMartin K. Petersen return -EINVAL; 6948ea61fca5SMartin K. Petersen } 6949ad0c7775SDouglas Gilbert 6950ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6951ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6952ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6953ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6954ad0c7775SDouglas Gilbert } 6955ad0c7775SDouglas Gilbert 69568d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6957ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6958ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 69598d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 69608d039e22SDouglas Gilbert } 6961ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6962ad0c7775SDouglas Gilbert } 6963ea61fca5SMartin K. Petersen 6964773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6965773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6966ea61fca5SMartin K. Petersen return -EINVAL; 6967ea61fca5SMartin K. Petersen } 6968ea61fca5SMartin K. Petersen 6969c4837394SDouglas Gilbert if (submit_queues < 1) { 6970c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6971c4837394SDouglas Gilbert return -EINVAL; 6972c4837394SDouglas Gilbert } 6973c87bf24cSJohn Garry 6974c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6975c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6976c87bf24cSJohn Garry return -EINVAL; 6977c87bf24cSJohn Garry } 6978c87bf24cSJohn Garry 6979c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6980c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6981c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6982c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6983c10fa55fSJohn Garry return -EINVAL; 6984c10fa55fSJohn Garry } 6985c10fa55fSJohn Garry 6986c10fa55fSJohn Garry if (sdebug_host_max_queue && 6987c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6988c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6989c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6990c10fa55fSJohn Garry sdebug_max_queue); 6991c10fa55fSJohn Garry } 6992c10fa55fSJohn Garry 6993c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6994c4837394SDouglas Gilbert GFP_KERNEL); 6995c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6996c4837394SDouglas Gilbert return -ENOMEM; 6997c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6998c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6999c4837394SDouglas Gilbert 7000f0d1cf93SDouglas Gilbert /* 70019267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 70029267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 7003f0d1cf93SDouglas Gilbert */ 70049267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 70059267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 70069267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 70079267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 70089267e0ebSDouglas Gilbert if (k < 0) { 70099267e0ebSDouglas Gilbert ret = k; 70103b01d7eaSDinghao Liu goto free_q_arr; 70119267e0ebSDouglas Gilbert } 70129267e0ebSDouglas Gilbert sdeb_zbc_model = k; 70139267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 70149267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 701564e14eceSDamien Le Moal case BLK_ZONED_HA: 70169267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 70179267e0ebSDouglas Gilbert break; 70189267e0ebSDouglas Gilbert case BLK_ZONED_HM: 70199267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 70209267e0ebSDouglas Gilbert break; 70219267e0ebSDouglas Gilbert default: 70229267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 70233b01d7eaSDinghao Liu ret = -EINVAL; 70243b01d7eaSDinghao Liu goto free_q_arr; 70259267e0ebSDouglas Gilbert } 70269267e0ebSDouglas Gilbert } 70279267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 7028f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 70299267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70309267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 70319267e0ebSDouglas Gilbert } 7032f0d1cf93SDouglas Gilbert 70339267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 70349267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 7035773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 7036773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 7037773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 7038773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 703928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 70401da177e4SLinus Torvalds 70411da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 70421da177e4SLinus Torvalds sdebug_heads = 8; 70431da177e4SLinus Torvalds sdebug_sectors_per = 32; 7044773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 70451da177e4SLinus Torvalds sdebug_heads = 64; 7046773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 7047fa785f0aSAndy Shevchenko sdebug_heads = 32; 70481da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70491da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70501da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 70511da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 70521da177e4SLinus Torvalds sdebug_heads = 255; 70531da177e4SLinus Torvalds sdebug_sectors_per = 63; 70541da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 70551da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 70561da177e4SLinus Torvalds } 70575b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 7058773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 7059773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 70606014759cSMartin K. Petersen 7061773642d9SDouglas Gilbert sdebug_unmap_max_desc = 7062773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 70636014759cSMartin K. Petersen 7064773642d9SDouglas Gilbert sdebug_unmap_granularity = 7065773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 70666014759cSMartin K. Petersen 7067773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 7068773642d9SDouglas Gilbert sdebug_unmap_granularity <= 7069773642d9SDouglas Gilbert sdebug_unmap_alignment) { 7070c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 7071c4837394SDouglas Gilbert ret = -EINVAL; 707287c715dcSDouglas Gilbert goto free_q_arr; 707344d92694SMartin K. Petersen } 707444d92694SMartin K. Petersen } 707587c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 707687c715dcSDouglas Gilbert if (want_store) { 707787c715dcSDouglas Gilbert idx = sdebug_add_store(); 707887c715dcSDouglas Gilbert if (idx < 0) { 707987c715dcSDouglas Gilbert ret = idx; 708087c715dcSDouglas Gilbert goto free_q_arr; 708187c715dcSDouglas Gilbert } 708244d92694SMartin K. Petersen } 708344d92694SMartin K. Petersen 70849b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 70859b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 7086c1287970STomas Winkler pr_warn("root_device_register() error\n"); 70879b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 70886ecaff7fSRandy Dunlap goto free_vm; 70896ecaff7fSRandy Dunlap } 70906ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 70916ecaff7fSRandy Dunlap if (ret < 0) { 7092c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 70936ecaff7fSRandy Dunlap goto dev_unreg; 70946ecaff7fSRandy Dunlap } 70956ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 70966ecaff7fSRandy Dunlap if (ret < 0) { 7097c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 70986ecaff7fSRandy Dunlap goto bus_unreg; 70996ecaff7fSRandy Dunlap } 71001da177e4SLinus Torvalds 710187c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 7102773642d9SDouglas Gilbert sdebug_add_host = 0; 71031da177e4SLinus Torvalds 71041107c7b2SJohn Garry queued_cmd_cache = KMEM_CACHE(sdebug_queued_cmd, SLAB_HWCACHE_ALIGN); 71051107c7b2SJohn Garry if (!queued_cmd_cache) 71061107c7b2SJohn Garry goto driver_unreg; 71071107c7b2SJohn Garry 710887c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 710987c715dcSDouglas Gilbert if (want_store && k == 0) { 711087c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 711187c715dcSDouglas Gilbert if (ret < 0) { 711287c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 711387c715dcSDouglas Gilbert k, -ret); 711487c715dcSDouglas Gilbert break; 711587c715dcSDouglas Gilbert } 711687c715dcSDouglas Gilbert } else { 711787c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 711887c715dcSDouglas Gilbert sdebug_per_host_store); 711987c715dcSDouglas Gilbert if (ret < 0) { 712087c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 71211da177e4SLinus Torvalds break; 71221da177e4SLinus Torvalds } 71231da177e4SLinus Torvalds } 712487c715dcSDouglas Gilbert } 7125773642d9SDouglas Gilbert if (sdebug_verbose) 7126f19fe8f3SBart Van Assche pr_info("built %d host(s)\n", sdebug_num_hosts); 7127c1287970STomas Winkler 71281da177e4SLinus Torvalds return 0; 71296ecaff7fSRandy Dunlap 71301107c7b2SJohn Garry driver_unreg: 71311107c7b2SJohn Garry driver_unregister(&sdebug_driverfs_driver); 71326ecaff7fSRandy Dunlap bus_unreg: 71336ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 71346ecaff7fSRandy Dunlap dev_unreg: 71359b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71366ecaff7fSRandy Dunlap free_vm: 713787c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 7138c4837394SDouglas Gilbert free_q_arr: 7139c4837394SDouglas Gilbert kfree(sdebug_q_arr); 71406ecaff7fSRandy Dunlap return ret; 71411da177e4SLinus Torvalds } 71421da177e4SLinus Torvalds 71431da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 71441da177e4SLinus Torvalds { 7145f19fe8f3SBart Van Assche int k = sdebug_num_hosts; 71461da177e4SLinus Torvalds 7147f19fe8f3SBart Van Assche for (; k; k--) 714887c715dcSDouglas Gilbert sdebug_do_remove_host(true); 71491107c7b2SJohn Garry kmem_cache_destroy(queued_cmd_cache); 71501da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 71511da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 71529b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 71531da177e4SLinus Torvalds 715487c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 715587c715dcSDouglas Gilbert xa_destroy(per_store_ap); 7156f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 71571da177e4SLinus Torvalds } 71581da177e4SLinus Torvalds 71591da177e4SLinus Torvalds device_initcall(scsi_debug_init); 71601da177e4SLinus Torvalds module_exit(scsi_debug_exit); 71611da177e4SLinus Torvalds 71621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 71631da177e4SLinus Torvalds { 71641da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71651da177e4SLinus Torvalds 7166785d6b7cSJohn Garry sdbg_host = dev_to_sdebug_host(dev); 71671da177e4SLinus Torvalds kfree(sdbg_host); 71681da177e4SLinus Torvalds } 71691da177e4SLinus Torvalds 717087c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 717187c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 71721da177e4SLinus Torvalds { 717387c715dcSDouglas Gilbert if (idx < 0) 717487c715dcSDouglas Gilbert return; 717587c715dcSDouglas Gilbert if (!sip) { 717687c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 717787c715dcSDouglas Gilbert return; 717887c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 717987c715dcSDouglas Gilbert if (!sip) 718087c715dcSDouglas Gilbert return; 718187c715dcSDouglas Gilbert } 718287c715dcSDouglas Gilbert vfree(sip->map_storep); 718387c715dcSDouglas Gilbert vfree(sip->dif_storep); 718487c715dcSDouglas Gilbert vfree(sip->storep); 718587c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 718687c715dcSDouglas Gilbert kfree(sip); 718787c715dcSDouglas Gilbert } 718887c715dcSDouglas Gilbert 718987c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 719087c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 719187c715dcSDouglas Gilbert { 719287c715dcSDouglas Gilbert unsigned long idx; 719387c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 719487c715dcSDouglas Gilbert 719587c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 719687c715dcSDouglas Gilbert if (apart_from_first) 719787c715dcSDouglas Gilbert apart_from_first = false; 719887c715dcSDouglas Gilbert else 719987c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 720087c715dcSDouglas Gilbert } 720187c715dcSDouglas Gilbert if (apart_from_first) 720287c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 720387c715dcSDouglas Gilbert } 720487c715dcSDouglas Gilbert 720587c715dcSDouglas Gilbert /* 720687c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 720787c715dcSDouglas Gilbert * Limit the number of stores to 65536. 720887c715dcSDouglas Gilbert */ 720987c715dcSDouglas Gilbert static int sdebug_add_store(void) 721087c715dcSDouglas Gilbert { 721187c715dcSDouglas Gilbert int res; 721287c715dcSDouglas Gilbert u32 n_idx; 721387c715dcSDouglas Gilbert unsigned long iflags; 721487c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 721587c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 721687c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 721787c715dcSDouglas Gilbert 721887c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 721987c715dcSDouglas Gilbert if (!sip) 722087c715dcSDouglas Gilbert return -ENOMEM; 722187c715dcSDouglas Gilbert 722287c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 722387c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 722487c715dcSDouglas Gilbert if (unlikely(res < 0)) { 722587c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 722687c715dcSDouglas Gilbert kfree(sip); 722787c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 722887c715dcSDouglas Gilbert return res; 722987c715dcSDouglas Gilbert } 723087c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 723187c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 723287c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 723387c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 723487c715dcSDouglas Gilbert 723587c715dcSDouglas Gilbert res = -ENOMEM; 723687c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 723787c715dcSDouglas Gilbert if (!sip->storep) { 723887c715dcSDouglas Gilbert pr_err("user data oom\n"); 723987c715dcSDouglas Gilbert goto err; 724087c715dcSDouglas Gilbert } 724187c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 724287c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 724387c715dcSDouglas Gilbert 724487c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 724587c715dcSDouglas Gilbert if (sdebug_dix) { 724687c715dcSDouglas Gilbert int dif_size; 724787c715dcSDouglas Gilbert 724887c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 724987c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 725087c715dcSDouglas Gilbert 725187c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 725287c715dcSDouglas Gilbert sip->dif_storep); 725387c715dcSDouglas Gilbert 725487c715dcSDouglas Gilbert if (!sip->dif_storep) { 725587c715dcSDouglas Gilbert pr_err("DIX oom\n"); 725687c715dcSDouglas Gilbert goto err; 725787c715dcSDouglas Gilbert } 725887c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 725987c715dcSDouglas Gilbert } 726087c715dcSDouglas Gilbert /* Logical Block Provisioning */ 726187c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 726287c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 726387c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 726487c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 726587c715dcSDouglas Gilbert 726687c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 726787c715dcSDouglas Gilbert 726887c715dcSDouglas Gilbert if (!sip->map_storep) { 726987c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 727087c715dcSDouglas Gilbert goto err; 727187c715dcSDouglas Gilbert } 727287c715dcSDouglas Gilbert 727387c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 727487c715dcSDouglas Gilbert 727587c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 727687c715dcSDouglas Gilbert if (sdebug_num_parts) 727787c715dcSDouglas Gilbert map_region(sip, 0, 2); 727887c715dcSDouglas Gilbert } 727987c715dcSDouglas Gilbert 728087c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 728187c715dcSDouglas Gilbert return (int)n_idx; 728287c715dcSDouglas Gilbert err: 728387c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 728487c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 728587c715dcSDouglas Gilbert return res; 728687c715dcSDouglas Gilbert } 728787c715dcSDouglas Gilbert 728887c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 728987c715dcSDouglas Gilbert { 729087c715dcSDouglas Gilbert int k, devs_per_host, idx; 729187c715dcSDouglas Gilbert int error = -ENOMEM; 72921da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 72938b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 72941da177e4SLinus Torvalds 729524669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 729687c715dcSDouglas Gilbert if (!sdbg_host) 72971da177e4SLinus Torvalds return -ENOMEM; 729887c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 729987c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 730087c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 730187c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 73021da177e4SLinus Torvalds 73031da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 73041da177e4SLinus Torvalds 7305773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 73061da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 73075cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 730887c715dcSDouglas Gilbert if (!sdbg_devinfo) 73091da177e4SLinus Torvalds goto clean; 73101da177e4SLinus Torvalds } 73111da177e4SLinus Torvalds 73120aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 73131da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 73140aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 73151da177e4SLinus Torvalds 73161da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 73179b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 73181da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 7319f19fe8f3SBart Van Assche dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 73201da177e4SLinus Torvalds 73211da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 7322e208a1d7SYuan Can if (error) { 73230aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 7324e208a1d7SYuan Can list_del(&sdbg_host->host_list); 73250aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 73261da177e4SLinus Torvalds goto clean; 7327e208a1d7SYuan Can } 73281da177e4SLinus Torvalds 7329f19fe8f3SBart Van Assche ++sdebug_num_hosts; 733087c715dcSDouglas Gilbert return 0; 73311da177e4SLinus Torvalds 73321da177e4SLinus Torvalds clean: 73338b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 73348b40228fSFUJITA Tomonori dev_list) { 73351da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7336f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 73371da177e4SLinus Torvalds kfree(sdbg_devinfo); 73381da177e4SLinus Torvalds } 7339e6d773f9SYang Yingliang if (sdbg_host->dev.release) 7340e6d773f9SYang Yingliang put_device(&sdbg_host->dev); 7341e6d773f9SYang Yingliang else 73421da177e4SLinus Torvalds kfree(sdbg_host); 734387c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 73441da177e4SLinus Torvalds return error; 73451da177e4SLinus Torvalds } 73461da177e4SLinus Torvalds 734787c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 73481da177e4SLinus Torvalds { 734987c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 735087c715dcSDouglas Gilbert 735187c715dcSDouglas Gilbert if (mk_new_store) { 735287c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 735387c715dcSDouglas Gilbert if (ph_idx < 0) 735487c715dcSDouglas Gilbert return ph_idx; 735587c715dcSDouglas Gilbert } 735687c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 735787c715dcSDouglas Gilbert } 735887c715dcSDouglas Gilbert 735987c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 736087c715dcSDouglas Gilbert { 736187c715dcSDouglas Gilbert int idx = -1; 73621da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 736387c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 73641da177e4SLinus Torvalds 73650aaa3fadSJohn Garry mutex_lock(&sdebug_host_list_mutex); 73661da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 73671da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 73681da177e4SLinus Torvalds struct sdebug_host_info, host_list); 736987c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 73701da177e4SLinus Torvalds } 737187c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 737287c715dcSDouglas Gilbert bool unique = true; 737387c715dcSDouglas Gilbert 737487c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 737587c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 737687c715dcSDouglas Gilbert continue; 737787c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 737887c715dcSDouglas Gilbert unique = false; 737987c715dcSDouglas Gilbert break; 738087c715dcSDouglas Gilbert } 738187c715dcSDouglas Gilbert } 738287c715dcSDouglas Gilbert if (unique) { 738387c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 738487c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 738587c715dcSDouglas Gilbert --sdeb_most_recent_idx; 738687c715dcSDouglas Gilbert } 738787c715dcSDouglas Gilbert } 738887c715dcSDouglas Gilbert if (sdbg_host) 738987c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 73900aaa3fadSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 73911da177e4SLinus Torvalds 73921da177e4SLinus Torvalds if (!sdbg_host) 73931da177e4SLinus Torvalds return; 73941da177e4SLinus Torvalds 73951da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 7396f19fe8f3SBart Van Assche --sdebug_num_hosts; 73971da177e4SLinus Torvalds } 73981da177e4SLinus Torvalds 7399fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7400cbf67842SDouglas Gilbert { 7401151f0ec9SJohn Garry struct sdebug_dev_info *devip = sdev->hostdata; 7402151f0ec9SJohn Garry 7403151f0ec9SJohn Garry if (!devip) 7404151f0ec9SJohn Garry return -ENODEV; 7405cbf67842SDouglas Gilbert 740625b80b2cSJohn Garry mutex_lock(&sdebug_host_list_mutex); 7407f19fe8f3SBart Van Assche block_unblock_all_queues(true); 740825b80b2cSJohn Garry 7409fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7410fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7411fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7412fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7413fc09acb7SDouglas Gilbert } 7414cbf67842SDouglas Gilbert if (qdepth < 1) 7415cbf67842SDouglas Gilbert qdepth = 1; 7416fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7417db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7418cbf67842SDouglas Gilbert 741925b80b2cSJohn Garry block_unblock_all_queues(false); 742025b80b2cSJohn Garry mutex_unlock(&sdebug_host_list_mutex); 742125b80b2cSJohn Garry 7422151f0ec9SJohn Garry if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 7423151f0ec9SJohn Garry sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d\n", __func__, qdepth); 742425b80b2cSJohn Garry 7425cbf67842SDouglas Gilbert return sdev->queue_depth; 7426cbf67842SDouglas Gilbert } 7427cbf67842SDouglas Gilbert 7428c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7429817fd66bSDouglas Gilbert { 7430c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7431773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7432773642d9SDouglas Gilbert sdebug_every_nth = -1; 7433773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7434c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7435773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7436817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7437c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7438817fd66bSDouglas Gilbert } 7439c4837394SDouglas Gilbert return false; 7440817fd66bSDouglas Gilbert } 7441817fd66bSDouglas Gilbert 7442fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7443fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7444fc13638aSDouglas Gilbert { 7445fc13638aSDouglas Gilbert int stopped_state; 7446fc13638aSDouglas Gilbert u64 diff_ns = 0; 7447fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7448fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7449fc13638aSDouglas Gilbert 7450fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7451fc13638aSDouglas Gilbert if (stopped_state == 2) { 7452fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7453fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7454fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7455fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7456fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7457fc13638aSDouglas Gilbert return 0; 7458fc13638aSDouglas Gilbert } 7459fc13638aSDouglas Gilbert } 7460fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7461fc13638aSDouglas Gilbert if (sdebug_verbose) 7462fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7463fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7464fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7465fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7466fc13638aSDouglas Gilbert 7467fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7468fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7469fc13638aSDouglas Gilbert else 7470fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7471fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7472fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7473fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7474fc13638aSDouglas Gilbert diff_ns); 7475fc13638aSDouglas Gilbert return check_condition_result; 7476fc13638aSDouglas Gilbert } 7477fc13638aSDouglas Gilbert } 7478fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7479fc13638aSDouglas Gilbert if (sdebug_verbose) 7480fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7481fc13638aSDouglas Gilbert my_name); 7482fc13638aSDouglas Gilbert return check_condition_result; 7483fc13638aSDouglas Gilbert } 7484fc13638aSDouglas Gilbert 7485a4e1d0b7SBart Van Assche static void sdebug_map_queues(struct Scsi_Host *shost) 7486c4b57d89SKashyap Desai { 7487c4b57d89SKashyap Desai int i, qoff; 7488c4b57d89SKashyap Desai 7489c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7490a4e1d0b7SBart Van Assche return; 7491c4b57d89SKashyap Desai 7492c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7493c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7494c4b57d89SKashyap Desai 7495c4b57d89SKashyap Desai map->nr_queues = 0; 7496c4b57d89SKashyap Desai 7497c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7498c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7499c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7500c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7501c4b57d89SKashyap Desai 7502c4b57d89SKashyap Desai if (!map->nr_queues) { 7503c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7504c4b57d89SKashyap Desai continue; 7505c4b57d89SKashyap Desai } 7506c4b57d89SKashyap Desai 7507c4b57d89SKashyap Desai map->queue_offset = qoff; 7508c4b57d89SKashyap Desai blk_mq_map_queues(map); 7509c4b57d89SKashyap Desai 7510c4b57d89SKashyap Desai qoff += map->nr_queues; 7511c4b57d89SKashyap Desai } 7512c4b57d89SKashyap Desai } 7513c4b57d89SKashyap Desai 7514*600d9eadSJohn Garry struct sdebug_blk_mq_poll_data { 7515*600d9eadSJohn Garry unsigned int queue_num; 7516*600d9eadSJohn Garry int *num_entries; 7517*600d9eadSJohn Garry }; 7518*600d9eadSJohn Garry 7519*600d9eadSJohn Garry /* 7520*600d9eadSJohn Garry * We don't handle aborted commands here, but it does not seem possible to have 7521*600d9eadSJohn Garry * aborted polled commands from schedule_resp() 7522*600d9eadSJohn Garry */ 7523*600d9eadSJohn Garry static bool sdebug_blk_mq_poll_iter(struct request *rq, void *opaque) 7524c4b57d89SKashyap Desai { 7525*600d9eadSJohn Garry struct sdebug_blk_mq_poll_data *data = opaque; 7526*600d9eadSJohn Garry struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); 7527*600d9eadSJohn Garry struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd); 75284a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7529*600d9eadSJohn Garry u32 unique_tag = blk_mq_unique_tag(rq); 7530*600d9eadSJohn Garry u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag); 7531*600d9eadSJohn Garry struct sdebug_queued_cmd *sqcp; 7532*600d9eadSJohn Garry struct sdebug_queue *sqp; 7533*600d9eadSJohn Garry unsigned long flags; 7534*600d9eadSJohn Garry int queue_num = data->queue_num; 7535*600d9eadSJohn Garry bool retiring = false; 7536*600d9eadSJohn Garry int qc_idx; 7537*600d9eadSJohn Garry ktime_t time; 7538*600d9eadSJohn Garry 7539*600d9eadSJohn Garry /* We're only interested in one queue for this iteration */ 7540*600d9eadSJohn Garry if (hwq != queue_num) 7541*600d9eadSJohn Garry return true; 7542*600d9eadSJohn Garry 7543*600d9eadSJohn Garry /* Subsequent checks would fail if this failed, but check anyway */ 7544*600d9eadSJohn Garry if (!test_bit(SCMD_STATE_INFLIGHT, &cmd->state)) 7545*600d9eadSJohn Garry return true; 7546*600d9eadSJohn Garry 7547*600d9eadSJohn Garry time = ktime_get_boottime(); 7548*600d9eadSJohn Garry 7549*600d9eadSJohn Garry spin_lock_irqsave(&sdsc->lock, flags); 7550*600d9eadSJohn Garry sqcp = TO_QUEUED_CMD(cmd); 7551*600d9eadSJohn Garry if (!sqcp) { 7552*600d9eadSJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 7553*600d9eadSJohn Garry return true; 7554*600d9eadSJohn Garry } 7555c4b57d89SKashyap Desai 7556c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 75571107c7b2SJohn Garry sd_dp = &sqcp->sd_dp; 75581107c7b2SJohn Garry 7559*600d9eadSJohn Garry if (READ_ONCE(sd_dp->defer_t) != SDEB_DEFER_POLL) { 75601107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 7561*600d9eadSJohn Garry return true; 75621107c7b2SJohn Garry } 75631107c7b2SJohn Garry 7564*600d9eadSJohn Garry if (time < sd_dp->cmpl_ts) { 75651107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 7566*600d9eadSJohn Garry return true; 75671107c7b2SJohn Garry } 75681107c7b2SJohn Garry 7569c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 75704a0c6f43SDouglas Gilbert retiring = true; 7571c4b57d89SKashyap Desai 7572*600d9eadSJohn Garry qc_idx = sd_dp->sqa_idx; 7573*600d9eadSJohn Garry sqp->qc_arr[qc_idx] = NULL; 7574c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 75751107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 7576*600d9eadSJohn Garry pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u\n", 7577*600d9eadSJohn Garry sqp, queue_num, qc_idx); 75781107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 7579*600d9eadSJohn Garry return true; 7580c4b57d89SKashyap Desai } 7581c4b57d89SKashyap Desai 7582*600d9eadSJohn Garry if (unlikely(retiring)) { /* user has reduced max_queue */ 7583*600d9eadSJohn Garry int k, retval = atomic_read(&retired_max_queue); 7584*600d9eadSJohn Garry 7585c4b57d89SKashyap Desai if (qc_idx >= retval) { 7586c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 75871107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 75881107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 7589*600d9eadSJohn Garry return true; 7590c4b57d89SKashyap Desai } 7591*600d9eadSJohn Garry 7592c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7593c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7594c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7595c4b57d89SKashyap Desai else 7596c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7597c4b57d89SKashyap Desai } 7598*600d9eadSJohn Garry 7599*600d9eadSJohn Garry ASSIGN_QUEUED_CMD(cmd, NULL); 76001107c7b2SJohn Garry spin_unlock_irqrestore(&sdsc->lock, flags); 7601548ebb33SJohn Garry 7602548ebb33SJohn Garry if (sdebug_statistics) { 7603548ebb33SJohn Garry atomic_inc(&sdebug_completions); 7604548ebb33SJohn Garry if (raw_smp_processor_id() != sd_dp->issuing_cpu) 7605548ebb33SJohn Garry atomic_inc(&sdebug_miss_cpus); 7606548ebb33SJohn Garry } 7607548ebb33SJohn Garry 76081107c7b2SJohn Garry sdebug_free_queued_cmd(sqcp); 76091107c7b2SJohn Garry 7610*600d9eadSJohn Garry scsi_done(cmd); /* callback to mid level */ 7611*600d9eadSJohn Garry (*data->num_entries)++; 7612*600d9eadSJohn Garry return true; 76134a0c6f43SDouglas Gilbert } 76143fd07aecSDamien Le Moal 7615*600d9eadSJohn Garry static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7616*600d9eadSJohn Garry { 7617*600d9eadSJohn Garry int num_entries = 0; 7618*600d9eadSJohn Garry unsigned long iflags; 7619*600d9eadSJohn Garry struct sdebug_queue *sqp; 7620*600d9eadSJohn Garry struct sdebug_blk_mq_poll_data data = { 7621*600d9eadSJohn Garry .queue_num = queue_num, 7622*600d9eadSJohn Garry .num_entries = &num_entries, 7623*600d9eadSJohn Garry }; 7624*600d9eadSJohn Garry sqp = sdebug_q_arr + queue_num; 76253fd07aecSDamien Le Moal 7626*600d9eadSJohn Garry spin_lock_irqsave(&sqp->qc_lock, iflags); 7627*600d9eadSJohn Garry 7628*600d9eadSJohn Garry blk_mq_tagset_busy_iter(&shost->tag_set, sdebug_blk_mq_poll_iter, 7629*600d9eadSJohn Garry &data); 7630*600d9eadSJohn Garry 7631*600d9eadSJohn Garry spin_unlock_irqrestore(&sqp->qc_lock, iflags); 76324a0c6f43SDouglas Gilbert if (num_entries > 0) 76334a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7634c4b57d89SKashyap Desai return num_entries; 7635c4b57d89SKashyap Desai } 7636c4b57d89SKashyap Desai 7637fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7638fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7639c2248fc9SDouglas Gilbert { 7640c2248fc9SDouglas Gilbert u8 sdeb_i; 7641c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7642c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7643c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7644c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7645c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7646c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7647f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7648c2248fc9SDouglas Gilbert int k, na; 7649c2248fc9SDouglas Gilbert int errsts = 0; 7650ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7651c2248fc9SDouglas Gilbert u32 flags; 7652c2248fc9SDouglas Gilbert u16 sa; 7653c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7654c2248fc9SDouglas Gilbert bool has_wlun_rl; 76553a90a63dSDouglas Gilbert bool inject_now; 7656c2248fc9SDouglas Gilbert 7657c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 76583a90a63dSDouglas Gilbert if (sdebug_statistics) { 7659c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 76603a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 76613a90a63dSDouglas Gilbert } else { 76623a90a63dSDouglas Gilbert inject_now = false; 76633a90a63dSDouglas Gilbert } 7664f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7665f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7666c2248fc9SDouglas Gilbert char b[120]; 7667c2248fc9SDouglas Gilbert int n, len, sb; 7668c2248fc9SDouglas Gilbert 7669c2248fc9SDouglas Gilbert len = scp->cmd_len; 7670c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7671c2248fc9SDouglas Gilbert if (len > 32) 7672c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7673c2248fc9SDouglas Gilbert else { 7674c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7675c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7676c2248fc9SDouglas Gilbert (u32)cmd[k]); 7677c2248fc9SDouglas Gilbert } 7678458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7679a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7680c2248fc9SDouglas Gilbert } 76813a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 76827ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 768334d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7684ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7685f46eb0e9SDouglas Gilbert goto err_out; 7686c2248fc9SDouglas Gilbert 7687c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7688c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7689c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7690f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7691f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7692c2248fc9SDouglas Gilbert if (NULL == devip) 7693f46eb0e9SDouglas Gilbert goto err_out; 7694c2248fc9SDouglas Gilbert } 76953a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 76963a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 76973a90a63dSDouglas Gilbert 7698c2248fc9SDouglas Gilbert na = oip->num_attached; 7699c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7700c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7701c2248fc9SDouglas Gilbert r_oip = oip; 7702c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7703c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7704c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7705c2248fc9SDouglas Gilbert else 7706c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7707c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7708c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7709c2248fc9SDouglas Gilbert break; 7710c2248fc9SDouglas Gilbert } 7711c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7712c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7713c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7714c2248fc9SDouglas Gilbert break; 7715c2248fc9SDouglas Gilbert } 7716c2248fc9SDouglas Gilbert } 7717c2248fc9SDouglas Gilbert if (k > na) { 7718c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7719c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7720c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7721c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7722c2248fc9SDouglas Gilbert else 7723c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7724c2248fc9SDouglas Gilbert goto check_cond; 7725c2248fc9SDouglas Gilbert } 7726c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7727c2248fc9SDouglas Gilbert flags = oip->flags; 7728f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7729c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7730c2248fc9SDouglas Gilbert goto check_cond; 7731c2248fc9SDouglas Gilbert } 7732f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7733773642d9SDouglas Gilbert if (sdebug_verbose) 7734773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7735773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7736c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7737c2248fc9SDouglas Gilbert goto check_cond; 7738c2248fc9SDouglas Gilbert } 7739f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7740c2248fc9SDouglas Gilbert u8 rem; 7741c2248fc9SDouglas Gilbert int j; 7742c2248fc9SDouglas Gilbert 7743c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7744c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7745c2248fc9SDouglas Gilbert if (rem) { 7746c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7747c2248fc9SDouglas Gilbert if (0x80 & rem) 7748c2248fc9SDouglas Gilbert break; 7749c2248fc9SDouglas Gilbert } 7750c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7751c2248fc9SDouglas Gilbert goto check_cond; 7752c2248fc9SDouglas Gilbert } 7753c2248fc9SDouglas Gilbert } 7754c2248fc9SDouglas Gilbert } 7755f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7756b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7757b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7758f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7759c2248fc9SDouglas Gilbert if (errsts) 7760c2248fc9SDouglas Gilbert goto check_cond; 7761c2248fc9SDouglas Gilbert } 7762fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7763fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7764fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7765fc13638aSDouglas Gilbert if (errsts) 7766c2248fc9SDouglas Gilbert goto fini; 7767c2248fc9SDouglas Gilbert } 7768773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7769c2248fc9SDouglas Gilbert goto fini; 7770f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7771c4837394SDouglas Gilbert if (fake_timeout(scp)) 7772c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7773c2248fc9SDouglas Gilbert } 7774f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7775f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7776f66b8517SMartin Wilck else 7777f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7778c2248fc9SDouglas Gilbert 7779c2248fc9SDouglas Gilbert fini: 778067da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7781f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 778275aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 778375aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 778480c49563SDouglas Gilbert /* 778575aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 778675aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 778775aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 778875aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 778980c49563SDouglas Gilbert */ 779080c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 77914f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 779280c49563SDouglas Gilbert 77934f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7794f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 779580c49563SDouglas Gilbert } else 7796f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 779710bde980SDouglas Gilbert sdebug_ndelay); 7798c2248fc9SDouglas Gilbert check_cond: 7799f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7800f46eb0e9SDouglas Gilbert err_out: 7801f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7802c2248fc9SDouglas Gilbert } 7803c2248fc9SDouglas Gilbert 78041107c7b2SJohn Garry static int sdebug_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd) 78051107c7b2SJohn Garry { 78061107c7b2SJohn Garry struct sdebug_scsi_cmd *sdsc = scsi_cmd_priv(cmd); 78071107c7b2SJohn Garry 78081107c7b2SJohn Garry spin_lock_init(&sdsc->lock); 78091107c7b2SJohn Garry 78101107c7b2SJohn Garry return 0; 78111107c7b2SJohn Garry } 78121107c7b2SJohn Garry 78131107c7b2SJohn Garry 78149e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7815c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7816c8ed555aSAl Viro .write_info = scsi_debug_write_info, 78179e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 78189e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 78199e603ca0SFUJITA Tomonori .info = scsi_debug_info, 78209e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 78219e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 78229e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 78239e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7824185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7825cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7826c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7827c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 78289e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 78299e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7830cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7831cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 78329e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7833c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 78349e603ca0SFUJITA Tomonori .this_id = 7, 783565e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7836cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 78376bb5e6e7SAkinobu Mita .max_sectors = -1U, 783850c2e910SChristoph Hellwig .max_segment_size = -1U, 78399e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7840c40ecc12SChristoph Hellwig .track_queue_depth = 1, 78411107c7b2SJohn Garry .cmd_size = sizeof(struct sdebug_scsi_cmd), 78421107c7b2SJohn Garry .init_cmd_priv = sdebug_init_cmd_priv, 78439e603ca0SFUJITA Tomonori }; 78449e603ca0SFUJITA Tomonori 78451da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 78461da177e4SLinus Torvalds { 78471da177e4SLinus Torvalds int error = 0; 78481da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 78491da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7850f46eb0e9SDouglas Gilbert int hprot; 78511da177e4SLinus Torvalds 7852785d6b7cSJohn Garry sdbg_host = dev_to_sdebug_host(dev); 78531da177e4SLinus Torvalds 7854773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7855fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 78562a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 78574af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 78584af14d11SChristoph Hellwig 7859785d6b7cSJohn Garry hpnt = scsi_host_alloc(&sdebug_driver_template, 0); 78601da177e4SLinus Torvalds if (NULL == hpnt) { 7861c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 78621da177e4SLinus Torvalds error = -ENODEV; 78631da177e4SLinus Torvalds return error; 78641da177e4SLinus Torvalds } 7865c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 78669b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7867c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7868c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7869c4837394SDouglas Gilbert } 7870c10fa55fSJohn Garry /* 7871c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7872f7c4cdc7SJohn Garry * following should give the same answer for each host. 7873c10fa55fSJohn Garry */ 7874c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7875f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7876f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 78771da177e4SLinus Torvalds 7878c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7879c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7880c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7881c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7882c4b57d89SKashyap Desai poll_queues = 0; 7883c4b57d89SKashyap Desai } 7884c4b57d89SKashyap Desai 7885c4b57d89SKashyap Desai /* 7886c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7887c4b57d89SKashyap Desai * left over for non-polled I/O. 7888c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7889c4b57d89SKashyap Desai */ 7890c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7891fc09acb7SDouglas Gilbert if (submit_queues < 3) 7892c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7893fc09acb7SDouglas Gilbert else 7894fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7895fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7896c4b57d89SKashyap Desai poll_queues = 1; 7897c4b57d89SKashyap Desai } 7898c4b57d89SKashyap Desai if (poll_queues) 7899c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7900c4b57d89SKashyap Desai 79011da177e4SLinus Torvalds sdbg_host->shost = hpnt; 7902773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7903773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 79041da177e4SLinus Torvalds else 7905773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7906773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7907f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 79081da177e4SLinus Torvalds 7909f46eb0e9SDouglas Gilbert hprot = 0; 7910c6a44287SMartin K. Petersen 7911773642d9SDouglas Gilbert switch (sdebug_dif) { 7912c6a44287SMartin K. Petersen 79138475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7914f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7915773642d9SDouglas Gilbert if (sdebug_dix) 7916f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7917c6a44287SMartin K. Petersen break; 7918c6a44287SMartin K. Petersen 79198475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7920f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7921773642d9SDouglas Gilbert if (sdebug_dix) 7922f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7923c6a44287SMartin K. Petersen break; 7924c6a44287SMartin K. Petersen 79258475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7926f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7927773642d9SDouglas Gilbert if (sdebug_dix) 7928f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7929c6a44287SMartin K. Petersen break; 7930c6a44287SMartin K. Petersen 7931c6a44287SMartin K. Petersen default: 7932773642d9SDouglas Gilbert if (sdebug_dix) 7933f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7934c6a44287SMartin K. Petersen break; 7935c6a44287SMartin K. Petersen } 7936c6a44287SMartin K. Petersen 7937f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7938c6a44287SMartin K. Petersen 7939f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7940c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7941f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7942f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7943f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7944f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7945f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7946f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7947f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7948c6a44287SMartin K. Petersen 7949773642d9SDouglas Gilbert if (sdebug_guard == 1) 7950c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7951c6a44287SMartin K. Petersen else 7952c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7953c6a44287SMartin K. Petersen 7954773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7955773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7956c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7957c4837394SDouglas Gilbert sdebug_statistics = true; 79581da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 79591da177e4SLinus Torvalds if (error) { 7960c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 79611da177e4SLinus Torvalds error = -ENODEV; 79621da177e4SLinus Torvalds scsi_host_put(hpnt); 796387c715dcSDouglas Gilbert } else { 79641da177e4SLinus Torvalds scsi_scan_host(hpnt); 796587c715dcSDouglas Gilbert } 79661da177e4SLinus Torvalds 79671da177e4SLinus Torvalds return error; 79681da177e4SLinus Torvalds } 79691da177e4SLinus Torvalds 7970fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev) 79711da177e4SLinus Torvalds { 79721da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 79738b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 79741da177e4SLinus Torvalds 7975785d6b7cSJohn Garry sdbg_host = dev_to_sdebug_host(dev); 79761da177e4SLinus Torvalds 79771da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 79781da177e4SLinus Torvalds 79798b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 79808b40228fSFUJITA Tomonori dev_list) { 79811da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7982f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 79831da177e4SLinus Torvalds kfree(sdbg_devinfo); 79841da177e4SLinus Torvalds } 79851da177e4SLinus Torvalds 79861da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 79871da177e4SLinus Torvalds } 79881da177e4SLinus Torvalds 79898dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 79908dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 79911da177e4SLinus Torvalds { 79928dea0d02SFUJITA Tomonori return 1; 79938dea0d02SFUJITA Tomonori } 79941da177e4SLinus Torvalds 79958dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 79968dea0d02SFUJITA Tomonori .name = "pseudo", 79978dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 79988dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 79998dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 800082069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 80018dea0d02SFUJITA Tomonori }; 8002