18d7c56d0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 21da177e4SLinus Torvalds /* 31da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 41da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 51da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 61da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 71da177e4SLinus Torvalds * anything out of the ordinary is seen. 81da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 91da177e4SLinus Torvalds * 1048e3bf16SDouglas Gilbert * Copyright (C) 2001 - 2020 Douglas Gilbert 111da177e4SLinus Torvalds * 1230f67481SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/scsi_debug.html 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 15c1287970STomas Winkler 16c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 17c1287970STomas Winkler 181da177e4SLinus Torvalds #include <linux/module.h> 191da177e4SLinus Torvalds 201da177e4SLinus Torvalds #include <linux/kernel.h> 211da177e4SLinus Torvalds #include <linux/errno.h> 22b333a819SDouglas Gilbert #include <linux/jiffies.h> 235a0e3ad6STejun Heo #include <linux/slab.h> 241da177e4SLinus Torvalds #include <linux/types.h> 251da177e4SLinus Torvalds #include <linux/string.h> 261da177e4SLinus Torvalds #include <linux/genhd.h> 271da177e4SLinus Torvalds #include <linux/fs.h> 281da177e4SLinus Torvalds #include <linux/init.h> 291da177e4SLinus Torvalds #include <linux/proc_fs.h> 301da177e4SLinus Torvalds #include <linux/vmalloc.h> 311da177e4SLinus Torvalds #include <linux/moduleparam.h> 32852e034dSJens Axboe #include <linux/scatterlist.h> 331da177e4SLinus Torvalds #include <linux/blkdev.h> 34c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 35cbf67842SDouglas Gilbert #include <linux/spinlock.h> 362aad3cd8SDouglas Gilbert #include <linux/mutex.h> 37cbf67842SDouglas Gilbert #include <linux/interrupt.h> 38cbf67842SDouglas Gilbert #include <linux/atomic.h> 39cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 4009ba24c1SDouglas Gilbert #include <linux/uuid.h> 416ebf105cSChristoph Hellwig #include <linux/t10-pi.h> 421442f76dSChristoph Hellwig #include <linux/msdos_partition.h> 430c4bc91dSDouglas Gilbert #include <linux/random.h> 4487c715dcSDouglas Gilbert #include <linux/xarray.h> 45ed9f3e25SDouglas Gilbert #include <linux/prefetch.h> 46c6a44287SMartin K. Petersen 47c6a44287SMartin K. Petersen #include <net/checksum.h> 489ff26eefSFUJITA Tomonori 4944d92694SMartin K. Petersen #include <asm/unaligned.h> 5044d92694SMartin K. Petersen 519ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 541da177e4SLinus Torvalds #include <scsi/scsi_host.h> 551da177e4SLinus Torvalds #include <scsi/scsicam.h> 56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 591da177e4SLinus Torvalds 60c6a44287SMartin K. Petersen #include "sd.h" 611da177e4SLinus Torvalds #include "scsi_logging.h" 621da177e4SLinus Torvalds 63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 6430f67481SDouglas Gilbert #define SDEBUG_VERSION "0190" /* format to fit INQUIRY revision field */ 6530f67481SDouglas Gilbert static const char *sdebug_version_date = "20200710"; 66cbf67842SDouglas Gilbert 67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 681da177e4SLinus Torvalds 696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 799447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27 80cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 81cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8219c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8319c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8422017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8522017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 86cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 87cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 88cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8922017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 901da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 916f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 92c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 93c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9422017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 96acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 97481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc 98f0d1cf93SDouglas Gilbert #define UNALIGNED_WRITE_ASCQ 0x4 99f0d1cf93SDouglas Gilbert #define WRITE_BOUNDARY_ASCQ 0x5 100f0d1cf93SDouglas Gilbert #define READ_INVDATA_ASCQ 0x6 101f0d1cf93SDouglas Gilbert #define READ_BOUNDARY_ASCQ 0x7 102f0d1cf93SDouglas Gilbert #define INSUFF_ZONE_ASCQ 0xe 1031da177e4SLinus Torvalds 1046f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 1056f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 1066f3cbf55SDouglas Gilbert 1071da177e4SLinus Torvalds /* Default values for driver parameters */ 1081da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1091da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1101da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1111da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1121da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1131da177e4SLinus Torvalds */ 1145b94e232SMartin K. Petersen #define DEF_ATO 1 1159b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10 116c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1179267e0ebSDouglas Gilbert #define DEF_DEV_SIZE_PRE_INIT 0 1181da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1199267e0ebSDouglas Gilbert #define DEF_ZBC_DEV_SIZE_MB 128 1205b94e232SMartin K. Petersen #define DEF_DIF 0 1215b94e232SMartin K. Petersen #define DEF_DIX 0 12287c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false 1235b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1241da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1255b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1265b94e232SMartin K. Petersen #define DEF_GUARD 0 127cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1285b94e232SMartin K. Petersen #define DEF_LBPU 0 1295b94e232SMartin K. Petersen #define DEF_LBPWS 0 1305b94e232SMartin K. Petersen #define DEF_LBPWS10 0 131be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1325b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 133cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1345b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1351da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1361da177e4SLinus Torvalds #define DEF_OPTS 0 13732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1385b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 13986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 140b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 1410c4bc91dSDouglas Gilbert #define DEF_RANDOM false 142d986788bSMartin Pitt #define DEF_REMOVABLE false 143760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1445b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1455b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1465b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1476014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1486014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1495b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1505b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1515b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 152c2248fc9SDouglas Gilbert #define DEF_STRICT 0 153c4837394SDouglas Gilbert #define DEF_STATISTICS false 154c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 155fc13638aSDouglas Gilbert #define DEF_TUR_MS_TO_READY 0 15609ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 157c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1581da177e4SLinus Torvalds 159f0d1cf93SDouglas Gilbert /* Default parameters for ZBC drives */ 160f0d1cf93SDouglas Gilbert #define DEF_ZBC_ZONE_SIZE_MB 128 161f0d1cf93SDouglas Gilbert #define DEF_ZBC_MAX_OPEN_ZONES 8 162aa8fecf9SDamien Le Moal #define DEF_ZBC_NR_CONV_ZONES 1 163f0d1cf93SDouglas Gilbert 164b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 165b01f6f83SDouglas Gilbert 166773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 167773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 168773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 169773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 170773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 171773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 172773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 173773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 174773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 175773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 176773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 177*7d5a129bSDouglas 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 */ 200cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 201cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 2020d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 20319c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 205acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 206acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 207cbf67842SDouglas Gilbert 208773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2091da177e4SLinus Torvalds * sector on read commands: */ 2101da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 21132f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2121da177e4SLinus Torvalds 213c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 214c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 215c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 216c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 217c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 218c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 219c4837394SDouglas Gilbert */ 220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 222fc09acb7SDouglas Gilbert #define DEF_CMD_PER_LUN SDEBUG_CANQUEUE 223cbf67842SDouglas Gilbert 224b6ff8ca7SDouglas Gilbert /* UA - Unit Attention; SA - Service Action; SSU - Start Stop Unit */ 225b6ff8ca7SDouglas Gilbert #define F_D_IN 1 /* Data-in command (e.g. READ) */ 226b6ff8ca7SDouglas Gilbert #define F_D_OUT 2 /* Data-out command (e.g. WRITE) */ 227fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 228fd32119bSDouglas Gilbert #define F_D_UNKN 8 229b6ff8ca7SDouglas Gilbert #define F_RL_WLUN_OK 0x10 /* allowed with REPORT LUNS W-LUN */ 230b6ff8ca7SDouglas Gilbert #define F_SKIP_UA 0x20 /* bypass UAs (e.g. INQUIRY command) */ 231b6ff8ca7SDouglas Gilbert #define F_DELAY_OVERR 0x40 /* for commands like INQUIRY */ 232b6ff8ca7SDouglas Gilbert #define F_SA_LOW 0x80 /* SA is in cdb byte 1, bits 4 to 0 */ 233b6ff8ca7SDouglas Gilbert #define F_SA_HIGH 0x100 /* SA is in cdb bytes 8 and 9 */ 234b6ff8ca7SDouglas Gilbert #define F_INV_OP 0x200 /* invalid opcode (not supported) */ 235b6ff8ca7SDouglas Gilbert #define F_FAKE_RW 0x400 /* bypass resp_*() when fake_rw set */ 236b6ff8ca7SDouglas Gilbert #define F_M_ACCESS 0x800 /* media access, reacts to SSU state */ 237b6ff8ca7SDouglas Gilbert #define F_SSU_DELAY 0x1000 /* SSU command delay (long-ish) */ 238b6ff8ca7SDouglas Gilbert #define F_SYNC_DELAY 0x2000 /* SYNCHRONIZE CACHE delay */ 239fd32119bSDouglas Gilbert 240b6ff8ca7SDouglas Gilbert /* Useful combinations of the above flags */ 241fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 24246f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 243fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2444f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 245fd32119bSDouglas Gilbert 246fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 247fd32119bSDouglas Gilbert 248b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 249fd32119bSDouglas Gilbert 25087c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 25187c715dcSDouglas Gilbert 25264e14eceSDamien Le Moal /* Zone types (zbcr05 table 25) */ 25364e14eceSDamien Le Moal enum sdebug_z_type { 25464e14eceSDamien Le Moal ZBC_ZONE_TYPE_CNV = 0x1, 25564e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWR = 0x2, 25664e14eceSDamien Le Moal ZBC_ZONE_TYPE_SWP = 0x3, 25764e14eceSDamien Le Moal }; 25864e14eceSDamien Le Moal 259f0d1cf93SDouglas Gilbert /* enumeration names taken from table 26, zbcr05 */ 260f0d1cf93SDouglas Gilbert enum sdebug_z_cond { 261f0d1cf93SDouglas Gilbert ZBC_NOT_WRITE_POINTER = 0x0, 262f0d1cf93SDouglas Gilbert ZC1_EMPTY = 0x1, 263f0d1cf93SDouglas Gilbert ZC2_IMPLICIT_OPEN = 0x2, 264f0d1cf93SDouglas Gilbert ZC3_EXPLICIT_OPEN = 0x3, 265f0d1cf93SDouglas Gilbert ZC4_CLOSED = 0x4, 266f0d1cf93SDouglas Gilbert ZC6_READ_ONLY = 0xd, 267f0d1cf93SDouglas Gilbert ZC5_FULL = 0xe, 268f0d1cf93SDouglas Gilbert ZC7_OFFLINE = 0xf, 269f0d1cf93SDouglas Gilbert }; 270f0d1cf93SDouglas Gilbert 271f0d1cf93SDouglas Gilbert struct sdeb_zone_state { /* ZBC: per zone state */ 27264e14eceSDamien Le Moal enum sdebug_z_type z_type; 273f0d1cf93SDouglas Gilbert enum sdebug_z_cond z_cond; 27464e14eceSDamien Le Moal bool z_non_seq_resource; 275f0d1cf93SDouglas Gilbert unsigned int z_size; 276f0d1cf93SDouglas Gilbert sector_t z_start; 277f0d1cf93SDouglas Gilbert sector_t z_wp; 278f0d1cf93SDouglas Gilbert }; 279fd32119bSDouglas Gilbert 280fd32119bSDouglas Gilbert struct sdebug_dev_info { 281fd32119bSDouglas Gilbert struct list_head dev_list; 282fd32119bSDouglas Gilbert unsigned int channel; 283fd32119bSDouglas Gilbert unsigned int target; 284fd32119bSDouglas Gilbert u64 lun; 285bf476433SChristoph Hellwig uuid_t lu_name; 286fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 287fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 288fd32119bSDouglas Gilbert atomic_t num_in_q; 289fc13638aSDouglas Gilbert atomic_t stopped; /* 1: by SSU, 2: device start */ 290fd32119bSDouglas Gilbert bool used; 291f0d1cf93SDouglas Gilbert 292f0d1cf93SDouglas Gilbert /* For ZBC devices */ 29364e14eceSDamien Le Moal enum blk_zoned_model zmodel; 294f0d1cf93SDouglas Gilbert unsigned int zsize; 295f0d1cf93SDouglas Gilbert unsigned int zsize_shift; 296f0d1cf93SDouglas Gilbert unsigned int nr_zones; 297aa8fecf9SDamien Le Moal unsigned int nr_conv_zones; 298f0d1cf93SDouglas Gilbert unsigned int nr_imp_open; 299f0d1cf93SDouglas Gilbert unsigned int nr_exp_open; 300f0d1cf93SDouglas Gilbert unsigned int nr_closed; 301f0d1cf93SDouglas Gilbert unsigned int max_open; 302fc13638aSDouglas Gilbert ktime_t create_ts; /* time since bootup that this device was created */ 303f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zstate; 304fd32119bSDouglas Gilbert }; 305fd32119bSDouglas Gilbert 306fd32119bSDouglas Gilbert struct sdebug_host_info { 307fd32119bSDouglas Gilbert struct list_head host_list; 30887c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 309fd32119bSDouglas Gilbert struct Scsi_Host *shost; 310fd32119bSDouglas Gilbert struct device dev; 311fd32119bSDouglas Gilbert struct list_head dev_info_list; 312fd32119bSDouglas Gilbert }; 313fd32119bSDouglas Gilbert 31487c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 31587c715dcSDouglas Gilbert struct sdeb_store_info { 31687c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 31787c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 31887c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 31987c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 32087c715dcSDouglas Gilbert }; 32187c715dcSDouglas Gilbert 322fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 323fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 324fd32119bSDouglas Gilbert 32510bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 3264a0c6f43SDouglas Gilbert SDEB_DEFER_WQ = 2, SDEB_DEFER_POLL = 3}; 32710bde980SDouglas Gilbert 328fd32119bSDouglas Gilbert struct sdebug_defer { 329fd32119bSDouglas Gilbert struct hrtimer hrt; 330fd32119bSDouglas Gilbert struct execute_work ew; 3314a0c6f43SDouglas Gilbert ktime_t cmpl_ts;/* time since boot to complete this cmd */ 332c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 333c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 334c10fa55fSJohn Garry int hc_idx; /* hostwide tag index */ 335c4837394SDouglas Gilbert int issuing_cpu; 33610bde980SDouglas Gilbert bool init_hrt; 33710bde980SDouglas Gilbert bool init_wq; 3384a0c6f43SDouglas Gilbert bool init_poll; 3397382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 34010bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 341fd32119bSDouglas Gilbert }; 342fd32119bSDouglas Gilbert 343fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 344c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 345c4837394SDouglas Gilbert * instance indicates this slot is in use. 346c4837394SDouglas Gilbert */ 347fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 348fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 349fd32119bSDouglas Gilbert }; 350fd32119bSDouglas Gilbert 351c4837394SDouglas Gilbert struct sdebug_queue { 352c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 353c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 354c4837394SDouglas Gilbert spinlock_t qc_lock; 355c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 356fd32119bSDouglas Gilbert }; 357fd32119bSDouglas Gilbert 358c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 359c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 360c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 361c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 3623a90a63dSDouglas Gilbert static atomic_t sdeb_inject_pending; 3634a0c6f43SDouglas Gilbert static atomic_t sdeb_mq_poll_count; /* bumped when mq_poll returns > 0 */ 364c4837394SDouglas Gilbert 365fd32119bSDouglas Gilbert struct opcode_info_t { 366b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 367b01f6f83SDouglas Gilbert /* for terminating element */ 368fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 369fd32119bSDouglas Gilbert u16 sa; /* service action */ 370fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 371fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 372fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3739a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3749a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 375fd32119bSDouglas Gilbert }; 376fd32119bSDouglas Gilbert 377fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 378c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 379c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 380c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 381c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 382c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 383c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 384c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 385c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 386c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 387c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 388c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 389c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 390c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 39146f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 39246f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 393c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 394c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 395c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 396481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 397c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 398c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 399c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 400c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 401c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 402c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 403c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 404c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 405c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 406c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 407c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 408ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 409f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT = 30, /* 0x94+SA; includes no data xfer */ 410f0d1cf93SDouglas Gilbert SDEB_I_ZONE_IN = 31, /* 0x95+SA; all have data-in */ 411f0d1cf93SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 32, /* keep this last (previous + 1) */ 412c2248fc9SDouglas Gilbert }; 413c2248fc9SDouglas Gilbert 414c4837394SDouglas Gilbert 415c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 416c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 417c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 418c2248fc9SDouglas Gilbert 0, 0, 0, 0, 419c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 420c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 421c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 422c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 423c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 424c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 425c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 426c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 427ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 428c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 429c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 430c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 431c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 432c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 433c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 434c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 435fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 436c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 437c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 438c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 439c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 440c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 441c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 442c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 443f0d1cf93SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 444f0d1cf93SDouglas Gilbert SDEB_I_ZONE_OUT, SDEB_I_ZONE_IN, 0, 0, 44546f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 446c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 447c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 448c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 44946f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 45046f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 451c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 452c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 453c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 454c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 455c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 456c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 457c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 458c2248fc9SDouglas Gilbert }; 459c2248fc9SDouglas Gilbert 46080c49563SDouglas Gilbert /* 46180c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 46280c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 46380c49563SDouglas Gilbert * command completion, they can mask their return value with 46480c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 46580c49563SDouglas Gilbert */ 46680c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 46780c49563SDouglas Gilbert 468c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 469c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 470c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 471c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 472c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 473c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 474c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 475c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 476c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 477481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 478c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 479c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 480c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 481c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 482c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 48338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 48438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 485c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 486c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 487c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 48838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 489acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 49080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 491ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 492f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *, struct sdebug_dev_info *); 493f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 494f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 495f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 496f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *, struct sdebug_dev_info *); 497c2248fc9SDouglas Gilbert 49887c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 49987c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 50087c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 50187c715dcSDouglas Gilbert static int sdebug_add_store(void); 50287c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 50387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 50487c715dcSDouglas Gilbert 50546f64e70SDouglas Gilbert /* 50646f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 50746f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 50846f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 50946f64e70SDouglas Gilbert */ 51046f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 511c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 512c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 513c2248fc9SDouglas Gilbert }; 514c2248fc9SDouglas Gilbert 51546f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 516c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 517c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 518c2248fc9SDouglas Gilbert }; 519c2248fc9SDouglas Gilbert 52046f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 52146f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 522b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 523c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 52446f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 525c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 52646f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 527b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 528c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 529c2248fc9SDouglas Gilbert }; 530c2248fc9SDouglas Gilbert 53146f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 53246f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 53346f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 53446f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 53546f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 53646f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 53746f64e70SDouglas Gilbert 0, 0, 0} }, 53846f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 53946f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54046f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 541c2248fc9SDouglas Gilbert }; 542c2248fc9SDouglas Gilbert 543c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 544c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 545c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 546c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 547c3e2fe92SDouglas Gilbert }; 548c3e2fe92SDouglas Gilbert 54946f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 550c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 551c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 55246f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 553c2248fc9SDouglas Gilbert }; 554c2248fc9SDouglas Gilbert 55546f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 55646f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 557b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 558c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 559481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 560481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 561481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 562c2248fc9SDouglas Gilbert }; 563c2248fc9SDouglas Gilbert 56446f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 56538d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 566c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 56746f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 56838d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 569c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 57046f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 571c2248fc9SDouglas Gilbert }; 572c2248fc9SDouglas Gilbert 57346f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 57446f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 575c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 57646f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 577c2248fc9SDouglas Gilbert }; 578c2248fc9SDouglas Gilbert 57946f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 580c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 581c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 582c2248fc9SDouglas Gilbert }; 583c2248fc9SDouglas Gilbert 58446f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 585c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 586c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 587c2248fc9SDouglas Gilbert }; 588c2248fc9SDouglas Gilbert 58980c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5904f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 59180c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59280c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 59380c49563SDouglas Gilbert }; 59480c49563SDouglas Gilbert 595ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 596b6ff8ca7SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | FF_MEDIA_IO, resp_pre_fetch, NULL, 597ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 598ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 599ed9f3e25SDouglas Gilbert }; 600ed9f3e25SDouglas Gilbert 601f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_out_iarr[] = { /* ZONE OUT(16) */ 602b6ff8ca7SDouglas Gilbert {0, 0x94, 0x1, F_SA_LOW | F_M_ACCESS, resp_close_zone, NULL, 603f0d1cf93SDouglas Gilbert {16, 0x1, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 604f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* CLOSE ZONE */ 605b6ff8ca7SDouglas Gilbert {0, 0x94, 0x2, F_SA_LOW | F_M_ACCESS, resp_finish_zone, NULL, 606f0d1cf93SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 607f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* FINISH ZONE */ 608b6ff8ca7SDouglas Gilbert {0, 0x94, 0x4, F_SA_LOW | F_M_ACCESS, resp_rwp_zone, NULL, 609f0d1cf93SDouglas Gilbert {16, 0x4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 610f0d1cf93SDouglas Gilbert 0xff, 0, 0, 0xff, 0xff, 0x1, 0xc7} }, /* RESET WRITE POINTER */ 611f0d1cf93SDouglas Gilbert }; 612f0d1cf93SDouglas Gilbert 613f0d1cf93SDouglas Gilbert static const struct opcode_info_t zone_in_iarr[] = { /* ZONE IN(16) */ 614b6ff8ca7SDouglas Gilbert {0, 0x95, 0x6, F_SA_LOW | F_D_IN | F_M_ACCESS, NULL, NULL, 615f0d1cf93SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 616f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* REPORT ZONES */ 617f0d1cf93SDouglas Gilbert }; 618f0d1cf93SDouglas Gilbert 619c2248fc9SDouglas Gilbert 620c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 621c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 622c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 623ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 624c2248fc9SDouglas Gilbert /* 0 */ 62546f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 626c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 62746f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 628c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 629c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 630c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 63146f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 632c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 633c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 634c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 635c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63646f64e70SDouglas Gilbert /* 5 */ 63746f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 63846f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 63946f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64046f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 64146f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 64246f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 64346f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 644c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 645c2248fc9SDouglas Gilbert 0, 0, 0} }, 64646f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 647c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 648c2248fc9SDouglas Gilbert 0, 0} }, 64946f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 65046f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 65146f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 652c2248fc9SDouglas Gilbert /* 10 */ 65346f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 65446f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 65546f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 65680c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 6574f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 658c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 65946f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 66046f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 66146f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 66246f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 663481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 664481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 665481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 66646f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 66746f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 66846f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 66946f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 67046f64e70SDouglas Gilbert /* 15 */ 671c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 672c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 673c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 674c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 675c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 676c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 67746f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 67846f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 67946f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 68046f64e70SDouglas Gilbert 0xff, 0xff} }, 68146f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 68246f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 683c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 684c2248fc9SDouglas Gilbert 0} }, 68546f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 68646f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 687c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 688c2248fc9SDouglas Gilbert 0} }, 689c2248fc9SDouglas Gilbert /* 20 */ 690f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 691f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 692c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 693c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 694c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 695c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 696c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 697c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 69846f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 699b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 70046f64e70SDouglas Gilbert /* 25 */ 701acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 702acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 703acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 70446f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 70546f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 70646f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 70746f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 7084f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 70980c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 710b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 71180c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 71246f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 713c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 714b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 715b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | FF_MEDIA_IO, 716ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 717ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 718ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 719c2248fc9SDouglas Gilbert 720ed9f3e25SDouglas Gilbert /* 30 */ 721b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_out_iarr), 0x94, 0x3, F_SA_LOW | F_M_ACCESS, 722f0d1cf93SDouglas Gilbert resp_open_zone, zone_out_iarr, /* ZONE_OUT(16), OPEN ZONE) */ 723f0d1cf93SDouglas Gilbert {16, 0x3 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 724f0d1cf93SDouglas Gilbert 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x1, 0xc7} }, 725b6ff8ca7SDouglas Gilbert {ARRAY_SIZE(zone_in_iarr), 0x95, 0x0, F_SA_LOW | F_M_ACCESS, 726f0d1cf93SDouglas Gilbert resp_report_zones, zone_in_iarr, /* ZONE_IN(16), REPORT ZONES) */ 727f0d1cf93SDouglas Gilbert {16, 0x0 /* SA */, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 728f0d1cf93SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xc7} }, 729f0d1cf93SDouglas Gilbert /* sentinel */ 730c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 731c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 732c2248fc9SDouglas Gilbert }; 733c2248fc9SDouglas Gilbert 7342aad3cd8SDouglas Gilbert static atomic_t sdebug_num_hosts; 7352aad3cd8SDouglas Gilbert static DEFINE_MUTEX(add_host_mutex); 7362aad3cd8SDouglas Gilbert 73787c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 738773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 7399b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 740c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 7419267e0ebSDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_PRE_INIT; 742773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 743773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 744773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 745773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 746773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 747773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 748c10fa55fSJohn Garry static int sdebug_host_max_queue; /* per host */ 749773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 750773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 751c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 752d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 753d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 754cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 755c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 756773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 757773642d9SDouglas Gilbert static int sdebug_no_uld; 758773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 759773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 760773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 761773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 762773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 76386e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 764b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 765773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 766773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 767fc13638aSDouglas Gilbert static int sdeb_tur_ms_to_ready = DEF_TUR_MS_TO_READY; 768773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 769773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 770773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 771773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 772773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 773773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 774773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 775773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 776773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 777773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 778773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 77909ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7800c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 78187c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 782773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 7832aad3cd8SDouglas Gilbert static bool sdebug_deflect_incoming; 784773642d9SDouglas Gilbert static bool sdebug_clustering; 785773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 786773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 787817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 788773642d9SDouglas Gilbert static bool sdebug_verbose; 789f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7904f2c8bf6SDouglas Gilbert static bool write_since_sync; 791c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7929447b6ceSMartin K. Petersen static bool sdebug_wp; 7939267e0ebSDouglas Gilbert /* Following enum: 0: no zbc, def; 1: host aware; 2: host managed */ 7949267e0ebSDouglas Gilbert static enum blk_zoned_model sdeb_zbc_model = BLK_ZONED_NONE; 7959267e0ebSDouglas Gilbert static char *sdeb_zbc_model_s; 7961da177e4SLinus Torvalds 797ad0c7775SDouglas Gilbert enum sam_lun_addr_method {SAM_LUN_AM_PERIPHERAL = 0x0, 798ad0c7775SDouglas Gilbert SAM_LUN_AM_FLAT = 0x1, 799ad0c7775SDouglas Gilbert SAM_LUN_AM_LOGICAL_UNIT = 0x2, 800ad0c7775SDouglas Gilbert SAM_LUN_AM_EXTENDED = 0x3}; 801ad0c7775SDouglas Gilbert static enum sam_lun_addr_method sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 802ad0c7775SDouglas Gilbert static int sdebug_lun_am_i = (int)SAM_LUN_AM_PERIPHERAL; 803ad0c7775SDouglas Gilbert 804c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 8051da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 8061da177e4SLinus Torvalds 8071da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 8081da177e4SLinus Torvalds may still need them */ 8091da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 8101da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 8111da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 8121da177e4SLinus Torvalds 8131da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 8141da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 8151da177e4SLinus Torvalds 81687c715dcSDouglas Gilbert static struct xarray per_store_arr; 81787c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 81887c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 81987c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 82087c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 8211da177e4SLinus Torvalds 82244d92694SMartin K. Petersen static unsigned long map_size; 823cbf67842SDouglas Gilbert static int num_aborts; 824cbf67842SDouglas Gilbert static int num_dev_resets; 825cbf67842SDouglas Gilbert static int num_target_resets; 826cbf67842SDouglas Gilbert static int num_bus_resets; 827cbf67842SDouglas Gilbert static int num_host_resets; 828c6a44287SMartin K. Petersen static int dix_writes; 829c6a44287SMartin K. Petersen static int dix_reads; 830c6a44287SMartin K. Petersen static int dif_errors; 8311da177e4SLinus Torvalds 832f0d1cf93SDouglas Gilbert /* ZBC global data */ 83364e14eceSDamien Le Moal static bool sdeb_zbc_in_use; /* true for host-aware and host-managed disks */ 83498e0a689SDamien Le Moal static int sdeb_zbc_zone_size_mb; 835380603a5SDamien Le Moal static int sdeb_zbc_max_open = DEF_ZBC_MAX_OPEN_ZONES; 836aa8fecf9SDamien Le Moal static int sdeb_zbc_nr_conv = DEF_ZBC_NR_CONV_ZONES; 837f0d1cf93SDouglas Gilbert 838c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 839c4b57d89SKashyap Desai static int poll_queues; /* iouring iopoll interface.*/ 840c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 841fd32119bSDouglas Gilbert 8421da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 84387c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 84487c715dcSDouglas Gilbert 84587c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 8461da177e4SLinus Torvalds 847cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 848cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 8491da177e4SLinus Torvalds 8501da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 8511da177e4SLinus Torvalds 8521da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 8531da177e4SLinus Torvalds .name = sdebug_proc_name, 8541da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 8551da177e4SLinus Torvalds }; 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds static const int check_condition_result = 858464a00c9SHannes Reinecke SAM_STAT_CHECK_CONDITION; 8591da177e4SLinus Torvalds 860c6a44287SMartin K. Petersen static const int illegal_condition_result = 861464a00c9SHannes Reinecke (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 862c6a44287SMartin K. Petersen 863cbf67842SDouglas Gilbert static const int device_qfull_result = 864*7d5a129bSDouglas Gilbert (DID_ABORT << 16) | SAM_STAT_TASK_SET_FULL; 865cbf67842SDouglas Gilbert 866ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 867ed9f3e25SDouglas Gilbert 868fd32119bSDouglas Gilbert 869760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 870760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 871760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 872760f3b03SDouglas Gilbert */ 873760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 874fd32119bSDouglas Gilbert { 875fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 876fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 877fd32119bSDouglas Gilbert } 878c65b1445SDouglas Gilbert 87987c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 88087c715dcSDouglas Gilbert unsigned long long lba) 88114faa944SAkinobu Mita { 88287c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 88314faa944SAkinobu Mita 88487c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 88587c715dcSDouglas Gilbert if (!sip || !sip->storep) { 88687c715dcSDouglas Gilbert WARN_ON_ONCE(true); 88787c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 88887c715dcSDouglas Gilbert } 88987c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 89014faa944SAkinobu Mita } 89114faa944SAkinobu Mita 89287c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 89387c715dcSDouglas Gilbert sector_t sector) 89414faa944SAkinobu Mita { 89549413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 89614faa944SAkinobu Mita 89787c715dcSDouglas Gilbert return sip->dif_storep + sector; 89814faa944SAkinobu Mita } 89914faa944SAkinobu Mita 9008dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 9018dea0d02SFUJITA Tomonori { 9028dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 9038dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 9048dea0d02SFUJITA Tomonori 9058dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 9068dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9078dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 9088dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 909773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 910773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 9118dea0d02SFUJITA Tomonori else 912773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 913773642d9SDouglas Gilbert /* sdebug_max_luns; */ 914f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 9158dea0d02SFUJITA Tomonori } 9168dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 9178dea0d02SFUJITA Tomonori } 9188dea0d02SFUJITA Tomonori 91922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 92022017ed2SDouglas Gilbert 92122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 922fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 923fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 92422017ed2SDouglas Gilbert int in_byte, int in_bit) 92522017ed2SDouglas Gilbert { 92622017ed2SDouglas Gilbert unsigned char *sbuff; 92722017ed2SDouglas Gilbert u8 sks[4]; 92822017ed2SDouglas Gilbert int sl, asc; 92922017ed2SDouglas Gilbert 93022017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 93122017ed2SDouglas Gilbert if (!sbuff) { 93222017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 93322017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 93422017ed2SDouglas Gilbert return; 93522017ed2SDouglas Gilbert } 93622017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 93722017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 938f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, ILLEGAL_REQUEST, asc, 0); 93922017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 94022017ed2SDouglas Gilbert sks[0] = 0x80; 94122017ed2SDouglas Gilbert if (c_d) 94222017ed2SDouglas Gilbert sks[0] |= 0x40; 94322017ed2SDouglas Gilbert if (in_bit >= 0) { 94422017ed2SDouglas Gilbert sks[0] |= 0x8; 94522017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 94622017ed2SDouglas Gilbert } 94722017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 948773642d9SDouglas Gilbert if (sdebug_dsense) { 94922017ed2SDouglas Gilbert sl = sbuff[7] + 8; 95022017ed2SDouglas Gilbert sbuff[7] = sl; 95122017ed2SDouglas Gilbert sbuff[sl] = 0x2; 95222017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 95322017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 95422017ed2SDouglas Gilbert } else 95522017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 956773642d9SDouglas Gilbert if (sdebug_verbose) 95722017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 95822017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 95922017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 96022017ed2SDouglas Gilbert } 96122017ed2SDouglas Gilbert 962cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 9638dea0d02SFUJITA Tomonori { 964f2b1e9c6SHannes Reinecke if (!scp->sense_buffer) { 965cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 966cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 967cbf67842SDouglas Gilbert return; 968cbf67842SDouglas Gilbert } 969f2b1e9c6SHannes Reinecke memset(scp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); 9708dea0d02SFUJITA Tomonori 971f2b1e9c6SHannes Reinecke scsi_build_sense(scp, sdebug_dsense, key, asc, asq); 9728dea0d02SFUJITA Tomonori 973773642d9SDouglas Gilbert if (sdebug_verbose) 974cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 975cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 976cbf67842SDouglas Gilbert my_name, key, asc, asq); 9778dea0d02SFUJITA Tomonori } 9781da177e4SLinus Torvalds 979fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 98022017ed2SDouglas Gilbert { 98122017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 98222017ed2SDouglas Gilbert } 98322017ed2SDouglas Gilbert 9846f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 9856f4e626fSNathan Chancellor void __user *arg) 9861da177e4SLinus Torvalds { 987773642d9SDouglas Gilbert if (sdebug_verbose) { 988cbf67842SDouglas Gilbert if (0x1261 == cmd) 989cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 990cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 991cbf67842SDouglas Gilbert else if (0x5331 == cmd) 992cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 993cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 994cbf67842SDouglas Gilbert __func__); 995cbf67842SDouglas Gilbert else 996cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 997cbf67842SDouglas Gilbert __func__, cmd); 9981da177e4SLinus Torvalds } 9991da177e4SLinus Torvalds return -EINVAL; 10001da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 10011da177e4SLinus Torvalds } 10021da177e4SLinus Torvalds 10039b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 10049b760fd8SDouglas Gilbert { 10059b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 10069b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 10079b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10089b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10099b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10109b760fd8SDouglas Gilbert break; 10119b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 10129b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10139b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10149b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10159b760fd8SDouglas Gilbert break; 10169b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 10179b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10189b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10199b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10209b760fd8SDouglas Gilbert break; 10219b760fd8SDouglas Gilbert case 16: 10229b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10239b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10249b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10259b760fd8SDouglas Gilbert break; 10269b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 10279b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 10289b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 10299b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 10309b760fd8SDouglas Gilbert break; 10319b760fd8SDouglas Gilbert default: 10329b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 10339b760fd8SDouglas Gilbert sdebug_cdb_len); 10349b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 10359b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 10369b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 10379b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 10389b760fd8SDouglas Gilbert break; 10399b760fd8SDouglas Gilbert } 10409b760fd8SDouglas Gilbert } 10419b760fd8SDouglas Gilbert 10429b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 10439b760fd8SDouglas Gilbert { 10449b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 10459b760fd8SDouglas Gilbert struct Scsi_Host *shost; 10469b760fd8SDouglas Gilbert struct scsi_device *sdev; 10479b760fd8SDouglas Gilbert 10489b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 10499b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 10509b760fd8SDouglas Gilbert shost = sdbg_host->shost; 10519b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 10529b760fd8SDouglas Gilbert config_cdb_len(sdev); 10539b760fd8SDouglas Gilbert } 10549b760fd8SDouglas Gilbert } 10559b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 10569b760fd8SDouglas Gilbert } 10579b760fd8SDouglas Gilbert 105819c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 105919c8ead7SEwan D. Milne { 106019c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 106119c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 106219c8ead7SEwan D. Milne 106319c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 106419c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 106519c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 106619c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 106719c8ead7SEwan D. Milne (devip->target == dp->target)) 106819c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 106919c8ead7SEwan D. Milne } 107019c8ead7SEwan D. Milne } 107119c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 107219c8ead7SEwan D. Milne } 107319c8ead7SEwan D. Milne 1074f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 10751da177e4SLinus Torvalds { 1076cbf67842SDouglas Gilbert int k; 1077cbf67842SDouglas Gilbert 1078cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 1079cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 1080cbf67842SDouglas Gilbert const char *cp = NULL; 1081cbf67842SDouglas Gilbert 1082cbf67842SDouglas Gilbert switch (k) { 1083cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 1084f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1085f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 1086773642d9SDouglas Gilbert if (sdebug_verbose) 1087cbf67842SDouglas Gilbert cp = "power on reset"; 1088cbf67842SDouglas Gilbert break; 1089cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 1090f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1091f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1092773642d9SDouglas Gilbert if (sdebug_verbose) 1093cbf67842SDouglas Gilbert cp = "bus reset"; 1094cbf67842SDouglas Gilbert break; 1095cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1096f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1097f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1098773642d9SDouglas Gilbert if (sdebug_verbose) 1099cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1100cbf67842SDouglas Gilbert break; 11010d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1102f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1103f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1104773642d9SDouglas Gilbert if (sdebug_verbose) 11050d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1106f49accf1SEwan D. Milne break; 1107acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1108f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1109b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1110b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1111773642d9SDouglas Gilbert if (sdebug_verbose) 1112acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1113acafd0b9SEwan D. Milne break; 1114acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1115f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1116acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1117acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1118773642d9SDouglas Gilbert if (sdebug_verbose) 1119acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1120acafd0b9SEwan D. Milne break; 112119c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 112219c8ead7SEwan D. Milne /* 112319c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 112419c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 112519c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 112619c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1127773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 112819c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 112919c8ead7SEwan D. Milne */ 1130773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 113119c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1132f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 113319c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 113419c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1135773642d9SDouglas Gilbert if (sdebug_verbose) 113619c8ead7SEwan D. Milne cp = "reported luns data has changed"; 113719c8ead7SEwan D. Milne break; 1138cbf67842SDouglas Gilbert default: 1139773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1140773642d9SDouglas Gilbert if (sdebug_verbose) 1141cbf67842SDouglas Gilbert cp = "unknown"; 1142cbf67842SDouglas Gilbert break; 1143cbf67842SDouglas Gilbert } 1144cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1145773642d9SDouglas Gilbert if (sdebug_verbose) 1146f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1147cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1148cbf67842SDouglas Gilbert my_name, cp); 11491da177e4SLinus Torvalds return check_condition_result; 11501da177e4SLinus Torvalds } 11511da177e4SLinus Torvalds return 0; 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 1154fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 11551da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 11561da177e4SLinus Torvalds int arr_len) 11571da177e4SLinus Torvalds { 115821a61829SFUJITA Tomonori int act_len; 1159ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 11601da177e4SLinus Torvalds 1161072d0bb3SFUJITA Tomonori if (!sdb->length) 11621da177e4SLinus Torvalds return 0; 1163ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1164773642d9SDouglas Gilbert return DID_ERROR << 16; 116521a61829SFUJITA Tomonori 116621a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 116721a61829SFUJITA Tomonori arr, arr_len); 116842d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 116921a61829SFUJITA Tomonori 11701da177e4SLinus Torvalds return 0; 11711da177e4SLinus Torvalds } 11721da177e4SLinus Torvalds 1173fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1174fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1175fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1176fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1177fb0cc8d1SDouglas Gilbert */ 1178fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1179fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1180fb0cc8d1SDouglas Gilbert { 11819237f04eSDamien Le Moal unsigned int act_len, n; 1182ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1183fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1184fb0cc8d1SDouglas Gilbert 1185fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1186fb0cc8d1SDouglas Gilbert return 0; 1187ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1188fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1189fb0cc8d1SDouglas Gilbert 1190fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1191fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1192fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 119342d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 119442d387beSBart Van Assche scsi_get_resid(scp)); 11959237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 119636e07d7eSGeorge Kennedy scsi_set_resid(scp, min_t(u32, scsi_get_resid(scp), n)); 1197fb0cc8d1SDouglas Gilbert return 0; 1198fb0cc8d1SDouglas Gilbert } 1199fb0cc8d1SDouglas Gilbert 1200fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1201fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1202fb0cc8d1SDouglas Gilbert */ 12031da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 120421a61829SFUJITA Tomonori int arr_len) 12051da177e4SLinus Torvalds { 120621a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 12071da177e4SLinus Torvalds return 0; 1208ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 12091da177e4SLinus Torvalds return -1; 121021a61829SFUJITA Tomonori 121121a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds 1215e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1216e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 12179b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 12181b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 12191b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 12201b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 12211b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 12221da177e4SLinus Torvalds 1223cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1224760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 12255a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 122609ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1227bf476433SChristoph Hellwig const uuid_t *lu_name) 12281da177e4SLinus Torvalds { 1229c65b1445SDouglas Gilbert int num, port_a; 1230c65b1445SDouglas Gilbert char b[32]; 12311da177e4SLinus Torvalds 1232c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 12331da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 12341da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 12351da177e4SLinus Torvalds arr[1] = 0x1; 12361da177e4SLinus Torvalds arr[2] = 0x0; 1237e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1238e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 12391da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 12401da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 12411da177e4SLinus Torvalds arr[3] = num; 12421da177e4SLinus Torvalds num += 4; 1243c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 124409ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 124509ba24c1SDouglas Gilbert /* Locally assigned UUID */ 124609ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 124709ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 124809ba24c1SDouglas Gilbert arr[num++] = 0x0; 124909ba24c1SDouglas Gilbert arr[num++] = 0x12; 125009ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 125109ba24c1SDouglas Gilbert arr[num++] = 0x0; 125209ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 125309ba24c1SDouglas Gilbert num += 16; 125409ba24c1SDouglas Gilbert } else { 12551b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1256c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1257c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1258c65b1445SDouglas Gilbert arr[num++] = 0x0; 1259c65b1445SDouglas Gilbert arr[num++] = 0x8; 12601b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1261773642d9SDouglas Gilbert num += 8; 126209ba24c1SDouglas Gilbert } 1263c65b1445SDouglas Gilbert /* Target relative port number */ 1264c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1265c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1266c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1267c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1268c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1269c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1270c65b1445SDouglas Gilbert arr[num++] = 0x0; 1271c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1272c65b1445SDouglas Gilbert } 12731b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1274c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1275c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1276c65b1445SDouglas Gilbert arr[num++] = 0x0; 1277c65b1445SDouglas Gilbert arr[num++] = 0x8; 12781b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1279773642d9SDouglas Gilbert num += 8; 12801b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 12815a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 12825a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 12835a09e398SHannes Reinecke arr[num++] = 0x0; 12845a09e398SHannes Reinecke arr[num++] = 0x4; 12855a09e398SHannes Reinecke arr[num++] = 0; 12865a09e398SHannes Reinecke arr[num++] = 0; 1287773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1288773642d9SDouglas Gilbert num += 2; 12891b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1290c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1291c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1292c65b1445SDouglas Gilbert arr[num++] = 0x0; 1293c65b1445SDouglas Gilbert arr[num++] = 0x8; 12941b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1295773642d9SDouglas Gilbert num += 8; 1296c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1297c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1298c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1299c65b1445SDouglas Gilbert arr[num++] = 0x0; 1300c65b1445SDouglas Gilbert arr[num++] = 24; 13011b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1302c65b1445SDouglas Gilbert num += 12; 1303c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1304c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1305c65b1445SDouglas Gilbert num += 8; 1306c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1307c65b1445SDouglas Gilbert num += 4; 1308c65b1445SDouglas Gilbert return num; 1309c65b1445SDouglas Gilbert } 1310c65b1445SDouglas Gilbert 1311c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1312c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1313c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1314c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1315c65b1445SDouglas Gilbert }; 1316c65b1445SDouglas Gilbert 1317cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1318760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1319c65b1445SDouglas Gilbert { 1320c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1321c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1322c65b1445SDouglas Gilbert } 1323c65b1445SDouglas Gilbert 1324cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1325760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1326c65b1445SDouglas Gilbert { 1327c65b1445SDouglas Gilbert int num = 0; 1328c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1329c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1330c65b1445SDouglas Gilbert int plen, olen; 1331c65b1445SDouglas Gilbert 1332c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1333c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1334c65b1445SDouglas Gilbert arr[num++] = 0x0; 1335c65b1445SDouglas Gilbert olen = strlen(na1); 1336c65b1445SDouglas Gilbert plen = olen + 1; 1337c65b1445SDouglas Gilbert if (plen % 4) 1338c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1339c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1340c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1341c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1342c65b1445SDouglas Gilbert num += plen; 1343c65b1445SDouglas Gilbert 1344c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1345c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1346c65b1445SDouglas Gilbert arr[num++] = 0x0; 1347c65b1445SDouglas Gilbert olen = strlen(na2); 1348c65b1445SDouglas Gilbert plen = olen + 1; 1349c65b1445SDouglas Gilbert if (plen % 4) 1350c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1351c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1352c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1353c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1354c65b1445SDouglas Gilbert num += plen; 1355c65b1445SDouglas Gilbert 1356c65b1445SDouglas Gilbert return num; 1357c65b1445SDouglas Gilbert } 1358c65b1445SDouglas Gilbert 1359c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1360760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1361c65b1445SDouglas Gilbert { 1362c65b1445SDouglas Gilbert int num = 0; 1363c65b1445SDouglas Gilbert int port_a, port_b; 1364c65b1445SDouglas Gilbert 1365c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1366c65b1445SDouglas Gilbert port_b = port_a + 1; 1367c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1368c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1369c65b1445SDouglas Gilbert arr[num++] = 0x0; 1370c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1371c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1372c65b1445SDouglas Gilbert num += 6; 1373c65b1445SDouglas Gilbert arr[num++] = 0x0; 1374c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1375c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1376c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1377c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1378c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1379c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13801b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1381773642d9SDouglas Gilbert num += 8; 1382c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1383c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1384c65b1445SDouglas Gilbert arr[num++] = 0x0; 1385c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 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 (B) */ 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_b, arr + num); 1396773642d9SDouglas Gilbert num += 8; 1397c65b1445SDouglas Gilbert 1398c65b1445SDouglas Gilbert return num; 1399c65b1445SDouglas Gilbert } 1400c65b1445SDouglas Gilbert 1401c65b1445SDouglas Gilbert 1402c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1403c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1404c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1405c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1406c65b1445SDouglas Gilbert '1','2','3','4', 1407c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1408c65b1445SDouglas Gilbert 0xec,0,0,0, 1409c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1410c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1411c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1412c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1413c65b1445SDouglas Gilbert 0x53,0x41, 1414c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1415c65b1445SDouglas Gilbert 0x20,0x20, 1416c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1417c65b1445SDouglas Gilbert 0x10,0x80, 1418c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1419c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1420c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1421c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1422c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1423c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1424c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1425c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1426c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1427c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1428c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1429c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1430c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1431c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1432c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1433c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1434c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1435c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1436c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1437c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1438c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1439c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1444c65b1445SDouglas Gilbert }; 1445c65b1445SDouglas Gilbert 1446cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1447760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1448c65b1445SDouglas Gilbert { 1449c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1450c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1451c65b1445SDouglas Gilbert } 1452c65b1445SDouglas Gilbert 1453c65b1445SDouglas Gilbert 1454c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 14551e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 14561e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14571e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 14581e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1459c65b1445SDouglas Gilbert }; 1460c65b1445SDouglas Gilbert 1461cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1462760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1463c65b1445SDouglas Gilbert { 1464ea61fca5SMartin K. Petersen unsigned int gran; 1465ea61fca5SMartin K. Petersen 1466c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1467e308b3d1SMartin K. Petersen 1468e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 146986e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 147086e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 147186e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 147286e6828aSLukas Herbolt else 1473773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1474773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1475e308b3d1SMartin K. Petersen 1476e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1477773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1478773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 147944d92694SMartin K. Petersen 1480e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1481773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1482e308b3d1SMartin K. Petersen 1483773642d9SDouglas Gilbert if (sdebug_lbpu) { 1484e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1485773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1486e308b3d1SMartin K. Petersen 1487e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1488773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 148944d92694SMartin K. Petersen } 149044d92694SMartin K. Petersen 1491e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1492773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1493773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 149444d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 149544d92694SMartin K. Petersen } 149644d92694SMartin K. Petersen 1497e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1498773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 14996014759cSMartin K. Petersen 15005b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1501773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 15025b94e232SMartin K. Petersen 15035b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 150444d92694SMartin K. Petersen 1505c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 15061da177e4SLinus Torvalds } 15071da177e4SLinus Torvalds 15081e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 150964e14eceSDamien Le Moal static int inquiry_vpd_b1(struct sdebug_dev_info *devip, unsigned char *arr) 1510eac6e8e4SMatthew Wilcox { 1511eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1512eac6e8e4SMatthew Wilcox arr[0] = 0; 15131e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 15141e49f785SDouglas Gilbert arr[2] = 0; 15151e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 151664e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 151764e14eceSDamien Le Moal arr[4] = 1 << 4; /* zoned field = 01b */ 1518eac6e8e4SMatthew Wilcox 1519eac6e8e4SMatthew Wilcox return 0x3c; 1520eac6e8e4SMatthew Wilcox } 15211da177e4SLinus Torvalds 1522760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1523760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 15246014759cSMartin K. Petersen { 15253f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 15266014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1527773642d9SDouglas Gilbert if (sdebug_lbpu) 15286014759cSMartin K. Petersen arr[1] = 1 << 7; 1529773642d9SDouglas Gilbert if (sdebug_lbpws) 15306014759cSMartin K. Petersen arr[1] |= 1 << 6; 1531773642d9SDouglas Gilbert if (sdebug_lbpws10) 15325b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1533760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1534760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1535760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1536760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1537760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 15383f0bc3b3SMartin K. Petersen return 0x4; 15396014759cSMartin K. Petersen } 15406014759cSMartin K. Petersen 1541d36da305SDouglas Gilbert /* Zoned block device characteristics VPD page (ZBC mandatory) */ 1542f0d1cf93SDouglas Gilbert static int inquiry_vpd_b6(struct sdebug_dev_info *devip, unsigned char *arr) 1543d36da305SDouglas Gilbert { 1544d36da305SDouglas Gilbert memset(arr, 0, 0x3c); 1545d36da305SDouglas Gilbert arr[0] = 0x1; /* set URSWRZ (unrestricted read in seq. wr req zone) */ 1546d36da305SDouglas Gilbert /* 1547d36da305SDouglas Gilbert * Set Optimal number of open sequential write preferred zones and 1548d36da305SDouglas Gilbert * Optimal number of non-sequentially written sequential write 1549f0d1cf93SDouglas Gilbert * preferred zones fields to 'not reported' (0xffffffff). Leave other 1550f0d1cf93SDouglas Gilbert * fields set to zero, apart from Max. number of open swrz_s field. 1551d36da305SDouglas Gilbert */ 1552d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[4]); 1553d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[8]); 155464e14eceSDamien Le Moal if (sdeb_zbc_model == BLK_ZONED_HM && devip->max_open) 1555f0d1cf93SDouglas Gilbert put_unaligned_be32(devip->max_open, &arr[12]); 1556f0d1cf93SDouglas Gilbert else 1557d36da305SDouglas Gilbert put_unaligned_be32(0xffffffff, &arr[12]); 1558d36da305SDouglas Gilbert return 0x3c; 1559d36da305SDouglas Gilbert } 1560d36da305SDouglas Gilbert 15611da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1562c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 15631da177e4SLinus Torvalds 1564c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 15651da177e4SLinus Torvalds { 15661da177e4SLinus Torvalds unsigned char pq_pdt; 15675a09e398SHannes Reinecke unsigned char *arr; 156801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 156936e07d7eSGeorge Kennedy u32 alloc_len, n; 157036e07d7eSGeorge Kennedy int ret; 1571d36da305SDouglas Gilbert bool have_wlun, is_disk, is_zbc, is_disk_zbc; 15721da177e4SLinus Torvalds 1573773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 15746f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 15756f3cbf55SDouglas Gilbert if (! arr) 15766f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1577760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 157864e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 1579d36da305SDouglas Gilbert is_disk_zbc = (is_disk || is_zbc); 1580b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1581c2248fc9SDouglas Gilbert if (have_wlun) 1582b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1583b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1584b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1585c65b1445SDouglas Gilbert else 1586773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 15871da177e4SLinus Torvalds arr[0] = pq_pdt; 15881da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 158922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 15905a09e398SHannes Reinecke kfree(arr); 15911da177e4SLinus Torvalds return check_condition_result; 15921da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 159336e07d7eSGeorge Kennedy int lu_id_num, port_group_id, target_dev_id; 159436e07d7eSGeorge Kennedy u32 len; 1595c65b1445SDouglas Gilbert char lu_id_str[6]; 1596c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 15971da177e4SLinus Torvalds 15985a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 15995a09e398SHannes Reinecke (devip->channel & 0x7f); 1600b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 160123183910SDouglas Gilbert host_no = 0; 1602c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1603c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1604c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1605c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1606c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 16071da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1608c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1609c65b1445SDouglas Gilbert n = 4; 1610c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1611c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1612c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1613c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1614c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1615c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1616c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1617c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1618d36da305SDouglas Gilbert if (is_disk_zbc) { /* SBC or ZBC */ 1619c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1620760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1621760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1622d36da305SDouglas Gilbert if (is_disk) 1623d36da305SDouglas Gilbert arr[n++] = 0xb2; /* LB Provisioning */ 162464e14eceSDamien Le Moal if (is_zbc) 1625d36da305SDouglas Gilbert arr[n++] = 0xb6; /* ZB dev. char. */ 1626760f3b03SDouglas Gilbert } 1627c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 16281da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1629c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 16301da177e4SLinus Torvalds arr[3] = len; 1631c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 16321da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1633c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1634760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 16355a09e398SHannes Reinecke target_dev_id, lu_id_num, 163609ba24c1SDouglas Gilbert lu_id_str, len, 163709ba24c1SDouglas Gilbert &devip->lu_name); 1638c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1639c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1640760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1641c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1642c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1643760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1644c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1645c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1646c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 16478475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1648c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1649760f3b03SDouglas Gilbert else if (have_dif_prot) 1650c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1651c6a44287SMartin K. Petersen else 1652c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1653c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1654c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1655c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1656c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1657c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1658c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1659c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1660c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1661c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1662c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1663760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1664d36da305SDouglas Gilbert } else if (is_disk_zbc && 0x89 == cmd[2]) { /* ATA info */ 1665c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1666760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1667773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1668d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb0 == cmd[2]) { /* Block limits */ 1669c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1670760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1671d36da305SDouglas Gilbert } else if (is_disk_zbc && 0xb1 == cmd[2]) { /* Block char. */ 1672eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 167364e14eceSDamien Le Moal arr[3] = inquiry_vpd_b1(devip, &arr[4]); 1674760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 16756014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1676760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 1677d36da305SDouglas Gilbert } else if (is_zbc && cmd[2] == 0xb6) { /* ZB dev. charact. */ 1678d36da305SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1679f0d1cf93SDouglas Gilbert arr[3] = inquiry_vpd_b6(devip, &arr[4]); 16801da177e4SLinus Torvalds } else { 168122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 16825a09e398SHannes Reinecke kfree(arr); 16831da177e4SLinus Torvalds return check_condition_result; 16841da177e4SLinus Torvalds } 168536e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 16865a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 168736e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 16885a09e398SHannes Reinecke kfree(arr); 16895a09e398SHannes Reinecke return ret; 16901da177e4SLinus Torvalds } 16911da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1692773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1693773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 16941da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 16951da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1696f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1697b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 169870bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1699c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 17001da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1701c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1702e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1703e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1704e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 17059b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 17069b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 17071da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1708760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1709760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1710c65b1445SDouglas Gilbert n = 62; 1711760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1712760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1713760f3b03SDouglas Gilbert n += 2; 1714760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1715760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1716760f3b03SDouglas Gilbert n += 2; 1717d36da305SDouglas Gilbert } else if (is_zbc) { /* ZBC BSR INCITS 536 revision 05 */ 1718d36da305SDouglas Gilbert put_unaligned_be16(0x624, arr + n); 1719d36da305SDouglas Gilbert n += 2; 17201da177e4SLinus Torvalds } 1721760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 17225a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 172336e07d7eSGeorge Kennedy min_t(u32, alloc_len, SDEBUG_LONG_INQ_SZ)); 17245a09e398SHannes Reinecke kfree(arr); 17255a09e398SHannes Reinecke return ret; 17261da177e4SLinus Torvalds } 17271da177e4SLinus Torvalds 172884905d34SDouglas Gilbert /* See resp_iec_m_pg() for how this data is manipulated */ 1729fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1730fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1731fd32119bSDouglas Gilbert 17321da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 17331da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17341da177e4SLinus Torvalds { 173501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 173684905d34SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; /* assume >= 18 bytes */ 173784905d34SDouglas Gilbert bool dsense = !!(cmd[1] & 1); 173836e07d7eSGeorge Kennedy u32 alloc_len = cmd[4]; 173936e07d7eSGeorge Kennedy u32 len = 18; 174084905d34SDouglas Gilbert int stopped_state = atomic_read(&devip->stopped); 17411da177e4SLinus Torvalds 1742c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 174384905d34SDouglas Gilbert if (stopped_state > 0) { /* some "pollable" data [spc6r02: 5.12.2] */ 174484905d34SDouglas Gilbert if (dsense) { 174584905d34SDouglas Gilbert arr[0] = 0x72; 174684905d34SDouglas Gilbert arr[1] = NOT_READY; 174784905d34SDouglas Gilbert arr[2] = LOGICAL_UNIT_NOT_READY; 174884905d34SDouglas Gilbert arr[3] = (stopped_state == 2) ? 0x1 : 0x2; 174984905d34SDouglas Gilbert len = 8; 175084905d34SDouglas Gilbert } else { 175184905d34SDouglas Gilbert arr[0] = 0x70; 175284905d34SDouglas Gilbert arr[2] = NOT_READY; /* NO_SENSE in sense_key */ 175384905d34SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 175484905d34SDouglas Gilbert arr[12] = LOGICAL_UNIT_NOT_READY; 175584905d34SDouglas Gilbert arr[13] = (stopped_state == 2) ? 0x1 : 0x2; 175684905d34SDouglas Gilbert } 175784905d34SDouglas Gilbert } else if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 175884905d34SDouglas Gilbert /* Information exceptions control mode page: TEST=1, MRIE=6 */ 1759c2248fc9SDouglas Gilbert if (dsense) { 1760c65b1445SDouglas Gilbert arr[0] = 0x72; 1761c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1762c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 176384905d34SDouglas Gilbert arr[3] = 0xff; /* Failure prediction(false) */ 1764c2248fc9SDouglas Gilbert len = 8; 1765c65b1445SDouglas Gilbert } else { 1766c65b1445SDouglas Gilbert arr[0] = 0x70; 1767c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1768c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1769c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 177084905d34SDouglas Gilbert arr[13] = 0xff; /* Failure prediction(false) */ 1771c65b1445SDouglas Gilbert } 177284905d34SDouglas Gilbert } else { /* nothing to report */ 1773c2248fc9SDouglas Gilbert if (dsense) { 1774c2248fc9SDouglas Gilbert len = 8; 177584905d34SDouglas Gilbert memset(arr, 0, len); 177684905d34SDouglas Gilbert arr[0] = 0x72; 1777c2248fc9SDouglas Gilbert } else { 177884905d34SDouglas Gilbert memset(arr, 0, len); 1779c2248fc9SDouglas Gilbert arr[0] = 0x70; 1780c2248fc9SDouglas Gilbert arr[7] = 0xa; 1781c2248fc9SDouglas Gilbert } 1782c65b1445SDouglas Gilbert } 178336e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, len, alloc_len)); 17841da177e4SLinus Torvalds } 17851da177e4SLinus Torvalds 1786fc13638aSDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 1787c65b1445SDouglas Gilbert { 178801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1789fc13638aSDouglas Gilbert int power_cond, want_stop, stopped_state; 17904f2c8bf6SDouglas Gilbert bool changing; 1791c65b1445SDouglas Gilbert 1792c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1793c65b1445SDouglas Gilbert if (power_cond) { 179422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1795c65b1445SDouglas Gilbert return check_condition_result; 1796c65b1445SDouglas Gilbert } 1797fc13638aSDouglas Gilbert want_stop = !(cmd[4] & 1); 1798fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 1799fc13638aSDouglas Gilbert if (stopped_state == 2) { 1800fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 1801fc13638aSDouglas Gilbert 1802fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 1803fc13638aSDouglas Gilbert u64 diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 1804fc13638aSDouglas Gilbert 1805fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 1806fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 1807fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 1808fc13638aSDouglas Gilbert stopped_state = 0; 1809fc13638aSDouglas Gilbert } 1810fc13638aSDouglas Gilbert } 1811fc13638aSDouglas Gilbert if (stopped_state == 2) { 1812fc13638aSDouglas Gilbert if (want_stop) { 1813fc13638aSDouglas Gilbert stopped_state = 1; /* dummy up success */ 1814fc13638aSDouglas Gilbert } else { /* Disallow tur_ms_to_ready delay to be overridden */ 1815fc13638aSDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 0 /* START bit */); 1816fc13638aSDouglas Gilbert return check_condition_result; 1817fc13638aSDouglas Gilbert } 1818fc13638aSDouglas Gilbert } 1819fc13638aSDouglas Gilbert } 1820fc13638aSDouglas Gilbert changing = (stopped_state != want_stop); 1821fc13638aSDouglas Gilbert if (changing) 1822fc13638aSDouglas Gilbert atomic_xchg(&devip->stopped, want_stop); 1823fc13638aSDouglas Gilbert if (!changing || (cmd[1] & 0x1)) /* state unchanged or IMMED bit set in cdb */ 18244f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 18254f2c8bf6SDouglas Gilbert else 18264f2c8bf6SDouglas Gilbert return 0; 1827c65b1445SDouglas Gilbert } 1828c65b1445SDouglas Gilbert 182928898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 183028898873SFUJITA Tomonori { 1831773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1832773642d9SDouglas Gilbert 1833773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1834773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1835773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 183628898873SFUJITA Tomonori else 183728898873SFUJITA Tomonori return sdebug_store_sectors; 183828898873SFUJITA Tomonori } 183928898873SFUJITA Tomonori 18401da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 18411da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 18421da177e4SLinus Torvalds struct sdebug_dev_info *devip) 18431da177e4SLinus Torvalds { 18441da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1845c65b1445SDouglas Gilbert unsigned int capac; 18461da177e4SLinus Torvalds 1847c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 184828898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 18491da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1850c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1851c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1852773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1853773642d9SDouglas Gilbert } else 1854773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1855773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 18561da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 18571da177e4SLinus Torvalds } 18581da177e4SLinus Torvalds 1859c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1860c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1861c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1862c65b1445SDouglas Gilbert { 186301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1864c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 18654e3ace00SYe Bin u32 alloc_len; 1866c65b1445SDouglas Gilbert 1867773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1868c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 186928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1870c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1871773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1872773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1873773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1874773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 187544d92694SMartin K. Petersen 1876be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 18775b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1878760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1879760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1880760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1881760f3b03SDouglas Gilbert */ 1882760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1883760f3b03SDouglas Gilbert arr[14] |= 0x40; 1884be1dd78dSEric Sandeen } 188544d92694SMartin K. Petersen 1886773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1887c6a44287SMartin K. Petersen 1888760f3b03SDouglas Gilbert if (have_dif_prot) { 1889773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1890c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1891c6a44287SMartin K. Petersen } 1892c6a44287SMartin K. Petersen 1893c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 18944e3ace00SYe Bin min_t(u32, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1895c65b1445SDouglas Gilbert } 1896c65b1445SDouglas Gilbert 18975a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 18985a09e398SHannes Reinecke 18995a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 19005a09e398SHannes Reinecke struct sdebug_dev_info *devip) 19015a09e398SHannes Reinecke { 190201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19035a09e398SHannes Reinecke unsigned char *arr; 19045a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 19055a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 1906f347c268SYe Bin u32 alen, n, rlen; 1907f347c268SYe Bin int ret; 19085a09e398SHannes Reinecke 1909773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 19106f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 19116f3cbf55SDouglas Gilbert if (! arr) 19126f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 19135a09e398SHannes Reinecke /* 19145a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 19155a09e398SHannes Reinecke * real and a fake port with no device connected. 19165a09e398SHannes Reinecke * So we create two port groups with one port each 19175a09e398SHannes Reinecke * and set the group with port B to unavailable. 19185a09e398SHannes Reinecke */ 19195a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 19205a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 19215a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 19225a09e398SHannes Reinecke (devip->channel & 0x7f); 19235a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 19245a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 19255a09e398SHannes Reinecke 19265a09e398SHannes Reinecke /* 19275a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 19285a09e398SHannes Reinecke */ 19295a09e398SHannes Reinecke n = 4; 1930b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 19315a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 19325a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 19335a09e398SHannes Reinecke } else { 19345a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1935773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 19365a09e398SHannes Reinecke } 1937773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1938773642d9SDouglas Gilbert n += 2; 19395a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19405a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19415a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19425a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19435a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19445a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1945773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1946773642d9SDouglas Gilbert n += 2; 19475a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 19485a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1949773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1950773642d9SDouglas Gilbert n += 2; 19515a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19525a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 19535a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 19545a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 19555a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 19565a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1957773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1958773642d9SDouglas Gilbert n += 2; 19595a09e398SHannes Reinecke 19605a09e398SHannes Reinecke rlen = n - 4; 1961773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 19625a09e398SHannes Reinecke 19635a09e398SHannes Reinecke /* 19645a09e398SHannes Reinecke * Return the smallest value of either 19655a09e398SHannes Reinecke * - The allocated length 19665a09e398SHannes Reinecke * - The constructed command length 19675a09e398SHannes Reinecke * - The maximum array size 19685a09e398SHannes Reinecke */ 1969f347c268SYe Bin rlen = min(alen, n); 19705a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1971f347c268SYe Bin min_t(u32, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 19725a09e398SHannes Reinecke kfree(arr); 19735a09e398SHannes Reinecke return ret; 19745a09e398SHannes Reinecke } 19755a09e398SHannes Reinecke 1976fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1977fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 197838d5c833SDouglas Gilbert { 197938d5c833SDouglas Gilbert bool rctd; 198038d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 198138d5c833SDouglas Gilbert u16 req_sa, u; 198238d5c833SDouglas Gilbert u32 alloc_len, a_len; 198338d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 198438d5c833SDouglas Gilbert const struct opcode_info_t *oip; 198538d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 198638d5c833SDouglas Gilbert u8 *arr; 198738d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 198838d5c833SDouglas Gilbert 198938d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 199038d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 199138d5c833SDouglas Gilbert req_opcode = cmd[3]; 199238d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 199338d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 19946d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 199538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 199638d5c833SDouglas Gilbert return check_condition_result; 199738d5c833SDouglas Gilbert } 199838d5c833SDouglas Gilbert if (alloc_len > 8192) 199938d5c833SDouglas Gilbert a_len = 8192; 200038d5c833SDouglas Gilbert else 200138d5c833SDouglas Gilbert a_len = alloc_len; 200299531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 200338d5c833SDouglas Gilbert if (NULL == arr) { 200438d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 200538d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 200638d5c833SDouglas Gilbert return check_condition_result; 200738d5c833SDouglas Gilbert } 200838d5c833SDouglas Gilbert switch (reporting_opts) { 200938d5c833SDouglas Gilbert case 0: /* all commands */ 201038d5c833SDouglas Gilbert /* count number of commands */ 201138d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 201238d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 201338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 201438d5c833SDouglas Gilbert continue; 201538d5c833SDouglas Gilbert count += (oip->num_attached + 1); 201638d5c833SDouglas Gilbert } 201738d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 201838d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 201938d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 202038d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 202138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 202238d5c833SDouglas Gilbert continue; 202338d5c833SDouglas Gilbert na = oip->num_attached; 202438d5c833SDouglas Gilbert arr[offset] = oip->opcode; 202538d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 202638d5c833SDouglas Gilbert if (rctd) 202738d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 202838d5c833SDouglas Gilbert if (FF_SA & oip->flags) 202938d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 203038d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 203138d5c833SDouglas Gilbert if (rctd) 203238d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 203338d5c833SDouglas Gilbert r_oip = oip; 203438d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 203538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 203638d5c833SDouglas Gilbert continue; 203738d5c833SDouglas Gilbert offset += bump; 203838d5c833SDouglas Gilbert arr[offset] = oip->opcode; 203938d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 204038d5c833SDouglas Gilbert if (rctd) 204138d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 204238d5c833SDouglas Gilbert if (FF_SA & oip->flags) 204338d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 204438d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 204538d5c833SDouglas Gilbert arr + offset + 6); 204638d5c833SDouglas Gilbert if (rctd) 204738d5c833SDouglas Gilbert put_unaligned_be16(0xa, 204838d5c833SDouglas Gilbert arr + offset + 8); 204938d5c833SDouglas Gilbert } 205038d5c833SDouglas Gilbert oip = r_oip; 205138d5c833SDouglas Gilbert offset += bump; 205238d5c833SDouglas Gilbert } 205338d5c833SDouglas Gilbert break; 205438d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 205538d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 205638d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 205738d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 205838d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 205938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 206038d5c833SDouglas Gilbert supp = 1; 206138d5c833SDouglas Gilbert offset = 4; 206238d5c833SDouglas Gilbert } else { 206338d5c833SDouglas Gilbert if (1 == reporting_opts) { 206438d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 206538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 206638d5c833SDouglas Gilbert 2, 2); 206738d5c833SDouglas Gilbert kfree(arr); 206838d5c833SDouglas Gilbert return check_condition_result; 206938d5c833SDouglas Gilbert } 207038d5c833SDouglas Gilbert req_sa = 0; 207138d5c833SDouglas Gilbert } else if (2 == reporting_opts && 207238d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 207338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 207438d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 207538d5c833SDouglas Gilbert return check_condition_result; 207638d5c833SDouglas Gilbert } 207738d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 207838d5c833SDouglas Gilbert req_opcode == oip->opcode) 207938d5c833SDouglas Gilbert supp = 3; 208038d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 208138d5c833SDouglas Gilbert na = oip->num_attached; 208238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 208338d5c833SDouglas Gilbert ++k, ++oip) { 208438d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 208538d5c833SDouglas Gilbert break; 208638d5c833SDouglas Gilbert } 208738d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 208838d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 208938d5c833SDouglas Gilbert na = oip->num_attached; 209038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 209138d5c833SDouglas Gilbert ++k, ++oip) { 209238d5c833SDouglas Gilbert if (req_sa == oip->sa) 209338d5c833SDouglas Gilbert break; 209438d5c833SDouglas Gilbert } 209538d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 209638d5c833SDouglas Gilbert } else 209738d5c833SDouglas Gilbert supp = 3; 209838d5c833SDouglas Gilbert if (3 == supp) { 209938d5c833SDouglas Gilbert u = oip->len_mask[0]; 210038d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 210138d5c833SDouglas Gilbert arr[4] = oip->opcode; 210238d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 210338d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 210438d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 210538d5c833SDouglas Gilbert offset = 4 + u; 210638d5c833SDouglas Gilbert } else 210738d5c833SDouglas Gilbert offset = 4; 210838d5c833SDouglas Gilbert } 210938d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 211038d5c833SDouglas Gilbert if (rctd) { 211138d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 211238d5c833SDouglas Gilbert offset += 12; 211338d5c833SDouglas Gilbert } 211438d5c833SDouglas Gilbert break; 211538d5c833SDouglas Gilbert default: 211638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 211738d5c833SDouglas Gilbert kfree(arr); 211838d5c833SDouglas Gilbert return check_condition_result; 211938d5c833SDouglas Gilbert } 212038d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 212138d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 212238d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 212338d5c833SDouglas Gilbert kfree(arr); 212438d5c833SDouglas Gilbert return errsts; 212538d5c833SDouglas Gilbert } 212638d5c833SDouglas Gilbert 2127fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 2128fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 212938d5c833SDouglas Gilbert { 213038d5c833SDouglas Gilbert bool repd; 213138d5c833SDouglas Gilbert u32 alloc_len, len; 213238d5c833SDouglas Gilbert u8 arr[16]; 213338d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 213438d5c833SDouglas Gilbert 213538d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 213638d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 213738d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 213838d5c833SDouglas Gilbert if (alloc_len < 4) { 213938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 214038d5c833SDouglas Gilbert return check_condition_result; 214138d5c833SDouglas Gilbert } 214238d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 214338d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 214438d5c833SDouglas Gilbert if (repd) { 214538d5c833SDouglas Gilbert arr[3] = 0xc; 214638d5c833SDouglas Gilbert len = 16; 214738d5c833SDouglas Gilbert } else 214838d5c833SDouglas Gilbert len = 4; 214938d5c833SDouglas Gilbert 215038d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 215138d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 215238d5c833SDouglas Gilbert } 215338d5c833SDouglas Gilbert 21541da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 21551da177e4SLinus Torvalds 21561da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 21571da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 21581da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 21591da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 21601da177e4SLinus Torvalds 21611da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 21621da177e4SLinus Torvalds if (1 == pcontrol) 21631da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 21641da177e4SLinus Torvalds return sizeof(err_recov_pg); 21651da177e4SLinus Torvalds } 21661da177e4SLinus Torvalds 21671da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 21681da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 21691da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 21701da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 21711da177e4SLinus Torvalds 21721da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 21731da177e4SLinus Torvalds if (1 == pcontrol) 21741da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 21751da177e4SLinus Torvalds return sizeof(disconnect_pg); 21761da177e4SLinus Torvalds } 21771da177e4SLinus Torvalds 21781da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 21791da177e4SLinus Torvalds { /* Format device page for mode_sense */ 21801da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 21811da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 21821da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 21831da177e4SLinus Torvalds 21841da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2185773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2186773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2187773642d9SDouglas Gilbert if (sdebug_removable) 21881da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 21891da177e4SLinus Torvalds if (1 == pcontrol) 21901da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 21911da177e4SLinus Torvalds return sizeof(format_pg); 21921da177e4SLinus Torvalds } 21931da177e4SLinus Torvalds 2194fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2195fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2196fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2197fd32119bSDouglas Gilbert 21981da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 21991da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2200cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2201cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2202cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 22031da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 22041da177e4SLinus Torvalds 2205773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2206cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 22071da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 22081da177e4SLinus Torvalds if (1 == pcontrol) 2209cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2210cbf67842SDouglas Gilbert else if (2 == pcontrol) 2211cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 22121da177e4SLinus Torvalds return sizeof(caching_pg); 22131da177e4SLinus Torvalds } 22141da177e4SLinus Torvalds 2215fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2216fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2217fd32119bSDouglas Gilbert 22181da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 22191da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2220c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2221c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2222c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 22231da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 22241da177e4SLinus Torvalds 2225773642d9SDouglas Gilbert if (sdebug_dsense) 22261da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2227c65b1445SDouglas Gilbert else 2228c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2229c6a44287SMartin K. Petersen 2230773642d9SDouglas Gilbert if (sdebug_ato) 2231c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2232c6a44287SMartin K. Petersen 22331da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 22341da177e4SLinus Torvalds if (1 == pcontrol) 2235c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2236c65b1445SDouglas Gilbert else if (2 == pcontrol) 2237c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 22381da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 22391da177e4SLinus Torvalds } 22401da177e4SLinus Torvalds 2241c65b1445SDouglas Gilbert 22421da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 22431da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2244c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 22451da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2246c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2247c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2248c65b1445SDouglas Gilbert 22491da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 22501da177e4SLinus Torvalds if (1 == pcontrol) 2251c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2252c65b1445SDouglas Gilbert else if (2 == pcontrol) 2253c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 22541da177e4SLinus Torvalds return sizeof(iec_m_pg); 22551da177e4SLinus Torvalds } 22561da177e4SLinus Torvalds 2257c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2258c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2259c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2260c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2261c65b1445SDouglas Gilbert 2262c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2263c65b1445SDouglas Gilbert if (1 == pcontrol) 2264c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2265c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2266c65b1445SDouglas Gilbert } 2267c65b1445SDouglas Gilbert 2268c65b1445SDouglas Gilbert 2269c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2270c65b1445SDouglas Gilbert int target_dev_id) 2271c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2272c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2273c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2274773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2275773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2276c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2277c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2278c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2279c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2280773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2281773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2282c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2283c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2284c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2285c65b1445SDouglas Gilbert }; 2286c65b1445SDouglas Gilbert int port_a, port_b; 2287c65b1445SDouglas Gilbert 22881b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 22891b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 22901b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 22911b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2292c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2293c65b1445SDouglas Gilbert port_b = port_a + 1; 2294c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2295773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2296773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2297c65b1445SDouglas Gilbert if (1 == pcontrol) 2298c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2299c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2300c65b1445SDouglas Gilbert } 2301c65b1445SDouglas Gilbert 2302c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2303c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2304c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2305c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2306c65b1445SDouglas Gilbert }; 2307c65b1445SDouglas Gilbert 2308c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2309c65b1445SDouglas Gilbert if (1 == pcontrol) 2310c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2311c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2312c65b1445SDouglas Gilbert } 2313c65b1445SDouglas Gilbert 23141da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 23151da177e4SLinus Torvalds 2316fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2317fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 23181da177e4SLinus Torvalds { 231923183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 23201da177e4SLinus Torvalds unsigned char dev_spec; 232136e07d7eSGeorge Kennedy u32 alloc_len, offset, len; 232236e07d7eSGeorge Kennedy int target_dev_id; 2323c2248fc9SDouglas Gilbert int target = scp->device->id; 23241da177e4SLinus Torvalds unsigned char *ap; 23251da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 232601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2327d36da305SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, is_zbc, bad_pcode; 23281da177e4SLinus Torvalds 2329760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 23301da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 23311da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 23321da177e4SLinus Torvalds subpcode = cmd[3]; 23331da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2334760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2335760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 233664e14eceSDamien Le Moal is_zbc = (devip->zmodel != BLK_ZONED_NONE); 2337d36da305SDouglas Gilbert if ((is_disk || is_zbc) && !dbd) 233823183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 233923183910SDouglas Gilbert else 234023183910SDouglas Gilbert bd_len = 0; 2341773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 23421da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 23431da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2344cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 23451da177e4SLinus Torvalds return check_condition_result; 23461da177e4SLinus Torvalds } 2347c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2348c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2349d36da305SDouglas Gilbert /* for disks+zbc set DPOFUA bit and clear write protect (WP) bit */ 2350d36da305SDouglas Gilbert if (is_disk || is_zbc) { 2351b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 23529447b6ceSMartin K. Petersen if (sdebug_wp) 23539447b6ceSMartin K. Petersen dev_spec |= 0x80; 23549447b6ceSMartin K. Petersen } else 235523183910SDouglas Gilbert dev_spec = 0x0; 23561da177e4SLinus Torvalds if (msense_6) { 23571da177e4SLinus Torvalds arr[2] = dev_spec; 235823183910SDouglas Gilbert arr[3] = bd_len; 23591da177e4SLinus Torvalds offset = 4; 23601da177e4SLinus Torvalds } else { 23611da177e4SLinus Torvalds arr[3] = dev_spec; 236223183910SDouglas Gilbert if (16 == bd_len) 236323183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 236423183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 23651da177e4SLinus Torvalds offset = 8; 23661da177e4SLinus Torvalds } 23671da177e4SLinus Torvalds ap = arr + offset; 236828898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 236928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 237028898873SFUJITA Tomonori 237123183910SDouglas Gilbert if (8 == bd_len) { 2372773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2373773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2374773642d9SDouglas Gilbert else 2375773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2376773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 237723183910SDouglas Gilbert offset += bd_len; 237823183910SDouglas Gilbert ap = arr + offset; 237923183910SDouglas Gilbert } else if (16 == bd_len) { 2380773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2381773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 238223183910SDouglas Gilbert offset += bd_len; 238323183910SDouglas Gilbert ap = arr + offset; 238423183910SDouglas Gilbert } 23851da177e4SLinus Torvalds 2386c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2387c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 238822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 23891da177e4SLinus Torvalds return check_condition_result; 23901da177e4SLinus Torvalds } 2391760f3b03SDouglas Gilbert bad_pcode = false; 2392760f3b03SDouglas Gilbert 23931da177e4SLinus Torvalds switch (pcode) { 23941da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 23951da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 23961da177e4SLinus Torvalds offset += len; 23971da177e4SLinus Torvalds break; 23981da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 23991da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 24001da177e4SLinus Torvalds offset += len; 24011da177e4SLinus Torvalds break; 24021da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2403760f3b03SDouglas Gilbert if (is_disk) { 24041da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 24051da177e4SLinus Torvalds offset += len; 2406760f3b03SDouglas Gilbert } else 2407760f3b03SDouglas Gilbert bad_pcode = true; 24081da177e4SLinus Torvalds break; 24091da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2410d36da305SDouglas Gilbert if (is_disk || is_zbc) { 24111da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 24121da177e4SLinus Torvalds offset += len; 2413760f3b03SDouglas Gilbert } else 2414760f3b03SDouglas Gilbert bad_pcode = true; 24151da177e4SLinus Torvalds break; 24161da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 24171da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 24181da177e4SLinus Torvalds offset += len; 24191da177e4SLinus Torvalds break; 2420c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2421c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 242222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2423c65b1445SDouglas Gilbert return check_condition_result; 2424c65b1445SDouglas Gilbert } 2425c65b1445SDouglas Gilbert len = 0; 2426c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2427c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2428c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2429c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2430c65b1445SDouglas Gilbert target_dev_id); 2431c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2432c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2433c65b1445SDouglas Gilbert offset += len; 2434c65b1445SDouglas Gilbert break; 24351da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 24361da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 24371da177e4SLinus Torvalds offset += len; 24381da177e4SLinus Torvalds break; 24391da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2440c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 24411da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 24421da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2443760f3b03SDouglas Gilbert if (is_disk) { 2444760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2445760f3b03SDouglas Gilbert target); 2446760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2447760f3b03SDouglas Gilbert target); 2448d36da305SDouglas Gilbert } else if (is_zbc) { 2449d36da305SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2450d36da305SDouglas Gilbert target); 2451760f3b03SDouglas Gilbert } 24521da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2453c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2454c65b1445SDouglas Gilbert if (0xff == subpcode) { 2455c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2456c65b1445SDouglas Gilbert target, target_dev_id); 2457c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2458c65b1445SDouglas Gilbert } 24591da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2460760f3b03SDouglas Gilbert offset += len; 2461c65b1445SDouglas Gilbert } else { 246222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2463c65b1445SDouglas Gilbert return check_condition_result; 2464c65b1445SDouglas Gilbert } 24651da177e4SLinus Torvalds break; 24661da177e4SLinus Torvalds default: 2467760f3b03SDouglas Gilbert bad_pcode = true; 2468760f3b03SDouglas Gilbert break; 2469760f3b03SDouglas Gilbert } 2470760f3b03SDouglas Gilbert if (bad_pcode) { 247122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 24721da177e4SLinus Torvalds return check_condition_result; 24731da177e4SLinus Torvalds } 24741da177e4SLinus Torvalds if (msense_6) 24751da177e4SLinus Torvalds arr[0] = offset - 1; 2476773642d9SDouglas Gilbert else 2477773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 247836e07d7eSGeorge Kennedy return fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, offset)); 24791da177e4SLinus Torvalds } 24801da177e4SLinus Torvalds 2481c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2482c65b1445SDouglas Gilbert 2483fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2484fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2485c65b1445SDouglas Gilbert { 2486c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2487c2248fc9SDouglas Gilbert int param_len, res, mpage; 2488c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 248901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2490c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2491c65b1445SDouglas Gilbert 2492c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2493c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2494c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2495773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2496c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 249722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2498c65b1445SDouglas Gilbert return check_condition_result; 2499c65b1445SDouglas Gilbert } 2500c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2501c65b1445SDouglas Gilbert if (-1 == res) 2502773642d9SDouglas Gilbert return DID_ERROR << 16; 2503773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2504cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2505cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2506cbf67842SDouglas Gilbert __func__, param_len, res); 2507773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2508773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 2509e0a2c28dSGeorge Kennedy off = bd_len + (mselect6 ? 4 : 8); 2510e0a2c28dSGeorge Kennedy if (md_len > 2 || off >= res) { 251122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2512c65b1445SDouglas Gilbert return check_condition_result; 2513c65b1445SDouglas Gilbert } 2514c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2515c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2516c65b1445SDouglas Gilbert if (ps) { 251722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2518c65b1445SDouglas Gilbert return check_condition_result; 2519c65b1445SDouglas Gilbert } 2520c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2521773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2522c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2523c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2524cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2525c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2526c65b1445SDouglas Gilbert return check_condition_result; 2527c65b1445SDouglas Gilbert } 2528c65b1445SDouglas Gilbert switch (mpage) { 2529cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2530cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2531cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2532cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2533cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2534cbf67842SDouglas Gilbert } 2535cbf67842SDouglas Gilbert break; 2536c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2537c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2538c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2539c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 25409447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 25419447b6ceSMartin K. Petersen sdebug_wp = true; 25429447b6ceSMartin K. Petersen else 25439447b6ceSMartin K. Petersen sdebug_wp = false; 2544773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2545cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2546c65b1445SDouglas Gilbert } 2547c65b1445SDouglas Gilbert break; 2548c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2549c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2550c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2551c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2552cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2553c65b1445SDouglas Gilbert } 2554c65b1445SDouglas Gilbert break; 2555c65b1445SDouglas Gilbert default: 2556c65b1445SDouglas Gilbert break; 2557c65b1445SDouglas Gilbert } 255822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2559c65b1445SDouglas Gilbert return check_condition_result; 2560cbf67842SDouglas Gilbert set_mode_changed_ua: 2561cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2562cbf67842SDouglas Gilbert return 0; 2563c65b1445SDouglas Gilbert } 2564c65b1445SDouglas Gilbert 2565c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2566c65b1445SDouglas Gilbert { 2567c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2568c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2569c65b1445SDouglas Gilbert }; 2570c65b1445SDouglas Gilbert 2571c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2572c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2573c65b1445SDouglas Gilbert } 2574c65b1445SDouglas Gilbert 2575c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2576c65b1445SDouglas Gilbert { 2577c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2578c65b1445SDouglas Gilbert }; 2579c65b1445SDouglas Gilbert 2580c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2581c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2582c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2583c65b1445SDouglas Gilbert arr[5] = 0xff; 2584c65b1445SDouglas Gilbert } 2585c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2586c65b1445SDouglas Gilbert } 2587c65b1445SDouglas Gilbert 2588c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2589c65b1445SDouglas Gilbert 2590c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2591c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2592c65b1445SDouglas Gilbert { 259336e07d7eSGeorge Kennedy int ppc, sp, pcode, subpcode; 259436e07d7eSGeorge Kennedy u32 alloc_len, len, n; 2595c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 259601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2597c65b1445SDouglas Gilbert 2598c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2599c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2600c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2601c65b1445SDouglas Gilbert if (ppc || sp) { 260222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2603c65b1445SDouglas Gilbert return check_condition_result; 2604c65b1445SDouglas Gilbert } 2605c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 260623183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2607773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2608c65b1445SDouglas Gilbert arr[0] = pcode; 260923183910SDouglas Gilbert if (0 == subpcode) { 2610c65b1445SDouglas Gilbert switch (pcode) { 2611c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2612c65b1445SDouglas Gilbert n = 4; 2613c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2614c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2615c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2616c65b1445SDouglas Gilbert arr[3] = n - 4; 2617c65b1445SDouglas Gilbert break; 2618c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2619c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2620c65b1445SDouglas Gilbert break; 2621c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2622c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2623c65b1445SDouglas Gilbert break; 2624c65b1445SDouglas Gilbert default: 262522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2626c65b1445SDouglas Gilbert return check_condition_result; 2627c65b1445SDouglas Gilbert } 262823183910SDouglas Gilbert } else if (0xff == subpcode) { 262923183910SDouglas Gilbert arr[0] |= 0x40; 263023183910SDouglas Gilbert arr[1] = subpcode; 263123183910SDouglas Gilbert switch (pcode) { 263223183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 263323183910SDouglas Gilbert n = 4; 263423183910SDouglas Gilbert arr[n++] = 0x0; 263523183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 263623183910SDouglas Gilbert arr[n++] = 0x0; 263723183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 263823183910SDouglas Gilbert arr[n++] = 0xd; 263923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 264023183910SDouglas Gilbert arr[n++] = 0x2f; 264123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 264223183910SDouglas Gilbert arr[3] = n - 4; 264323183910SDouglas Gilbert break; 264423183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 264523183910SDouglas Gilbert n = 4; 264623183910SDouglas Gilbert arr[n++] = 0xd; 264723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 264823183910SDouglas Gilbert arr[3] = n - 4; 264923183910SDouglas Gilbert break; 265023183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 265123183910SDouglas Gilbert n = 4; 265223183910SDouglas Gilbert arr[n++] = 0x2f; 265323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 265423183910SDouglas Gilbert arr[3] = n - 4; 265523183910SDouglas Gilbert break; 265623183910SDouglas Gilbert default: 265722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 265823183910SDouglas Gilbert return check_condition_result; 265923183910SDouglas Gilbert } 266023183910SDouglas Gilbert } else { 266122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 266223183910SDouglas Gilbert return check_condition_result; 266323183910SDouglas Gilbert } 266436e07d7eSGeorge Kennedy len = min_t(u32, get_unaligned_be16(arr + 2) + 4, alloc_len); 2665c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 266636e07d7eSGeorge Kennedy min_t(u32, len, SDEBUG_MAX_INQ_ARR_SZ)); 2667c65b1445SDouglas Gilbert } 2668c65b1445SDouglas Gilbert 2669f0d1cf93SDouglas Gilbert static inline bool sdebug_dev_is_zoned(struct sdebug_dev_info *devip) 2670f0d1cf93SDouglas Gilbert { 2671f0d1cf93SDouglas Gilbert return devip->nr_zones != 0; 2672f0d1cf93SDouglas Gilbert } 2673f0d1cf93SDouglas Gilbert 2674f0d1cf93SDouglas Gilbert static struct sdeb_zone_state *zbc_zone(struct sdebug_dev_info *devip, 2675f0d1cf93SDouglas Gilbert unsigned long long lba) 2676f0d1cf93SDouglas Gilbert { 2677108e36f0SDamien Le Moal return &devip->zstate[lba >> devip->zsize_shift]; 2678f0d1cf93SDouglas Gilbert } 2679f0d1cf93SDouglas Gilbert 2680f0d1cf93SDouglas Gilbert static inline bool zbc_zone_is_conv(struct sdeb_zone_state *zsp) 2681f0d1cf93SDouglas Gilbert { 268264e14eceSDamien Le Moal return zsp->z_type == ZBC_ZONE_TYPE_CNV; 2683f0d1cf93SDouglas Gilbert } 2684f0d1cf93SDouglas Gilbert 2685f0d1cf93SDouglas Gilbert static void zbc_close_zone(struct sdebug_dev_info *devip, 2686f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 2687f0d1cf93SDouglas Gilbert { 2688f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2689f0d1cf93SDouglas Gilbert 2690f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2691f0d1cf93SDouglas Gilbert return; 2692f0d1cf93SDouglas Gilbert 2693f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2694f0d1cf93SDouglas Gilbert if (!(zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN)) 2695f0d1cf93SDouglas Gilbert return; 2696f0d1cf93SDouglas Gilbert 2697f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN) 2698f0d1cf93SDouglas Gilbert devip->nr_imp_open--; 2699f0d1cf93SDouglas Gilbert else 2700f0d1cf93SDouglas Gilbert devip->nr_exp_open--; 2701f0d1cf93SDouglas Gilbert 2702f0d1cf93SDouglas Gilbert if (zsp->z_wp == zsp->z_start) { 2703f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 2704f0d1cf93SDouglas Gilbert } else { 2705f0d1cf93SDouglas Gilbert zsp->z_cond = ZC4_CLOSED; 2706f0d1cf93SDouglas Gilbert devip->nr_closed++; 2707f0d1cf93SDouglas Gilbert } 2708f0d1cf93SDouglas Gilbert } 2709f0d1cf93SDouglas Gilbert 2710f0d1cf93SDouglas Gilbert static void zbc_close_imp_open_zone(struct sdebug_dev_info *devip) 2711f0d1cf93SDouglas Gilbert { 2712f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 2713f0d1cf93SDouglas Gilbert unsigned int i; 2714f0d1cf93SDouglas Gilbert 2715f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 2716f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC2_IMPLICIT_OPEN) { 2717f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2718f0d1cf93SDouglas Gilbert return; 2719f0d1cf93SDouglas Gilbert } 2720f0d1cf93SDouglas Gilbert } 2721f0d1cf93SDouglas Gilbert } 2722f0d1cf93SDouglas Gilbert 2723f0d1cf93SDouglas Gilbert static void zbc_open_zone(struct sdebug_dev_info *devip, 2724f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool explicit) 2725f0d1cf93SDouglas Gilbert { 2726f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 2727f0d1cf93SDouglas Gilbert 2728f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2729f0d1cf93SDouglas Gilbert return; 2730f0d1cf93SDouglas Gilbert 2731f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 2732f0d1cf93SDouglas Gilbert if ((explicit && zc == ZC3_EXPLICIT_OPEN) || 2733f0d1cf93SDouglas Gilbert (!explicit && zc == ZC2_IMPLICIT_OPEN)) 2734f0d1cf93SDouglas Gilbert return; 2735f0d1cf93SDouglas Gilbert 2736f0d1cf93SDouglas Gilbert /* Close an implicit open zone if necessary */ 2737f0d1cf93SDouglas Gilbert if (explicit && zsp->z_cond == ZC2_IMPLICIT_OPEN) 2738f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 2739f0d1cf93SDouglas Gilbert else if (devip->max_open && 2740f0d1cf93SDouglas Gilbert devip->nr_imp_open + devip->nr_exp_open >= devip->max_open) 2741f0d1cf93SDouglas Gilbert zbc_close_imp_open_zone(devip); 2742f0d1cf93SDouglas Gilbert 2743f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 2744f0d1cf93SDouglas Gilbert devip->nr_closed--; 2745f0d1cf93SDouglas Gilbert if (explicit) { 2746f0d1cf93SDouglas Gilbert zsp->z_cond = ZC3_EXPLICIT_OPEN; 2747f0d1cf93SDouglas Gilbert devip->nr_exp_open++; 2748f0d1cf93SDouglas Gilbert } else { 2749f0d1cf93SDouglas Gilbert zsp->z_cond = ZC2_IMPLICIT_OPEN; 2750f0d1cf93SDouglas Gilbert devip->nr_imp_open++; 2751f0d1cf93SDouglas Gilbert } 2752f0d1cf93SDouglas Gilbert } 2753f0d1cf93SDouglas Gilbert 2754f0d1cf93SDouglas Gilbert static void zbc_inc_wp(struct sdebug_dev_info *devip, 2755f0d1cf93SDouglas Gilbert unsigned long long lba, unsigned int num) 2756f0d1cf93SDouglas Gilbert { 2757f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 275864e14eceSDamien Le Moal unsigned long long n, end, zend = zsp->z_start + zsp->z_size; 2759f0d1cf93SDouglas Gilbert 2760f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 2761f0d1cf93SDouglas Gilbert return; 2762f0d1cf93SDouglas Gilbert 276364e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2764f0d1cf93SDouglas Gilbert zsp->z_wp += num; 276564e14eceSDamien Le Moal if (zsp->z_wp >= zend) 2766f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 276764e14eceSDamien Le Moal return; 276864e14eceSDamien Le Moal } 276964e14eceSDamien Le Moal 277064e14eceSDamien Le Moal while (num) { 277164e14eceSDamien Le Moal if (lba != zsp->z_wp) 277264e14eceSDamien Le Moal zsp->z_non_seq_resource = true; 277364e14eceSDamien Le Moal 277464e14eceSDamien Le Moal end = lba + num; 277564e14eceSDamien Le Moal if (end >= zend) { 277664e14eceSDamien Le Moal n = zend - lba; 277764e14eceSDamien Le Moal zsp->z_wp = zend; 277864e14eceSDamien Le Moal } else if (end > zsp->z_wp) { 277964e14eceSDamien Le Moal n = num; 278064e14eceSDamien Le Moal zsp->z_wp = end; 278164e14eceSDamien Le Moal } else { 278264e14eceSDamien Le Moal n = num; 278364e14eceSDamien Le Moal } 278464e14eceSDamien Le Moal if (zsp->z_wp >= zend) 278564e14eceSDamien Le Moal zsp->z_cond = ZC5_FULL; 278664e14eceSDamien Le Moal 278764e14eceSDamien Le Moal num -= n; 278864e14eceSDamien Le Moal lba += n; 278964e14eceSDamien Le Moal if (num) { 279064e14eceSDamien Le Moal zsp++; 279164e14eceSDamien Le Moal zend = zsp->z_start + zsp->z_size; 279264e14eceSDamien Le Moal } 279364e14eceSDamien Le Moal } 2794f0d1cf93SDouglas Gilbert } 2795f0d1cf93SDouglas Gilbert 2796f0d1cf93SDouglas Gilbert static int check_zbc_access_params(struct scsi_cmnd *scp, 27979447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 27981da177e4SLinus Torvalds { 2799f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2800f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2801f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = zbc_zone(devip, lba); 2802f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp_end = zbc_zone(devip, lba + num - 1); 2803f0d1cf93SDouglas Gilbert 2804f0d1cf93SDouglas Gilbert if (!write) { 280564e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HA) 280664e14eceSDamien Le Moal return 0; 280764e14eceSDamien Le Moal /* For host-managed, reads cannot cross zone types boundaries */ 2808f0d1cf93SDouglas Gilbert if (zsp_end != zsp && 2809f0d1cf93SDouglas Gilbert zbc_zone_is_conv(zsp) && 2810f0d1cf93SDouglas Gilbert !zbc_zone_is_conv(zsp_end)) { 2811f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2812f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2813f0d1cf93SDouglas Gilbert READ_INVDATA_ASCQ); 2814f0d1cf93SDouglas Gilbert return check_condition_result; 2815f0d1cf93SDouglas Gilbert } 2816f0d1cf93SDouglas Gilbert return 0; 2817f0d1cf93SDouglas Gilbert } 2818f0d1cf93SDouglas Gilbert 2819f0d1cf93SDouglas Gilbert /* No restrictions for writes within conventional zones */ 2820f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 2821f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp_end)) { 2822f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2823f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2824f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2825f0d1cf93SDouglas Gilbert return check_condition_result; 2826f0d1cf93SDouglas Gilbert } 2827f0d1cf93SDouglas Gilbert return 0; 2828f0d1cf93SDouglas Gilbert } 2829f0d1cf93SDouglas Gilbert 283064e14eceSDamien Le Moal if (zsp->z_type == ZBC_ZONE_TYPE_SWR) { 2831f0d1cf93SDouglas Gilbert /* Writes cannot cross sequential zone boundaries */ 2832f0d1cf93SDouglas Gilbert if (zsp_end != zsp) { 2833f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2834f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2835f0d1cf93SDouglas Gilbert WRITE_BOUNDARY_ASCQ); 2836f0d1cf93SDouglas Gilbert return check_condition_result; 2837f0d1cf93SDouglas Gilbert } 2838f0d1cf93SDouglas Gilbert /* Cannot write full zones */ 2839f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC5_FULL) { 2840f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2841f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 2842f0d1cf93SDouglas Gilbert return check_condition_result; 2843f0d1cf93SDouglas Gilbert } 2844f0d1cf93SDouglas Gilbert /* Writes must be aligned to the zone WP */ 2845f0d1cf93SDouglas Gilbert if (lba != zsp->z_wp) { 2846f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2847f0d1cf93SDouglas Gilbert LBA_OUT_OF_RANGE, 2848f0d1cf93SDouglas Gilbert UNALIGNED_WRITE_ASCQ); 2849f0d1cf93SDouglas Gilbert return check_condition_result; 2850f0d1cf93SDouglas Gilbert } 285164e14eceSDamien Le Moal } 2852f0d1cf93SDouglas Gilbert 2853f0d1cf93SDouglas Gilbert /* Handle implicit open of closed and empty zones */ 2854f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC1_EMPTY || zsp->z_cond == ZC4_CLOSED) { 2855f0d1cf93SDouglas Gilbert if (devip->max_open && 2856f0d1cf93SDouglas Gilbert devip->nr_exp_open >= devip->max_open) { 2857f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, 2858f0d1cf93SDouglas Gilbert INSUFF_RES_ASC, 2859f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 2860f0d1cf93SDouglas Gilbert return check_condition_result; 2861f0d1cf93SDouglas Gilbert } 2862f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, false); 2863f0d1cf93SDouglas Gilbert } 2864f0d1cf93SDouglas Gilbert 2865f0d1cf93SDouglas Gilbert return 0; 2866f0d1cf93SDouglas Gilbert } 2867f0d1cf93SDouglas Gilbert 2868f0d1cf93SDouglas Gilbert static inline int check_device_access_params 2869f0d1cf93SDouglas Gilbert (struct scsi_cmnd *scp, unsigned long long lba, 2870f0d1cf93SDouglas Gilbert unsigned int num, bool write) 2871f0d1cf93SDouglas Gilbert { 2872f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 2873f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 2874f0d1cf93SDouglas Gilbert 2875c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 287622017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 28771da177e4SLinus Torvalds return check_condition_result; 28781da177e4SLinus Torvalds } 2879c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2880c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 288122017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2882cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2883c65b1445SDouglas Gilbert return check_condition_result; 2884c65b1445SDouglas Gilbert } 28859447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 28869447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 28879447b6ceSMartin K. Petersen return check_condition_result; 28889447b6ceSMartin K. Petersen } 2889f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 2890f0d1cf93SDouglas Gilbert return check_zbc_access_params(scp, lba, num, write); 2891f0d1cf93SDouglas Gilbert 289219789100SFUJITA Tomonori return 0; 289319789100SFUJITA Tomonori } 289419789100SFUJITA Tomonori 2895b6ff8ca7SDouglas Gilbert /* 2896b6ff8ca7SDouglas Gilbert * Note: if BUG_ON() fires it usually indicates a problem with the parser 2897b6ff8ca7SDouglas Gilbert * tables. Perhaps a missing F_FAKE_RW or FF_MEDIA_IO flag. Response functions 2898b6ff8ca7SDouglas Gilbert * that access any of the "stores" in struct sdeb_store_info should call this 2899b6ff8ca7SDouglas Gilbert * function with bug_if_fake_rw set to true. 2900b6ff8ca7SDouglas Gilbert */ 2901b6ff8ca7SDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip, 2902b6ff8ca7SDouglas Gilbert bool bug_if_fake_rw) 290387c715dcSDouglas Gilbert { 2904b6ff8ca7SDouglas Gilbert if (sdebug_fake_rw) { 2905b6ff8ca7SDouglas Gilbert BUG_ON(bug_if_fake_rw); /* See note above */ 2906b6ff8ca7SDouglas Gilbert return NULL; 2907b6ff8ca7SDouglas Gilbert } 2908b6ff8ca7SDouglas Gilbert return xa_load(per_store_ap, devip->sdbg_host->si_idx); 290987c715dcSDouglas Gilbert } 291087c715dcSDouglas Gilbert 2911a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 291287c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 291387c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 291419789100SFUJITA Tomonori { 291519789100SFUJITA Tomonori int ret; 2916c2248fc9SDouglas Gilbert u64 block, rest = 0; 2917a4517511SAkinobu Mita enum dma_data_direction dir; 291887c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 291987c715dcSDouglas Gilbert u8 *fsp; 292019789100SFUJITA Tomonori 2921c2248fc9SDouglas Gilbert if (do_write) { 2922a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 29234f2c8bf6SDouglas Gilbert write_since_sync = true; 2924a4517511SAkinobu Mita } else { 2925a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2926a4517511SAkinobu Mita } 2927a4517511SAkinobu Mita 292887c715dcSDouglas Gilbert if (!sdb->length || !sip) 2929a4517511SAkinobu Mita return 0; 293087c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2931a4517511SAkinobu Mita return -1; 293287c715dcSDouglas Gilbert fsp = sip->storep; 293319789100SFUJITA Tomonori 293419789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 293519789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 293619789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 293719789100SFUJITA Tomonori 2938386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 293987c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 29400a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2941773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2942a4517511SAkinobu Mita return ret; 2943a4517511SAkinobu Mita 2944a4517511SAkinobu Mita if (rest) { 2945386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 294687c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 29470a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 29480a7e69c7SDouglas Gilbert do_write); 2949a4517511SAkinobu Mita } 295019789100SFUJITA Tomonori 295119789100SFUJITA Tomonori return ret; 295219789100SFUJITA Tomonori } 295319789100SFUJITA Tomonori 295487c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 295587c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 295687c715dcSDouglas Gilbert { 295787c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 295887c715dcSDouglas Gilbert 295987c715dcSDouglas Gilbert if (!sdb->length) 296087c715dcSDouglas Gilbert return 0; 296187c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 296287c715dcSDouglas Gilbert return -1; 296387c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 296487c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 296587c715dcSDouglas Gilbert } 296687c715dcSDouglas Gilbert 296787c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 296887c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 296938d5c833SDouglas Gilbert * return false. */ 297087c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 2971c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 297238d5c833SDouglas Gilbert { 297338d5c833SDouglas Gilbert bool res; 297438d5c833SDouglas Gilbert u64 block, rest = 0; 297538d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2976773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 297787c715dcSDouglas Gilbert u8 *fsp = sip->storep; 297838d5c833SDouglas Gilbert 297938d5c833SDouglas Gilbert block = do_div(lba, store_blks); 298038d5c833SDouglas Gilbert if (block + num > store_blks) 298138d5c833SDouglas Gilbert rest = block + num - store_blks; 298238d5c833SDouglas Gilbert 298387c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 298438d5c833SDouglas Gilbert if (!res) 298538d5c833SDouglas Gilbert return res; 298638d5c833SDouglas Gilbert if (rest) 298787c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 298838d5c833SDouglas Gilbert rest * lb_size); 298938d5c833SDouglas Gilbert if (!res) 299038d5c833SDouglas Gilbert return res; 2991c3e2fe92SDouglas Gilbert if (compare_only) 2992c3e2fe92SDouglas Gilbert return true; 299338d5c833SDouglas Gilbert arr += num * lb_size; 299487c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 299538d5c833SDouglas Gilbert if (rest) 299687c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 299738d5c833SDouglas Gilbert return res; 299838d5c833SDouglas Gilbert } 299938d5c833SDouglas Gilbert 300051d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 3001beb40ea4SAkinobu Mita { 300251d648afSAkinobu Mita __be16 csum; 3003beb40ea4SAkinobu Mita 3004773642d9SDouglas Gilbert if (sdebug_guard) 300551d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 300651d648afSAkinobu Mita else 3007beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 300851d648afSAkinobu Mita 3009beb40ea4SAkinobu Mita return csum; 3010beb40ea4SAkinobu Mita } 3011beb40ea4SAkinobu Mita 30126ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 3013beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 3014beb40ea4SAkinobu Mita { 3015773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 3016beb40ea4SAkinobu Mita 3017beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 3018c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 3019beb40ea4SAkinobu Mita (unsigned long)sector, 3020beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 3021beb40ea4SAkinobu Mita be16_to_cpu(csum)); 3022beb40ea4SAkinobu Mita return 0x01; 3023beb40ea4SAkinobu Mita } 30248475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 3025beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 3026c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3027c1287970STomas Winkler (unsigned long)sector); 3028beb40ea4SAkinobu Mita return 0x03; 3029beb40ea4SAkinobu Mita } 30308475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3031beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 3032c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 3033c1287970STomas Winkler (unsigned long)sector); 3034beb40ea4SAkinobu Mita return 0x03; 3035beb40ea4SAkinobu Mita } 3036beb40ea4SAkinobu Mita return 0; 3037beb40ea4SAkinobu Mita } 3038beb40ea4SAkinobu Mita 303987c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 304065f72f2aSAkinobu Mita unsigned int sectors, bool read) 3041c6a44287SMartin K. Petersen { 3042be4e11beSAkinobu Mita size_t resid; 3043c6a44287SMartin K. Petersen void *paddr; 304487c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3045b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 304687c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 304714faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 3048be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3049c6a44287SMartin K. Petersen 3050e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 3051e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 3052c6a44287SMartin K. Petersen 305387c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 305487c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 3055be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 3056be4e11beSAkinobu Mita 3057be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 305887c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 305987c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 3060be4e11beSAkinobu Mita size_t rest = 0; 306114faa944SAkinobu Mita 306214faa944SAkinobu Mita if (dif_store_end < start + len) 306314faa944SAkinobu Mita rest = start + len - dif_store_end; 3064c6a44287SMartin K. Petersen 3065be4e11beSAkinobu Mita paddr = miter.addr; 306614faa944SAkinobu Mita 306765f72f2aSAkinobu Mita if (read) 306865f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 306965f72f2aSAkinobu Mita else 307065f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 307165f72f2aSAkinobu Mita 307265f72f2aSAkinobu Mita if (rest) { 307365f72f2aSAkinobu Mita if (read) 307414faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 307565f72f2aSAkinobu Mita else 307665f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 307765f72f2aSAkinobu Mita } 3078c6a44287SMartin K. Petersen 3079e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 3080c6a44287SMartin K. Petersen resid -= len; 3081c6a44287SMartin K. Petersen } 3082be4e11beSAkinobu Mita sg_miter_stop(&miter); 3083bb8c063cSAkinobu Mita } 3084c6a44287SMartin K. Petersen 308587c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 3086bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 3087bb8c063cSAkinobu Mita { 3088f7be6772SMartin K. Petersen int ret = 0; 3089bb8c063cSAkinobu Mita unsigned int i; 3090bb8c063cSAkinobu Mita sector_t sector; 309187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3092b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 309387c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 3094bb8c063cSAkinobu Mita 3095c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 3096bb8c063cSAkinobu Mita sector = start_sec + i; 309787c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 3098bb8c063cSAkinobu Mita 309951d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 3100bb8c063cSAkinobu Mita continue; 3101bb8c063cSAkinobu Mita 3102f7be6772SMartin K. Petersen /* 3103f7be6772SMartin K. Petersen * Because scsi_debug acts as both initiator and 3104f7be6772SMartin K. Petersen * target we proceed to verify the PI even if 3105f7be6772SMartin K. Petersen * RDPROTECT=3. This is done so the "initiator" knows 3106f7be6772SMartin K. Petersen * which type of error to return. Otherwise we would 3107f7be6772SMartin K. Petersen * have to iterate over the PI twice. 3108f7be6772SMartin K. Petersen */ 3109f7be6772SMartin K. Petersen if (scp->cmnd[1] >> 5) { /* RDPROTECT */ 3110f7be6772SMartin K. Petersen ret = dif_verify(sdt, lba2fake_store(sip, sector), 3111f7be6772SMartin K. Petersen sector, ei_lba); 3112bb8c063cSAkinobu Mita if (ret) { 3113bb8c063cSAkinobu Mita dif_errors++; 3114f7be6772SMartin K. Petersen break; 3115f7be6772SMartin K. Petersen } 3116bb8c063cSAkinobu Mita } 3117bb8c063cSAkinobu Mita } 3118bb8c063cSAkinobu Mita 311987c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 3120c6a44287SMartin K. Petersen dix_reads++; 3121c6a44287SMartin K. Petersen 3122f7be6772SMartin K. Petersen return ret; 3123c6a44287SMartin K. Petersen } 3124c6a44287SMartin K. Petersen 3125fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 312619789100SFUJITA Tomonori { 312787c715dcSDouglas Gilbert bool check_prot; 3128c2248fc9SDouglas Gilbert u32 num; 3129c2248fc9SDouglas Gilbert u32 ei_lba; 313019789100SFUJITA Tomonori int ret; 313187c715dcSDouglas Gilbert u64 lba; 3132b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 313387c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 313487c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 313519789100SFUJITA Tomonori 3136c2248fc9SDouglas Gilbert switch (cmd[0]) { 3137c2248fc9SDouglas Gilbert case READ_16: 3138c2248fc9SDouglas Gilbert ei_lba = 0; 3139c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3140c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3141c2248fc9SDouglas Gilbert check_prot = true; 3142c2248fc9SDouglas Gilbert break; 3143c2248fc9SDouglas Gilbert case READ_10: 3144c2248fc9SDouglas Gilbert ei_lba = 0; 3145c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3146c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3147c2248fc9SDouglas Gilbert check_prot = true; 3148c2248fc9SDouglas Gilbert break; 3149c2248fc9SDouglas Gilbert case READ_6: 3150c2248fc9SDouglas Gilbert ei_lba = 0; 3151c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3152c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3153c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3154c2248fc9SDouglas Gilbert check_prot = true; 3155c2248fc9SDouglas Gilbert break; 3156c2248fc9SDouglas Gilbert case READ_12: 3157c2248fc9SDouglas Gilbert ei_lba = 0; 3158c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3159c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3160c2248fc9SDouglas Gilbert check_prot = true; 3161c2248fc9SDouglas Gilbert break; 3162c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 3163c2248fc9SDouglas Gilbert ei_lba = 0; 3164c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3165c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3166c2248fc9SDouglas Gilbert check_prot = false; 3167c2248fc9SDouglas Gilbert break; 3168c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 3169c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3170c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3171c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3172c2248fc9SDouglas Gilbert check_prot = false; 3173c2248fc9SDouglas Gilbert break; 3174c2248fc9SDouglas Gilbert } 3175f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 31768475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3177c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3178c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3179c2248fc9SDouglas Gilbert return check_condition_result; 3180c2248fc9SDouglas Gilbert } 31818475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31828475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3183c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3184c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 3185c2248fc9SDouglas Gilbert "to DIF device\n"); 3186c2248fc9SDouglas Gilbert } 31873a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_SHORT_TRANSFER) && 31883a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 3189c2248fc9SDouglas Gilbert num /= 2; 31903a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3191c2248fc9SDouglas Gilbert } 3192c2248fc9SDouglas Gilbert 31939447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 31949447b6ceSMartin K. Petersen if (ret) 31959447b6ceSMartin K. Petersen return ret; 3196f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 3197d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 3198d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 3199c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 3200c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 3201c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 3202c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 3203c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 320432f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 320532f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 3206c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 3207c65b1445SDouglas Gilbert } 3208c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 32091da177e4SLinus Torvalds return check_condition_result; 32101da177e4SLinus Torvalds } 3211c6a44287SMartin K. Petersen 321267da413fSDouglas Gilbert read_lock(macc_lckp); 32136c78cc06SAkinobu Mita 3214c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3215f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3216f7be6772SMartin K. Petersen switch (prot_verify_read(scp, lba, num, ei_lba)) { 3217f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3218f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 321967da413fSDouglas Gilbert read_unlock(macc_lckp); 3220f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3221f7be6772SMartin K. Petersen return check_condition_result; 3222f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 3223f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3224f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3225c6a44287SMartin K. Petersen return illegal_condition_result; 3226c6a44287SMartin K. Petersen } 3227f7be6772SMartin K. Petersen break; 3228f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3229f7be6772SMartin K. Petersen if (cmd[1] >> 5 != 3) { /* RDPROTECT != 3 */ 3230f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3231f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3232f7be6772SMartin K. Petersen return check_condition_result; 3233f7be6772SMartin K. Petersen } else if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 3234f7be6772SMartin K. Petersen read_unlock(macc_lckp); 3235f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3236f7be6772SMartin K. Petersen return illegal_condition_result; 3237f7be6772SMartin K. Petersen } 3238f7be6772SMartin K. Petersen break; 3239f7be6772SMartin K. Petersen } 3240c6a44287SMartin K. Petersen } 3241c6a44287SMartin K. Petersen 324287c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 324367da413fSDouglas Gilbert read_unlock(macc_lckp); 3244f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 3245a4517511SAkinobu Mita return DID_ERROR << 16; 3246a4517511SAkinobu Mita 324742d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 3248a4517511SAkinobu Mita 32493a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 32503a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 32513a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 32523a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 32533a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3254c2248fc9SDouglas Gilbert return check_condition_result; 32553a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3256c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3257c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 32583a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3259c2248fc9SDouglas Gilbert return illegal_condition_result; 32603a90a63dSDouglas Gilbert } else if (SDEBUG_OPT_DIX_ERR & sdebug_opts) { 3261c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 32623a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3263c2248fc9SDouglas Gilbert return illegal_condition_result; 3264c2248fc9SDouglas Gilbert } 3265c2248fc9SDouglas Gilbert } 3266a4517511SAkinobu Mita return 0; 32671da177e4SLinus Torvalds } 32681da177e4SLinus Torvalds 3269c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 3270395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 3271c6a44287SMartin K. Petersen { 3272be4e11beSAkinobu Mita int ret; 32736ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 3274be4e11beSAkinobu Mita void *daddr; 327565f72f2aSAkinobu Mita sector_t sector = start_sec; 3276c6a44287SMartin K. Petersen int ppage_offset; 3277be4e11beSAkinobu Mita int dpage_offset; 3278be4e11beSAkinobu Mita struct sg_mapping_iter diter; 3279be4e11beSAkinobu Mita struct sg_mapping_iter piter; 3280c6a44287SMartin K. Petersen 3281c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 3282c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 3283c6a44287SMartin K. Petersen 3284be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 3285be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 3286be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3287be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 3288be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 3289c6a44287SMartin K. Petersen 3290be4e11beSAkinobu Mita /* For each protection page */ 3291be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 3292be4e11beSAkinobu Mita dpage_offset = 0; 3293be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3294be4e11beSAkinobu Mita ret = 0x01; 3295be4e11beSAkinobu Mita goto out; 3296c6a44287SMartin K. Petersen } 3297c6a44287SMartin K. Petersen 3298be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 32996ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 3300be4e11beSAkinobu Mita /* If we're at the end of the current 3301be4e11beSAkinobu Mita * data page advance to the next one 3302be4e11beSAkinobu Mita */ 3303be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 3304be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 3305be4e11beSAkinobu Mita ret = 0x01; 3306be4e11beSAkinobu Mita goto out; 3307be4e11beSAkinobu Mita } 3308be4e11beSAkinobu Mita dpage_offset = 0; 3309be4e11beSAkinobu Mita } 3310c6a44287SMartin K. Petersen 3311be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 3312be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 3313be4e11beSAkinobu Mita 3314f7be6772SMartin K. Petersen if (SCpnt->cmnd[1] >> 5 != 3) { /* WRPROTECT */ 3315be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 3316c78be80dSMartin K. Petersen if (ret) 3317395cef03SMartin K. Petersen goto out; 3318395cef03SMartin K. Petersen } 3319395cef03SMartin K. Petersen 3320c6a44287SMartin K. Petersen sector++; 3321395cef03SMartin K. Petersen ei_lba++; 3322773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 3323c6a44287SMartin K. Petersen } 3324be4e11beSAkinobu Mita diter.consumed = dpage_offset; 3325be4e11beSAkinobu Mita sg_miter_stop(&diter); 3326c6a44287SMartin K. Petersen } 3327be4e11beSAkinobu Mita sg_miter_stop(&piter); 3328c6a44287SMartin K. Petersen 332965f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 3330c6a44287SMartin K. Petersen dix_writes++; 3331c6a44287SMartin K. Petersen 3332c6a44287SMartin K. Petersen return 0; 3333c6a44287SMartin K. Petersen 3334c6a44287SMartin K. Petersen out: 3335c6a44287SMartin K. Petersen dif_errors++; 3336be4e11beSAkinobu Mita sg_miter_stop(&diter); 3337be4e11beSAkinobu Mita sg_miter_stop(&piter); 3338c6a44287SMartin K. Petersen return ret; 3339c6a44287SMartin K. Petersen } 3340c6a44287SMartin K. Petersen 3341b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 3342b90ebc3dSAkinobu Mita { 3343773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3344773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 3345773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 3346b90ebc3dSAkinobu Mita return lba; 3347b90ebc3dSAkinobu Mita } 3348b90ebc3dSAkinobu Mita 3349b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 3350b90ebc3dSAkinobu Mita { 3351773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 3352a027b5b9SAkinobu Mita 3353773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 3354773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 3355a027b5b9SAkinobu Mita return lba; 3356a027b5b9SAkinobu Mita } 3357a027b5b9SAkinobu Mita 335887c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 335987c715dcSDouglas Gilbert unsigned int *num) 336044d92694SMartin K. Petersen { 3361b90ebc3dSAkinobu Mita sector_t end; 3362b90ebc3dSAkinobu Mita unsigned int mapped; 3363b90ebc3dSAkinobu Mita unsigned long index; 3364b90ebc3dSAkinobu Mita unsigned long next; 336544d92694SMartin K. Petersen 3366b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 336787c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 336844d92694SMartin K. Petersen 336944d92694SMartin K. Petersen if (mapped) 337087c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 337144d92694SMartin K. Petersen else 337287c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 337344d92694SMartin K. Petersen 3374b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 337544d92694SMartin K. Petersen *num = end - lba; 337644d92694SMartin K. Petersen return mapped; 337744d92694SMartin K. Petersen } 337844d92694SMartin K. Petersen 337987c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 338087c715dcSDouglas Gilbert unsigned int len) 338144d92694SMartin K. Petersen { 338244d92694SMartin K. Petersen sector_t end = lba + len; 338344d92694SMartin K. Petersen 338444d92694SMartin K. Petersen while (lba < end) { 3385b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 338644d92694SMartin K. Petersen 3387b90ebc3dSAkinobu Mita if (index < map_size) 338887c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 338944d92694SMartin K. Petersen 3390b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 339144d92694SMartin K. Petersen } 339244d92694SMartin K. Petersen } 339344d92694SMartin K. Petersen 339487c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 339587c715dcSDouglas Gilbert unsigned int len) 339644d92694SMartin K. Petersen { 339744d92694SMartin K. Petersen sector_t end = lba + len; 339887c715dcSDouglas Gilbert u8 *fsp = sip->storep; 339944d92694SMartin K. Petersen 340044d92694SMartin K. Petersen while (lba < end) { 3401b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 340244d92694SMartin K. Petersen 3403b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3404773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3405b90ebc3dSAkinobu Mita index < map_size) { 340687c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3407760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 340887c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3409760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3410773642d9SDouglas Gilbert sdebug_sector_size * 3411773642d9SDouglas Gilbert sdebug_unmap_granularity); 3412be1dd78dSEric Sandeen } 341387c715dcSDouglas Gilbert if (sip->dif_storep) { 341487c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 341587c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3416773642d9SDouglas Gilbert sdebug_unmap_granularity); 3417e9926b43SAkinobu Mita } 3418b90ebc3dSAkinobu Mita } 3419b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 342044d92694SMartin K. Petersen } 342144d92694SMartin K. Petersen } 342244d92694SMartin K. Petersen 3423fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 34241da177e4SLinus Torvalds { 342587c715dcSDouglas Gilbert bool check_prot; 3426c2248fc9SDouglas Gilbert u32 num; 3427c2248fc9SDouglas Gilbert u32 ei_lba; 342819789100SFUJITA Tomonori int ret; 342987c715dcSDouglas Gilbert u64 lba; 3430b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3431b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 343287c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 34331da177e4SLinus Torvalds 3434c2248fc9SDouglas Gilbert switch (cmd[0]) { 3435c2248fc9SDouglas Gilbert case WRITE_16: 3436c2248fc9SDouglas Gilbert ei_lba = 0; 3437c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3438c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3439c2248fc9SDouglas Gilbert check_prot = true; 3440c2248fc9SDouglas Gilbert break; 3441c2248fc9SDouglas Gilbert case WRITE_10: 3442c2248fc9SDouglas Gilbert ei_lba = 0; 3443c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3444c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3445c2248fc9SDouglas Gilbert check_prot = true; 3446c2248fc9SDouglas Gilbert break; 3447c2248fc9SDouglas Gilbert case WRITE_6: 3448c2248fc9SDouglas Gilbert ei_lba = 0; 3449c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3450c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3451c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3452c2248fc9SDouglas Gilbert check_prot = true; 3453c2248fc9SDouglas Gilbert break; 3454c2248fc9SDouglas Gilbert case WRITE_12: 3455c2248fc9SDouglas Gilbert ei_lba = 0; 3456c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3457c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3458c2248fc9SDouglas Gilbert check_prot = true; 3459c2248fc9SDouglas Gilbert break; 3460c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3461c2248fc9SDouglas Gilbert ei_lba = 0; 3462c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3463c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3464c2248fc9SDouglas Gilbert check_prot = false; 3465c2248fc9SDouglas Gilbert break; 3466c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3467c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3468c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3469c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3470c2248fc9SDouglas Gilbert check_prot = false; 3471c2248fc9SDouglas Gilbert break; 3472c2248fc9SDouglas Gilbert } 3473f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 34748475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3475c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3476c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3477c2248fc9SDouglas Gilbert return check_condition_result; 3478c2248fc9SDouglas Gilbert } 34798475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 34808475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3481c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3482c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3483c2248fc9SDouglas Gilbert "to DIF device\n"); 3484c2248fc9SDouglas Gilbert } 3485f0d1cf93SDouglas Gilbert 348667da413fSDouglas Gilbert write_lock(macc_lckp); 3487f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3488f0d1cf93SDouglas Gilbert if (ret) { 3489f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3490f0d1cf93SDouglas Gilbert return ret; 3491f0d1cf93SDouglas Gilbert } 34926c78cc06SAkinobu Mita 3493c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3494f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3495f7be6772SMartin K. Petersen switch (prot_verify_write(scp, lba, num, ei_lba)) { 3496f7be6772SMartin K. Petersen case 1: /* Guard tag error */ 3497f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_GUARD_CHECK) { 349867da413fSDouglas Gilbert write_unlock(macc_lckp); 3499f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3500c6a44287SMartin K. Petersen return illegal_condition_result; 3501f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 3502f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3503f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3504f7be6772SMartin K. Petersen return check_condition_result; 3505f7be6772SMartin K. Petersen } 3506f7be6772SMartin K. Petersen break; 3507f7be6772SMartin K. Petersen case 3: /* Reference tag error */ 3508f7be6772SMartin K. Petersen if (scp->prot_flags & SCSI_PROT_REF_CHECK) { 3509f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3510f7be6772SMartin K. Petersen mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3); 3511f7be6772SMartin K. Petersen return illegal_condition_result; 3512f7be6772SMartin K. Petersen } else if (scp->cmnd[1] >> 5 != 3) { /* WRPROTECT != 3 */ 3513f7be6772SMartin K. Petersen write_unlock(macc_lckp); 3514f7be6772SMartin K. Petersen mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 3); 3515f7be6772SMartin K. Petersen return check_condition_result; 3516f7be6772SMartin K. Petersen } 3517f7be6772SMartin K. Petersen break; 3518c6a44287SMartin K. Petersen } 3519c6a44287SMartin K. Petersen } 3520c6a44287SMartin K. Petersen 352187c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3522f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 352387c715dcSDouglas Gilbert map_region(sip, lba, num); 3524f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3525f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3526f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 352767da413fSDouglas Gilbert write_unlock(macc_lckp); 3528f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3529773642d9SDouglas Gilbert return DID_ERROR << 16; 3530c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3531c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3532c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3533cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3534773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 353544d92694SMartin K. Petersen 35363a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 35373a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 35383a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 35393a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 35403a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3541c2248fc9SDouglas Gilbert return check_condition_result; 35423a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3543c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3544c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 35453a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3546c2248fc9SDouglas Gilbert return illegal_condition_result; 35473a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 3548c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 35493a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3550c2248fc9SDouglas Gilbert return illegal_condition_result; 3551c2248fc9SDouglas Gilbert } 3552c2248fc9SDouglas Gilbert } 35531da177e4SLinus Torvalds return 0; 35541da177e4SLinus Torvalds } 35551da177e4SLinus Torvalds 3556481b5e5cSDouglas Gilbert /* 3557481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3558481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3559481b5e5cSDouglas Gilbert */ 3560481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3561481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3562481b5e5cSDouglas Gilbert { 3563481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3564481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3565481b5e5cSDouglas Gilbert u8 *up; 3566b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3567b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 3568481b5e5cSDouglas Gilbert u8 wrprotect; 3569481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3570481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3571481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3572481b5e5cSDouglas Gilbert u32 ei_lba; 3573481b5e5cSDouglas Gilbert u64 lba; 3574481b5e5cSDouglas Gilbert int ret, res; 3575481b5e5cSDouglas Gilbert bool is_16; 3576481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3577481b5e5cSDouglas Gilbert 3578481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3579481b5e5cSDouglas Gilbert is_16 = false; 3580481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3581481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3582481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3583481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3584481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3585481b5e5cSDouglas Gilbert is_16 = true; 3586481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3587481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3588481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3589481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3590481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3591481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3592481b5e5cSDouglas Gilbert wrprotect) { 3593481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3594481b5e5cSDouglas Gilbert return illegal_condition_result; 3595481b5e5cSDouglas Gilbert } 3596481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3597481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3598481b5e5cSDouglas Gilbert wrprotect == 0) 3599481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3600481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3601481b5e5cSDouglas Gilbert } 3602481b5e5cSDouglas Gilbert } 3603481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3604481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3605481b5e5cSDouglas Gilbert if (lbdof == 0) { 3606481b5e5cSDouglas Gilbert if (sdebug_verbose) 3607481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3608481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3609481b5e5cSDouglas Gilbert my_name, __func__); 3610481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3611481b5e5cSDouglas Gilbert return illegal_condition_result; 3612481b5e5cSDouglas Gilbert } 3613481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3614481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3615481b5e5cSDouglas Gilbert if (sdebug_verbose) 3616481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3617481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3618481b5e5cSDouglas Gilbert my_name, __func__); 3619481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3620481b5e5cSDouglas Gilbert return illegal_condition_result; 3621481b5e5cSDouglas Gilbert } 3622481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3623481b5e5cSDouglas Gilbert if (lrdp == NULL) 3624481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3625481b5e5cSDouglas Gilbert if (sdebug_verbose) 3626481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3627481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3628481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3629481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3630481b5e5cSDouglas Gilbert if (res == -1) { 3631481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3632481b5e5cSDouglas Gilbert goto err_out; 3633481b5e5cSDouglas Gilbert } 3634481b5e5cSDouglas Gilbert 363567da413fSDouglas Gilbert write_lock(macc_lckp); 3636481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3637481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3638481b5e5cSDouglas Gilbert cum_lb = 0; 3639481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3640481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3641481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3642481b5e5cSDouglas Gilbert if (sdebug_verbose) 3643481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3644481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3645481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3646481b5e5cSDouglas Gilbert if (num == 0) 3647481b5e5cSDouglas Gilbert continue; 36489447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3649481b5e5cSDouglas Gilbert if (ret) 3650481b5e5cSDouglas Gilbert goto err_out_unlock; 3651481b5e5cSDouglas Gilbert num_by = num * lb_size; 3652481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3653481b5e5cSDouglas Gilbert 3654481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3655481b5e5cSDouglas Gilbert if (sdebug_verbose) 3656481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3657481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3658481b5e5cSDouglas Gilbert my_name, __func__); 3659481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3660481b5e5cSDouglas Gilbert 0); 3661481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3662481b5e5cSDouglas Gilbert goto err_out_unlock; 3663481b5e5cSDouglas Gilbert } 3664481b5e5cSDouglas Gilbert 3665481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3666481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3667481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3668481b5e5cSDouglas Gilbert ei_lba); 3669481b5e5cSDouglas Gilbert 3670481b5e5cSDouglas Gilbert if (prot_ret) { 3671481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3672481b5e5cSDouglas Gilbert prot_ret); 3673481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3674481b5e5cSDouglas Gilbert goto err_out_unlock; 3675481b5e5cSDouglas Gilbert } 3676481b5e5cSDouglas Gilbert } 3677481b5e5cSDouglas Gilbert 367887c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3679f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3680f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3681f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 3682481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 368387c715dcSDouglas Gilbert map_region(sip, lba, num); 3684481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3685481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3686481b5e5cSDouglas Gilbert goto err_out_unlock; 3687481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3688481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3689481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3690481b5e5cSDouglas Gilbert my_name, num_by, ret); 3691481b5e5cSDouglas Gilbert 36923a90a63dSDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_RECOV_DIF_DIX) && 36933a90a63dSDouglas Gilbert atomic_read(&sdeb_inject_pending))) { 36943a90a63dSDouglas Gilbert if (sdebug_opts & SDEBUG_OPT_RECOVERED_ERR) { 36953a90a63dSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, THRESHOLD_EXCEEDED, 0); 36963a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 36973a90a63dSDouglas Gilbert ret = check_condition_result; 3698481b5e5cSDouglas Gilbert goto err_out_unlock; 36993a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIF_ERR) { 3700481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 37013a90a63dSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 37023a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3703481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3704481b5e5cSDouglas Gilbert goto err_out_unlock; 37053a90a63dSDouglas Gilbert } else if (sdebug_opts & SDEBUG_OPT_DIX_ERR) { 37063a90a63dSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 37073a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 3708481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3709481b5e5cSDouglas Gilbert goto err_out_unlock; 3710481b5e5cSDouglas Gilbert } 3711481b5e5cSDouglas Gilbert } 3712481b5e5cSDouglas Gilbert sg_off += num_by; 3713481b5e5cSDouglas Gilbert cum_lb += num; 3714481b5e5cSDouglas Gilbert } 3715481b5e5cSDouglas Gilbert ret = 0; 3716481b5e5cSDouglas Gilbert err_out_unlock: 371767da413fSDouglas Gilbert write_unlock(macc_lckp); 3718481b5e5cSDouglas Gilbert err_out: 3719481b5e5cSDouglas Gilbert kfree(lrdp); 3720481b5e5cSDouglas Gilbert return ret; 3721481b5e5cSDouglas Gilbert } 3722481b5e5cSDouglas Gilbert 3723fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3724fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 372544d92694SMartin K. Petersen { 3726f0d1cf93SDouglas Gilbert struct scsi_device *sdp = scp->device; 3727f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip = (struct sdebug_dev_info *)sdp->hostdata; 372844d92694SMartin K. Petersen unsigned long long i; 372940d07b52SDouglas Gilbert u64 block, lbaa; 373087c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 373187c715dcSDouglas Gilbert int ret; 373287c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 3733b6ff8ca7SDouglas Gilbert scp->device->hostdata, true); 3734b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 373540d07b52SDouglas Gilbert u8 *fs1p; 373687c715dcSDouglas Gilbert u8 *fsp; 373744d92694SMartin K. Petersen 373867da413fSDouglas Gilbert write_lock(macc_lckp); 373944d92694SMartin K. Petersen 3740f0d1cf93SDouglas Gilbert ret = check_device_access_params(scp, lba, num, true); 3741f0d1cf93SDouglas Gilbert if (ret) { 3742f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 3743f0d1cf93SDouglas Gilbert return ret; 3744f0d1cf93SDouglas Gilbert } 3745f0d1cf93SDouglas Gilbert 37469ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 374787c715dcSDouglas Gilbert unmap_region(sip, lba, num); 374844d92694SMartin K. Petersen goto out; 374944d92694SMartin K. Petersen } 375040d07b52SDouglas Gilbert lbaa = lba; 375140d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3752c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 375387c715dcSDouglas Gilbert fsp = sip->storep; 375487c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3755c2248fc9SDouglas Gilbert if (ndob) { 375640d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3757c2248fc9SDouglas Gilbert ret = 0; 3758c2248fc9SDouglas Gilbert } else 375940d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 376044d92694SMartin K. Petersen 376144d92694SMartin K. Petersen if (-1 == ret) { 376267da413fSDouglas Gilbert write_unlock(&sip->macc_lck); 3763773642d9SDouglas Gilbert return DID_ERROR << 16; 376440d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3765c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3766e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 376740d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 376844d92694SMartin K. Petersen 376944d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 377040d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 377140d07b52SDouglas Gilbert lbaa = lba + i; 377240d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 377387c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 377440d07b52SDouglas Gilbert } 37759ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 377687c715dcSDouglas Gilbert map_region(sip, lba, num); 3777f0d1cf93SDouglas Gilbert /* If ZBC zone then bump its write pointer */ 3778f0d1cf93SDouglas Gilbert if (sdebug_dev_is_zoned(devip)) 3779f0d1cf93SDouglas Gilbert zbc_inc_wp(devip, lba, num); 378044d92694SMartin K. Petersen out: 378167da413fSDouglas Gilbert write_unlock(macc_lckp); 378244d92694SMartin K. Petersen 378344d92694SMartin K. Petersen return 0; 378444d92694SMartin K. Petersen } 378544d92694SMartin K. Petersen 3786fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3787fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3788c2248fc9SDouglas Gilbert { 3789c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3790c2248fc9SDouglas Gilbert u32 lba; 3791c2248fc9SDouglas Gilbert u16 num; 3792c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3793c2248fc9SDouglas Gilbert bool unmap = false; 3794c2248fc9SDouglas Gilbert 3795c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3796773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3797c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3798c2248fc9SDouglas Gilbert return check_condition_result; 3799c2248fc9SDouglas Gilbert } else 3800c2248fc9SDouglas Gilbert unmap = true; 3801c2248fc9SDouglas Gilbert } 3802c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3803c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3804773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3805c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3806c2248fc9SDouglas Gilbert return check_condition_result; 3807c2248fc9SDouglas Gilbert } 3808c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3809c2248fc9SDouglas Gilbert } 3810c2248fc9SDouglas Gilbert 3811fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3812fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3813c2248fc9SDouglas Gilbert { 3814c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3815c2248fc9SDouglas Gilbert u64 lba; 3816c2248fc9SDouglas Gilbert u32 num; 3817c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3818c2248fc9SDouglas Gilbert bool unmap = false; 3819c2248fc9SDouglas Gilbert bool ndob = false; 3820c2248fc9SDouglas Gilbert 3821c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3822773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3823c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3824c2248fc9SDouglas Gilbert return check_condition_result; 3825c2248fc9SDouglas Gilbert } else 3826c2248fc9SDouglas Gilbert unmap = true; 3827c2248fc9SDouglas Gilbert } 3828c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3829c2248fc9SDouglas Gilbert ndob = true; 3830c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3831c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3832773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3833c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3834c2248fc9SDouglas Gilbert return check_condition_result; 3835c2248fc9SDouglas Gilbert } 3836c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3837c2248fc9SDouglas Gilbert } 3838c2248fc9SDouglas Gilbert 3839acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3840acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3841acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3842fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3843fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3844acafd0b9SEwan D. Milne { 3845acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3846acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3847acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3848acafd0b9SEwan D. Milne u8 mode; 3849acafd0b9SEwan D. Milne 3850acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3851acafd0b9SEwan D. Milne switch (mode) { 3852acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3853acafd0b9SEwan D. Milne /* set UAs on this device only */ 3854acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3855acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3856acafd0b9SEwan D. Milne break; 3857acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3858acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3859acafd0b9SEwan D. Milne break; 3860acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3861acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3862acafd0b9SEwan D. Milne list_for_each_entry(dp, 3863acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3864acafd0b9SEwan D. Milne dev_list) 3865acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3866acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3867acafd0b9SEwan D. Milne if (devip != dp) 3868acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3869acafd0b9SEwan D. Milne dp->uas_bm); 3870acafd0b9SEwan D. Milne } 3871acafd0b9SEwan D. Milne break; 3872acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3873acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3874acafd0b9SEwan D. Milne list_for_each_entry(dp, 3875acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3876acafd0b9SEwan D. Milne dev_list) 3877acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3878acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3879acafd0b9SEwan D. Milne dp->uas_bm); 3880acafd0b9SEwan D. Milne break; 3881acafd0b9SEwan D. Milne default: 3882acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3883acafd0b9SEwan D. Milne break; 3884acafd0b9SEwan D. Milne } 3885acafd0b9SEwan D. Milne return 0; 3886acafd0b9SEwan D. Milne } 3887acafd0b9SEwan D. Milne 3888fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3889fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 389038d5c833SDouglas Gilbert { 389138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 389238d5c833SDouglas Gilbert u8 *arr; 3893b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3894b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 389538d5c833SDouglas Gilbert u64 lba; 389638d5c833SDouglas Gilbert u32 dnum; 3897773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 389838d5c833SDouglas Gilbert u8 num; 389938d5c833SDouglas Gilbert int ret; 3900d467d31fSDouglas Gilbert int retval = 0; 390138d5c833SDouglas Gilbert 3902d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 390338d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 390438d5c833SDouglas Gilbert if (0 == num) 390538d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 39068475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 390738d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 390838d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 390938d5c833SDouglas Gilbert return check_condition_result; 391038d5c833SDouglas Gilbert } 39118475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 39128475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 391338d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 391438d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 391538d5c833SDouglas Gilbert "to DIF device\n"); 39169447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 39179447b6ceSMartin K. Petersen if (ret) 39189447b6ceSMartin K. Petersen return ret; 3919d467d31fSDouglas Gilbert dnum = 2 * num; 39206396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 3921d467d31fSDouglas Gilbert if (NULL == arr) { 3922d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3923d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3924d467d31fSDouglas Gilbert return check_condition_result; 3925d467d31fSDouglas Gilbert } 392638d5c833SDouglas Gilbert 392767da413fSDouglas Gilbert write_lock(macc_lckp); 392838d5c833SDouglas Gilbert 392987c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 393038d5c833SDouglas Gilbert if (ret == -1) { 3931d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3932d467d31fSDouglas Gilbert goto cleanup; 3933773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 393438d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 393538d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 393638d5c833SDouglas Gilbert dnum * lb_size, ret); 3937c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 393838d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3939d467d31fSDouglas Gilbert retval = check_condition_result; 3940d467d31fSDouglas Gilbert goto cleanup; 394138d5c833SDouglas Gilbert } 394238d5c833SDouglas Gilbert if (scsi_debug_lbp()) 394387c715dcSDouglas Gilbert map_region(sip, lba, num); 3944d467d31fSDouglas Gilbert cleanup: 394567da413fSDouglas Gilbert write_unlock(macc_lckp); 3946d467d31fSDouglas Gilbert kfree(arr); 3947d467d31fSDouglas Gilbert return retval; 394838d5c833SDouglas Gilbert } 394938d5c833SDouglas Gilbert 395044d92694SMartin K. Petersen struct unmap_block_desc { 395144d92694SMartin K. Petersen __be64 lba; 395244d92694SMartin K. Petersen __be32 blocks; 395344d92694SMartin K. Petersen __be32 __reserved; 395444d92694SMartin K. Petersen }; 395544d92694SMartin K. Petersen 3956fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 395744d92694SMartin K. Petersen { 395844d92694SMartin K. Petersen unsigned char *buf; 395944d92694SMartin K. Petersen struct unmap_block_desc *desc; 3960b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 3961b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 396244d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 396344d92694SMartin K. Petersen int ret; 396444d92694SMartin K. Petersen 3965c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3966c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3967c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3968c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 396944d92694SMartin K. Petersen 397044d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3971773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3972c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 397344d92694SMartin K. Petersen return check_condition_result; 3974c2248fc9SDouglas Gilbert } 397544d92694SMartin K. Petersen 3976b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3977c2248fc9SDouglas Gilbert if (!buf) { 3978c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3979c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3980c2248fc9SDouglas Gilbert return check_condition_result; 3981c2248fc9SDouglas Gilbert } 3982c2248fc9SDouglas Gilbert 3983c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 398444d92694SMartin K. Petersen 398544d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 398644d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 398744d92694SMartin K. Petersen 398844d92694SMartin K. Petersen desc = (void *)&buf[8]; 398944d92694SMartin K. Petersen 399067da413fSDouglas Gilbert write_lock(macc_lckp); 39916c78cc06SAkinobu Mita 399244d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 399344d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 399444d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 399544d92694SMartin K. Petersen 39969447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 399744d92694SMartin K. Petersen if (ret) 399844d92694SMartin K. Petersen goto out; 399944d92694SMartin K. Petersen 400087c715dcSDouglas Gilbert unmap_region(sip, lba, num); 400144d92694SMartin K. Petersen } 400244d92694SMartin K. Petersen 400344d92694SMartin K. Petersen ret = 0; 400444d92694SMartin K. Petersen 400544d92694SMartin K. Petersen out: 400667da413fSDouglas Gilbert write_unlock(macc_lckp); 400744d92694SMartin K. Petersen kfree(buf); 400844d92694SMartin K. Petersen 400944d92694SMartin K. Petersen return ret; 401044d92694SMartin K. Petersen } 401144d92694SMartin K. Petersen 401244d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 401344d92694SMartin K. Petersen 4014fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 4015fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 401644d92694SMartin K. Petersen { 4017c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4018c2248fc9SDouglas Gilbert u64 lba; 4019c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 402044d92694SMartin K. Petersen int ret; 402187c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 402244d92694SMartin K. Petersen 4023c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4024c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 402544d92694SMartin K. Petersen 402644d92694SMartin K. Petersen if (alloc_len < 24) 402744d92694SMartin K. Petersen return 0; 402844d92694SMartin K. Petersen 40299447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 403044d92694SMartin K. Petersen if (ret) 403144d92694SMartin K. Petersen return ret; 403244d92694SMartin K. Petersen 4033b6ff8ca7SDouglas Gilbert if (scsi_debug_lbp()) { 4034b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4035b6ff8ca7SDouglas Gilbert 403687c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 4037b6ff8ca7SDouglas Gilbert } else { 4038c2248fc9SDouglas Gilbert mapped = 1; 4039c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 4040c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 4041c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 4042c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 4043c2248fc9SDouglas Gilbert else 4044c2248fc9SDouglas Gilbert num = 0xffffffff; 4045c2248fc9SDouglas Gilbert } 404644d92694SMartin K. Petersen 404744d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 4048c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 4049c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 4050c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 4051c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 405244d92694SMartin K. Petersen 4053c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 405444d92694SMartin K. Petersen } 405544d92694SMartin K. Petersen 405680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 405780c49563SDouglas Gilbert struct sdebug_dev_info *devip) 405880c49563SDouglas Gilbert { 40594f2c8bf6SDouglas Gilbert int res = 0; 406080c49563SDouglas Gilbert u64 lba; 406180c49563SDouglas Gilbert u32 num_blocks; 406280c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 406380c49563SDouglas Gilbert 406480c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 406580c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 406680c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 406780c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 406880c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 406980c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 407080c49563SDouglas Gilbert } 407180c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 407280c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 407380c49563SDouglas Gilbert return check_condition_result; 407480c49563SDouglas Gilbert } 4075fc13638aSDouglas Gilbert if (!write_since_sync || (cmd[1] & 0x2)) 40764f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 40774f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 40784f2c8bf6SDouglas Gilbert write_since_sync = false; 40794f2c8bf6SDouglas Gilbert return res; 408080c49563SDouglas Gilbert } 408180c49563SDouglas Gilbert 4082ed9f3e25SDouglas Gilbert /* 4083ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 4084ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 4085ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 4086ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 4087ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 4088ed9f3e25SDouglas Gilbert */ 4089ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 4090ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 4091ed9f3e25SDouglas Gilbert { 4092ed9f3e25SDouglas Gilbert int res = 0; 4093ed9f3e25SDouglas Gilbert u64 lba; 4094ed9f3e25SDouglas Gilbert u64 block, rest = 0; 4095ed9f3e25SDouglas Gilbert u32 nblks; 4096ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 4097b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4098b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4099b6ff8ca7SDouglas Gilbert u8 *fsp = sip->storep; 4100ed9f3e25SDouglas Gilbert 4101ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 4102ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4103ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 4104ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 4105ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4106ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 4107ed9f3e25SDouglas Gilbert } 4108ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 4109ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4110ed9f3e25SDouglas Gilbert return check_condition_result; 4111ed9f3e25SDouglas Gilbert } 4112ed9f3e25SDouglas Gilbert if (!fsp) 4113ed9f3e25SDouglas Gilbert goto fini; 4114ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 4115ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 4116ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 4117ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 4118ed9f3e25SDouglas Gilbert 4119ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 4120ed9f3e25SDouglas Gilbert read_lock(macc_lckp); 4121ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 4122ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 4123ed9f3e25SDouglas Gilbert if (rest) 4124ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 4125ed9f3e25SDouglas Gilbert read_unlock(macc_lckp); 4126ed9f3e25SDouglas Gilbert fini: 4127ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 4128ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 4129ed9f3e25SDouglas Gilbert return res | condition_met_result; 4130ed9f3e25SDouglas Gilbert } 4131ed9f3e25SDouglas Gilbert 4132fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 4133fb0cc8d1SDouglas Gilbert 41348d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 41358d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 41368d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 41378d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 41388d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 41398d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 41408d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 41418d039e22SDouglas Gilbert */ 41421da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 41431da177e4SLinus Torvalds struct sdebug_dev_info *devip) 41441da177e4SLinus Torvalds { 414501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 41468d039e22SDouglas Gilbert unsigned int alloc_len; 41478d039e22SDouglas Gilbert unsigned char select_report; 41488d039e22SDouglas Gilbert u64 lun; 41498d039e22SDouglas Gilbert struct scsi_lun *lun_p; 4150fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 41518d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 41528d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 41538d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 41548d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 4155fb0cc8d1SDouglas Gilbert int k, j, n, res; 4156fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 4157fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 41581da177e4SLinus Torvalds 415919c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 41608d039e22SDouglas Gilbert 41618d039e22SDouglas Gilbert select_report = cmd[2]; 41628d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 41638d039e22SDouglas Gilbert 41648d039e22SDouglas Gilbert if (alloc_len < 4) { 41658d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 41668d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 41671da177e4SLinus Torvalds return check_condition_result; 41681da177e4SLinus Torvalds } 41698d039e22SDouglas Gilbert 41708d039e22SDouglas Gilbert switch (select_report) { 41718d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 4172773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 41738d039e22SDouglas Gilbert wlun_cnt = 0; 41748d039e22SDouglas Gilbert break; 41758d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 4176c65b1445SDouglas Gilbert lun_cnt = 0; 41778d039e22SDouglas Gilbert wlun_cnt = 1; 41788d039e22SDouglas Gilbert break; 41798d039e22SDouglas Gilbert case 2: /* all LUNs */ 41808d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 41818d039e22SDouglas Gilbert wlun_cnt = 1; 41828d039e22SDouglas Gilbert break; 41838d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 41848d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 41858d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 41868d039e22SDouglas Gilbert default: 41878d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 41888d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 41898d039e22SDouglas Gilbert return check_condition_result; 41908d039e22SDouglas Gilbert } 41918d039e22SDouglas Gilbert 41928d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 4193c65b1445SDouglas Gilbert --lun_cnt; 41948d039e22SDouglas Gilbert 41958d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 4196fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 4197fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 41988d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 41998d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 42008d039e22SDouglas Gilbert 4201fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 42028d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 4203fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 4204fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 4205fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 4206fb0cc8d1SDouglas Gilbert if (k == 0) { 4207fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 4208fb0cc8d1SDouglas Gilbert ++lun_p; 4209fb0cc8d1SDouglas Gilbert j = 1; 4210fb0cc8d1SDouglas Gilbert } 4211fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 4212fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 4213fb0cc8d1SDouglas Gilbert break; 4214fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 4215ad0c7775SDouglas Gilbert if (lun > 1 && sdebug_lun_am == SAM_LUN_AM_FLAT) 4216ad0c7775SDouglas Gilbert lun_p->scsi_lun[0] |= 0x40; 4217fb0cc8d1SDouglas Gilbert } 4218fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 4219fb0cc8d1SDouglas Gilbert break; 4220fb0cc8d1SDouglas Gilbert n = j * sz_lun; 4221fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 4222fb0cc8d1SDouglas Gilbert if (res) 4223fb0cc8d1SDouglas Gilbert return res; 4224fb0cc8d1SDouglas Gilbert off_rsp += n; 4225fb0cc8d1SDouglas Gilbert } 4226fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 4227fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 4228fb0cc8d1SDouglas Gilbert ++j; 4229fb0cc8d1SDouglas Gilbert } 4230fb0cc8d1SDouglas Gilbert if (j > 0) 4231fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 42328d039e22SDouglas Gilbert return res; 42331da177e4SLinus Torvalds } 42341da177e4SLinus Torvalds 4235c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4236c3e2fe92SDouglas Gilbert { 4237c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 4238c3e2fe92SDouglas Gilbert u8 bytchk; 4239c3e2fe92SDouglas Gilbert int ret, j; 4240c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 4241c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 4242c3e2fe92SDouglas Gilbert u64 lba; 4243c3e2fe92SDouglas Gilbert u8 *arr; 4244c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 4245b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, true); 4246b6ff8ca7SDouglas Gilbert rwlock_t *macc_lckp = &sip->macc_lck; 4247c3e2fe92SDouglas Gilbert 4248c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 4249c3e2fe92SDouglas Gilbert if (bytchk == 0) { 4250c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 4251c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 4252c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 4253c3e2fe92SDouglas Gilbert return check_condition_result; 4254c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 4255c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 4256c3e2fe92SDouglas Gilbert } 4257c3e2fe92SDouglas Gilbert switch (cmd[0]) { 4258c3e2fe92SDouglas Gilbert case VERIFY_16: 4259c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 4260c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 4261c3e2fe92SDouglas Gilbert break; 4262c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 4263c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 4264c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 4265c3e2fe92SDouglas Gilbert break; 4266c3e2fe92SDouglas Gilbert default: 4267c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 4268c3e2fe92SDouglas Gilbert return check_condition_result; 4269c3e2fe92SDouglas Gilbert } 42703344b58bSGeorge Kennedy if (vnum == 0) 42713344b58bSGeorge Kennedy return 0; /* not an error */ 4272c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 4273c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 4274c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 4275c3e2fe92SDouglas Gilbert if (ret) 4276c3e2fe92SDouglas Gilbert return ret; 4277c3e2fe92SDouglas Gilbert 4278c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 4279c3e2fe92SDouglas Gilbert if (!arr) { 4280c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4281c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 4282c3e2fe92SDouglas Gilbert return check_condition_result; 4283c3e2fe92SDouglas Gilbert } 4284c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 428567da413fSDouglas Gilbert read_lock(macc_lckp); 4286c3e2fe92SDouglas Gilbert 4287c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 4288c3e2fe92SDouglas Gilbert if (ret == -1) { 4289c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 4290c3e2fe92SDouglas Gilbert goto cleanup; 4291c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 4292c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 4293c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 4294c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 4295c3e2fe92SDouglas Gilbert } 4296c3e2fe92SDouglas Gilbert if (is_bytchk3) { 4297c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 4298c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 4299c3e2fe92SDouglas Gilbert } 4300c3e2fe92SDouglas Gilbert ret = 0; 4301c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 4302c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 4303c3e2fe92SDouglas Gilbert ret = check_condition_result; 4304c3e2fe92SDouglas Gilbert goto cleanup; 4305c3e2fe92SDouglas Gilbert } 4306c3e2fe92SDouglas Gilbert cleanup: 430767da413fSDouglas Gilbert read_unlock(macc_lckp); 4308c3e2fe92SDouglas Gilbert kfree(arr); 4309c3e2fe92SDouglas Gilbert return ret; 4310c3e2fe92SDouglas Gilbert } 4311c3e2fe92SDouglas Gilbert 4312f0d1cf93SDouglas Gilbert #define RZONES_DESC_HD 64 4313f0d1cf93SDouglas Gilbert 4314f0d1cf93SDouglas Gilbert /* Report zones depending on start LBA nad reporting options */ 4315f0d1cf93SDouglas Gilbert static int resp_report_zones(struct scsi_cmnd *scp, 4316f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4317f0d1cf93SDouglas Gilbert { 4318f0d1cf93SDouglas Gilbert unsigned int i, max_zones, rep_max_zones, nrz = 0; 4319f0d1cf93SDouglas Gilbert int ret = 0; 4320f0d1cf93SDouglas Gilbert u32 alloc_len, rep_opts, rep_len; 4321f0d1cf93SDouglas Gilbert bool partial; 4322f0d1cf93SDouglas Gilbert u64 lba, zs_lba; 4323f0d1cf93SDouglas Gilbert u8 *arr = NULL, *desc; 4324f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4325f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4326b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4327f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4328f0d1cf93SDouglas Gilbert 4329f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4330f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4331f0d1cf93SDouglas Gilbert return check_condition_result; 4332f0d1cf93SDouglas Gilbert } 4333f0d1cf93SDouglas Gilbert zs_lba = get_unaligned_be64(cmd + 2); 4334f0d1cf93SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 43353344b58bSGeorge Kennedy if (alloc_len == 0) 43363344b58bSGeorge Kennedy return 0; /* not an error */ 4337f0d1cf93SDouglas Gilbert rep_opts = cmd[14] & 0x3f; 4338f0d1cf93SDouglas Gilbert partial = cmd[14] & 0x80; 4339f0d1cf93SDouglas Gilbert 4340f0d1cf93SDouglas Gilbert if (zs_lba >= sdebug_capacity) { 4341f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4342f0d1cf93SDouglas Gilbert return check_condition_result; 4343f0d1cf93SDouglas Gilbert } 4344f0d1cf93SDouglas Gilbert 4345108e36f0SDamien Le Moal max_zones = devip->nr_zones - (zs_lba >> devip->zsize_shift); 4346f0d1cf93SDouglas Gilbert rep_max_zones = min((alloc_len - 64) >> ilog2(RZONES_DESC_HD), 4347f0d1cf93SDouglas Gilbert max_zones); 4348f0d1cf93SDouglas Gilbert 43497db0e0c8SShin'ichiro Kawasaki arr = kzalloc(alloc_len, GFP_ATOMIC); 4350f0d1cf93SDouglas Gilbert if (!arr) { 4351f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 4352f0d1cf93SDouglas Gilbert INSUFF_RES_ASCQ); 4353f0d1cf93SDouglas Gilbert return check_condition_result; 4354f0d1cf93SDouglas Gilbert } 4355f0d1cf93SDouglas Gilbert 4356f0d1cf93SDouglas Gilbert read_lock(macc_lckp); 4357f0d1cf93SDouglas Gilbert 4358f0d1cf93SDouglas Gilbert desc = arr + 64; 4359f0d1cf93SDouglas Gilbert for (i = 0; i < max_zones; i++) { 4360f0d1cf93SDouglas Gilbert lba = zs_lba + devip->zsize * i; 4361f0d1cf93SDouglas Gilbert if (lba > sdebug_capacity) 4362f0d1cf93SDouglas Gilbert break; 4363f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, lba); 4364f0d1cf93SDouglas Gilbert switch (rep_opts) { 4365f0d1cf93SDouglas Gilbert case 0x00: 4366f0d1cf93SDouglas Gilbert /* All zones */ 4367f0d1cf93SDouglas Gilbert break; 4368f0d1cf93SDouglas Gilbert case 0x01: 4369f0d1cf93SDouglas Gilbert /* Empty zones */ 4370f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC1_EMPTY) 4371f0d1cf93SDouglas Gilbert continue; 4372f0d1cf93SDouglas Gilbert break; 4373f0d1cf93SDouglas Gilbert case 0x02: 4374f0d1cf93SDouglas Gilbert /* Implicit open zones */ 4375f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC2_IMPLICIT_OPEN) 4376f0d1cf93SDouglas Gilbert continue; 4377f0d1cf93SDouglas Gilbert break; 4378f0d1cf93SDouglas Gilbert case 0x03: 4379f0d1cf93SDouglas Gilbert /* Explicit open zones */ 4380f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC3_EXPLICIT_OPEN) 4381f0d1cf93SDouglas Gilbert continue; 4382f0d1cf93SDouglas Gilbert break; 4383f0d1cf93SDouglas Gilbert case 0x04: 4384f0d1cf93SDouglas Gilbert /* Closed zones */ 4385f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC4_CLOSED) 4386f0d1cf93SDouglas Gilbert continue; 4387f0d1cf93SDouglas Gilbert break; 4388f0d1cf93SDouglas Gilbert case 0x05: 4389f0d1cf93SDouglas Gilbert /* Full zones */ 4390f0d1cf93SDouglas Gilbert if (zsp->z_cond != ZC5_FULL) 4391f0d1cf93SDouglas Gilbert continue; 4392f0d1cf93SDouglas Gilbert break; 4393f0d1cf93SDouglas Gilbert case 0x06: 4394f0d1cf93SDouglas Gilbert case 0x07: 4395f0d1cf93SDouglas Gilbert case 0x10: 4396f0d1cf93SDouglas Gilbert /* 439764e14eceSDamien Le Moal * Read-only, offline, reset WP recommended are 439864e14eceSDamien Le Moal * not emulated: no zones to report; 4399f0d1cf93SDouglas Gilbert */ 4400f0d1cf93SDouglas Gilbert continue; 440164e14eceSDamien Le Moal case 0x11: 440264e14eceSDamien Le Moal /* non-seq-resource set */ 440364e14eceSDamien Le Moal if (!zsp->z_non_seq_resource) 440464e14eceSDamien Le Moal continue; 440564e14eceSDamien Le Moal break; 4406f0d1cf93SDouglas Gilbert case 0x3f: 4407f0d1cf93SDouglas Gilbert /* Not write pointer (conventional) zones */ 4408f0d1cf93SDouglas Gilbert if (!zbc_zone_is_conv(zsp)) 4409f0d1cf93SDouglas Gilbert continue; 4410f0d1cf93SDouglas Gilbert break; 4411f0d1cf93SDouglas Gilbert default: 4412f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 4413f0d1cf93SDouglas Gilbert INVALID_FIELD_IN_CDB, 0); 4414f0d1cf93SDouglas Gilbert ret = check_condition_result; 4415f0d1cf93SDouglas Gilbert goto fini; 4416f0d1cf93SDouglas Gilbert } 4417f0d1cf93SDouglas Gilbert 4418f0d1cf93SDouglas Gilbert if (nrz < rep_max_zones) { 4419f0d1cf93SDouglas Gilbert /* Fill zone descriptor */ 442064e14eceSDamien Le Moal desc[0] = zsp->z_type; 4421f0d1cf93SDouglas Gilbert desc[1] = zsp->z_cond << 4; 442264e14eceSDamien Le Moal if (zsp->z_non_seq_resource) 442364e14eceSDamien Le Moal desc[1] |= 1 << 1; 4424f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_size, desc + 8); 4425f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_start, desc + 16); 4426f0d1cf93SDouglas Gilbert put_unaligned_be64((u64)zsp->z_wp, desc + 24); 4427f0d1cf93SDouglas Gilbert desc += 64; 4428f0d1cf93SDouglas Gilbert } 4429f0d1cf93SDouglas Gilbert 4430f0d1cf93SDouglas Gilbert if (partial && nrz >= rep_max_zones) 4431f0d1cf93SDouglas Gilbert break; 4432f0d1cf93SDouglas Gilbert 4433f0d1cf93SDouglas Gilbert nrz++; 4434f0d1cf93SDouglas Gilbert } 4435f0d1cf93SDouglas Gilbert 4436f0d1cf93SDouglas Gilbert /* Report header */ 4437f0d1cf93SDouglas Gilbert put_unaligned_be32(nrz * RZONES_DESC_HD, arr + 0); 4438f0d1cf93SDouglas Gilbert put_unaligned_be64(sdebug_capacity - 1, arr + 8); 4439f0d1cf93SDouglas Gilbert 4440f0d1cf93SDouglas Gilbert rep_len = (unsigned long)desc - (unsigned long)arr; 444136e07d7eSGeorge Kennedy ret = fill_from_dev_buffer(scp, arr, min_t(u32, alloc_len, rep_len)); 4442f0d1cf93SDouglas Gilbert 4443f0d1cf93SDouglas Gilbert fini: 4444f0d1cf93SDouglas Gilbert read_unlock(macc_lckp); 4445f0d1cf93SDouglas Gilbert kfree(arr); 4446f0d1cf93SDouglas Gilbert return ret; 4447f0d1cf93SDouglas Gilbert } 4448f0d1cf93SDouglas Gilbert 4449f0d1cf93SDouglas Gilbert /* Logic transplanted from tcmu-runner, file_zbc.c */ 4450f0d1cf93SDouglas Gilbert static void zbc_open_all(struct sdebug_dev_info *devip) 4451f0d1cf93SDouglas Gilbert { 4452f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp = &devip->zstate[0]; 4453f0d1cf93SDouglas Gilbert unsigned int i; 4454f0d1cf93SDouglas Gilbert 4455f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++, zsp++) { 4456f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4457f0d1cf93SDouglas Gilbert zbc_open_zone(devip, &devip->zstate[i], true); 4458f0d1cf93SDouglas Gilbert } 4459f0d1cf93SDouglas Gilbert } 4460f0d1cf93SDouglas Gilbert 4461f0d1cf93SDouglas Gilbert static int resp_open_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4462f0d1cf93SDouglas Gilbert { 4463f0d1cf93SDouglas Gilbert int res = 0; 4464f0d1cf93SDouglas Gilbert u64 z_id; 4465f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 4466f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4467f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4468f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4469b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4470f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4471f0d1cf93SDouglas Gilbert 4472f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4473f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4474f0d1cf93SDouglas Gilbert return check_condition_result; 4475f0d1cf93SDouglas Gilbert } 4476f0d1cf93SDouglas Gilbert 4477f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4478f0d1cf93SDouglas Gilbert 4479f0d1cf93SDouglas Gilbert if (all) { 4480f0d1cf93SDouglas Gilbert /* Check if all closed zones can be open */ 4481f0d1cf93SDouglas Gilbert if (devip->max_open && 4482f0d1cf93SDouglas Gilbert devip->nr_exp_open + devip->nr_closed > devip->max_open) { 4483f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4484f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4485f0d1cf93SDouglas Gilbert res = check_condition_result; 4486f0d1cf93SDouglas Gilbert goto fini; 4487f0d1cf93SDouglas Gilbert } 4488f0d1cf93SDouglas Gilbert /* Open all closed zones */ 4489f0d1cf93SDouglas Gilbert zbc_open_all(devip); 4490f0d1cf93SDouglas Gilbert goto fini; 4491f0d1cf93SDouglas Gilbert } 4492f0d1cf93SDouglas Gilbert 4493f0d1cf93SDouglas Gilbert /* Open the specified zone */ 4494f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4495f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4496f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4497f0d1cf93SDouglas Gilbert res = check_condition_result; 4498f0d1cf93SDouglas Gilbert goto fini; 4499f0d1cf93SDouglas Gilbert } 4500f0d1cf93SDouglas Gilbert 4501f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4502f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4503f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4504f0d1cf93SDouglas Gilbert res = check_condition_result; 4505f0d1cf93SDouglas Gilbert goto fini; 4506f0d1cf93SDouglas Gilbert } 4507f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4508f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4509f0d1cf93SDouglas Gilbert res = check_condition_result; 4510f0d1cf93SDouglas Gilbert goto fini; 4511f0d1cf93SDouglas Gilbert } 4512f0d1cf93SDouglas Gilbert 4513f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4514f0d1cf93SDouglas Gilbert if (zc == ZC3_EXPLICIT_OPEN || zc == ZC5_FULL) 4515f0d1cf93SDouglas Gilbert goto fini; 4516f0d1cf93SDouglas Gilbert 4517f0d1cf93SDouglas Gilbert if (devip->max_open && devip->nr_exp_open >= devip->max_open) { 4518f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, DATA_PROTECT, INSUFF_RES_ASC, 4519f0d1cf93SDouglas Gilbert INSUFF_ZONE_ASCQ); 4520f0d1cf93SDouglas Gilbert res = check_condition_result; 4521f0d1cf93SDouglas Gilbert goto fini; 4522f0d1cf93SDouglas Gilbert } 4523f0d1cf93SDouglas Gilbert 4524f0d1cf93SDouglas Gilbert zbc_open_zone(devip, zsp, true); 4525f0d1cf93SDouglas Gilbert fini: 4526f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4527f0d1cf93SDouglas Gilbert return res; 4528f0d1cf93SDouglas Gilbert } 4529f0d1cf93SDouglas Gilbert 4530f0d1cf93SDouglas Gilbert static void zbc_close_all(struct sdebug_dev_info *devip) 4531f0d1cf93SDouglas Gilbert { 4532f0d1cf93SDouglas Gilbert unsigned int i; 4533f0d1cf93SDouglas Gilbert 4534f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4535f0d1cf93SDouglas Gilbert zbc_close_zone(devip, &devip->zstate[i]); 4536f0d1cf93SDouglas Gilbert } 4537f0d1cf93SDouglas Gilbert 4538f0d1cf93SDouglas Gilbert static int resp_close_zone(struct scsi_cmnd *scp, 4539f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4540f0d1cf93SDouglas Gilbert { 4541f0d1cf93SDouglas Gilbert int res = 0; 4542f0d1cf93SDouglas Gilbert u64 z_id; 4543f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4544f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4545f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4546b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4547f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4548f0d1cf93SDouglas Gilbert 4549f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4550f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4551f0d1cf93SDouglas Gilbert return check_condition_result; 4552f0d1cf93SDouglas Gilbert } 4553f0d1cf93SDouglas Gilbert 4554f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4555f0d1cf93SDouglas Gilbert 4556f0d1cf93SDouglas Gilbert if (all) { 4557f0d1cf93SDouglas Gilbert zbc_close_all(devip); 4558f0d1cf93SDouglas Gilbert goto fini; 4559f0d1cf93SDouglas Gilbert } 4560f0d1cf93SDouglas Gilbert 4561f0d1cf93SDouglas Gilbert /* Close specified zone */ 4562f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4563f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4564f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4565f0d1cf93SDouglas Gilbert res = check_condition_result; 4566f0d1cf93SDouglas Gilbert goto fini; 4567f0d1cf93SDouglas Gilbert } 4568f0d1cf93SDouglas Gilbert 4569f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4570f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4571f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4572f0d1cf93SDouglas Gilbert res = check_condition_result; 4573f0d1cf93SDouglas Gilbert goto fini; 4574f0d1cf93SDouglas Gilbert } 4575f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4576f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4577f0d1cf93SDouglas Gilbert res = check_condition_result; 4578f0d1cf93SDouglas Gilbert goto fini; 4579f0d1cf93SDouglas Gilbert } 4580f0d1cf93SDouglas Gilbert 4581f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4582f0d1cf93SDouglas Gilbert fini: 4583f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4584f0d1cf93SDouglas Gilbert return res; 4585f0d1cf93SDouglas Gilbert } 4586f0d1cf93SDouglas Gilbert 4587f0d1cf93SDouglas Gilbert static void zbc_finish_zone(struct sdebug_dev_info *devip, 4588f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp, bool empty) 4589f0d1cf93SDouglas Gilbert { 4590f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc = zsp->z_cond; 4591f0d1cf93SDouglas Gilbert 4592f0d1cf93SDouglas Gilbert if (zc == ZC4_CLOSED || zc == ZC2_IMPLICIT_OPEN || 4593f0d1cf93SDouglas Gilbert zc == ZC3_EXPLICIT_OPEN || (empty && zc == ZC1_EMPTY)) { 4594f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4595f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4596f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4597f0d1cf93SDouglas Gilbert devip->nr_closed--; 4598f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start + zsp->z_size; 4599f0d1cf93SDouglas Gilbert zsp->z_cond = ZC5_FULL; 4600f0d1cf93SDouglas Gilbert } 4601f0d1cf93SDouglas Gilbert } 4602f0d1cf93SDouglas Gilbert 4603f0d1cf93SDouglas Gilbert static void zbc_finish_all(struct sdebug_dev_info *devip) 4604f0d1cf93SDouglas Gilbert { 4605f0d1cf93SDouglas Gilbert unsigned int i; 4606f0d1cf93SDouglas Gilbert 4607f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4608f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, &devip->zstate[i], false); 4609f0d1cf93SDouglas Gilbert } 4610f0d1cf93SDouglas Gilbert 4611f0d1cf93SDouglas Gilbert static int resp_finish_zone(struct scsi_cmnd *scp, 4612f0d1cf93SDouglas Gilbert struct sdebug_dev_info *devip) 4613f0d1cf93SDouglas Gilbert { 4614f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4615f0d1cf93SDouglas Gilbert int res = 0; 4616f0d1cf93SDouglas Gilbert u64 z_id; 4617f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4618f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4619b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4620f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4621f0d1cf93SDouglas Gilbert 4622f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4623f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4624f0d1cf93SDouglas Gilbert return check_condition_result; 4625f0d1cf93SDouglas Gilbert } 4626f0d1cf93SDouglas Gilbert 4627f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4628f0d1cf93SDouglas Gilbert 4629f0d1cf93SDouglas Gilbert if (all) { 4630f0d1cf93SDouglas Gilbert zbc_finish_all(devip); 4631f0d1cf93SDouglas Gilbert goto fini; 4632f0d1cf93SDouglas Gilbert } 4633f0d1cf93SDouglas Gilbert 4634f0d1cf93SDouglas Gilbert /* Finish the specified zone */ 4635f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4636f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4637f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4638f0d1cf93SDouglas Gilbert res = check_condition_result; 4639f0d1cf93SDouglas Gilbert goto fini; 4640f0d1cf93SDouglas Gilbert } 4641f0d1cf93SDouglas Gilbert 4642f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4643f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4644f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4645f0d1cf93SDouglas Gilbert res = check_condition_result; 4646f0d1cf93SDouglas Gilbert goto fini; 4647f0d1cf93SDouglas Gilbert } 4648f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4649f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4650f0d1cf93SDouglas Gilbert res = check_condition_result; 4651f0d1cf93SDouglas Gilbert goto fini; 4652f0d1cf93SDouglas Gilbert } 4653f0d1cf93SDouglas Gilbert 4654f0d1cf93SDouglas Gilbert zbc_finish_zone(devip, zsp, true); 4655f0d1cf93SDouglas Gilbert fini: 4656f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4657f0d1cf93SDouglas Gilbert return res; 4658f0d1cf93SDouglas Gilbert } 4659f0d1cf93SDouglas Gilbert 4660f0d1cf93SDouglas Gilbert static void zbc_rwp_zone(struct sdebug_dev_info *devip, 4661f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp) 4662f0d1cf93SDouglas Gilbert { 4663f0d1cf93SDouglas Gilbert enum sdebug_z_cond zc; 46642d62253eSShin'ichiro Kawasaki struct sdeb_store_info *sip = devip2sip(devip, false); 4665f0d1cf93SDouglas Gilbert 4666f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) 4667f0d1cf93SDouglas Gilbert return; 4668f0d1cf93SDouglas Gilbert 4669f0d1cf93SDouglas Gilbert zc = zsp->z_cond; 4670f0d1cf93SDouglas Gilbert if (zc == ZC2_IMPLICIT_OPEN || zc == ZC3_EXPLICIT_OPEN) 4671f0d1cf93SDouglas Gilbert zbc_close_zone(devip, zsp); 4672f0d1cf93SDouglas Gilbert 4673f0d1cf93SDouglas Gilbert if (zsp->z_cond == ZC4_CLOSED) 4674f0d1cf93SDouglas Gilbert devip->nr_closed--; 4675f0d1cf93SDouglas Gilbert 46762d62253eSShin'ichiro Kawasaki if (zsp->z_wp > zsp->z_start) 46772d62253eSShin'ichiro Kawasaki memset(sip->storep + zsp->z_start * sdebug_sector_size, 0, 46782d62253eSShin'ichiro Kawasaki (zsp->z_wp - zsp->z_start) * sdebug_sector_size); 46792d62253eSShin'ichiro Kawasaki 468064e14eceSDamien Le Moal zsp->z_non_seq_resource = false; 4681f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4682f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4683f0d1cf93SDouglas Gilbert } 4684f0d1cf93SDouglas Gilbert 4685f0d1cf93SDouglas Gilbert static void zbc_rwp_all(struct sdebug_dev_info *devip) 4686f0d1cf93SDouglas Gilbert { 4687f0d1cf93SDouglas Gilbert unsigned int i; 4688f0d1cf93SDouglas Gilbert 4689f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) 4690f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, &devip->zstate[i]); 4691f0d1cf93SDouglas Gilbert } 4692f0d1cf93SDouglas Gilbert 4693f0d1cf93SDouglas Gilbert static int resp_rwp_zone(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 4694f0d1cf93SDouglas Gilbert { 4695f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4696f0d1cf93SDouglas Gilbert int res = 0; 4697f0d1cf93SDouglas Gilbert u64 z_id; 4698f0d1cf93SDouglas Gilbert u8 *cmd = scp->cmnd; 4699f0d1cf93SDouglas Gilbert bool all = cmd[14] & 0x01; 4700b6ff8ca7SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip, false); 4701f0d1cf93SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 4702f0d1cf93SDouglas Gilbert 4703f0d1cf93SDouglas Gilbert if (!sdebug_dev_is_zoned(devip)) { 4704f0d1cf93SDouglas Gilbert mk_sense_invalid_opcode(scp); 4705f0d1cf93SDouglas Gilbert return check_condition_result; 4706f0d1cf93SDouglas Gilbert } 4707f0d1cf93SDouglas Gilbert 4708f0d1cf93SDouglas Gilbert write_lock(macc_lckp); 4709f0d1cf93SDouglas Gilbert 4710f0d1cf93SDouglas Gilbert if (all) { 4711f0d1cf93SDouglas Gilbert zbc_rwp_all(devip); 4712f0d1cf93SDouglas Gilbert goto fini; 4713f0d1cf93SDouglas Gilbert } 4714f0d1cf93SDouglas Gilbert 4715f0d1cf93SDouglas Gilbert z_id = get_unaligned_be64(cmd + 2); 4716f0d1cf93SDouglas Gilbert if (z_id >= sdebug_capacity) { 4717f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 4718f0d1cf93SDouglas Gilbert res = check_condition_result; 4719f0d1cf93SDouglas Gilbert goto fini; 4720f0d1cf93SDouglas Gilbert } 4721f0d1cf93SDouglas Gilbert 4722f0d1cf93SDouglas Gilbert zsp = zbc_zone(devip, z_id); 4723f0d1cf93SDouglas Gilbert if (z_id != zsp->z_start) { 4724f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4725f0d1cf93SDouglas Gilbert res = check_condition_result; 4726f0d1cf93SDouglas Gilbert goto fini; 4727f0d1cf93SDouglas Gilbert } 4728f0d1cf93SDouglas Gilbert if (zbc_zone_is_conv(zsp)) { 4729f0d1cf93SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 4730f0d1cf93SDouglas Gilbert res = check_condition_result; 4731f0d1cf93SDouglas Gilbert goto fini; 4732f0d1cf93SDouglas Gilbert } 4733f0d1cf93SDouglas Gilbert 4734f0d1cf93SDouglas Gilbert zbc_rwp_zone(devip, zsp); 4735f0d1cf93SDouglas Gilbert fini: 4736f0d1cf93SDouglas Gilbert write_unlock(macc_lckp); 4737f0d1cf93SDouglas Gilbert return res; 4738f0d1cf93SDouglas Gilbert } 4739f0d1cf93SDouglas Gilbert 4740c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 4741c4837394SDouglas Gilbert { 4742c10fa55fSJohn Garry u16 hwq; 4743a6e76e6fSBart Van Assche u32 tag = blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4744c10fa55fSJohn Garry 4745c10fa55fSJohn Garry hwq = blk_mq_unique_tag_to_hwq(tag); 4746c4837394SDouglas Gilbert 4747458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 4748458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 4749458df78bSBart Van Assche hwq = 0; 4750f7c4cdc7SJohn Garry 4751458df78bSBart Van Assche return sdebug_q_arr + hwq; 4752c4837394SDouglas Gilbert } 4753c4837394SDouglas Gilbert 4754c10fa55fSJohn Garry static u32 get_tag(struct scsi_cmnd *cmnd) 4755c10fa55fSJohn Garry { 4756a6e76e6fSBart Van Assche return blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)); 4757c10fa55fSJohn Garry } 4758c10fa55fSJohn Garry 4759c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 4760fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 47611da177e4SLinus Torvalds { 47627382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 4763c4837394SDouglas Gilbert int qc_idx; 4764cbf67842SDouglas Gilbert int retiring = 0; 47651da177e4SLinus Torvalds unsigned long iflags; 4766c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4767cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4768cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 4769cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 47701da177e4SLinus Torvalds 47717382f9d8SDouglas Gilbert if (unlikely(aborted)) 47727382f9d8SDouglas Gilbert sd_dp->aborted = false; 4773c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 4774c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 4775c4837394SDouglas Gilbert if (sdebug_statistics) { 4776cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 4777c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 4778c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 4779c4837394SDouglas Gilbert } 4780c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 4781c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 47821da177e4SLinus Torvalds return; 47831da177e4SLinus Torvalds } 4784c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4785d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 4786c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 4787cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 4788b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 4789c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4790c10fa55fSJohn Garry pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d, hc_idx=%d\n", 4791c10fa55fSJohn Garry sd_dp->sqa_idx, qc_idx, sd_dp->hc_idx); 47921da177e4SLinus Torvalds return; 47931da177e4SLinus Torvalds } 4794cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 4795f46eb0e9SDouglas Gilbert if (likely(devip)) 4796cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 4797cbf67842SDouglas Gilbert else 4798c1287970STomas Winkler pr_err("devip=NULL\n"); 4799f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 4800cbf67842SDouglas Gilbert retiring = 1; 4801cbf67842SDouglas Gilbert 4802cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 4803c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 4804c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4805c1287970STomas Winkler pr_err("Unexpected completion\n"); 4806cbf67842SDouglas Gilbert return; 48071da177e4SLinus Torvalds } 48081da177e4SLinus Torvalds 4809cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 4810cbf67842SDouglas Gilbert int k, retval; 4811cbf67842SDouglas Gilbert 4812cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 4813c4837394SDouglas Gilbert if (qc_idx >= retval) { 4814c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4815c1287970STomas Winkler pr_err("index %d too large\n", retval); 4816cbf67842SDouglas Gilbert return; 4817cbf67842SDouglas Gilbert } 4818c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 4819773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 4820cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4821cbf67842SDouglas Gilbert else 4822cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4823cbf67842SDouglas Gilbert } 4824c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 48257382f9d8SDouglas Gilbert if (unlikely(aborted)) { 48267382f9d8SDouglas Gilbert if (sdebug_verbose) 48277382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 48287382f9d8SDouglas Gilbert return; 48297382f9d8SDouglas Gilbert } 48306c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 4831cbf67842SDouglas Gilbert } 4832cbf67842SDouglas Gilbert 4833cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4834fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4835cbf67842SDouglas Gilbert { 4836a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4837a10bc12aSDouglas Gilbert hrt); 4838a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4839cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4840cbf67842SDouglas Gilbert } 48411da177e4SLinus Torvalds 4842a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4843fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4844a10bc12aSDouglas Gilbert { 4845a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4846a10bc12aSDouglas Gilbert ew.work); 4847a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4848a10bc12aSDouglas Gilbert } 4849a10bc12aSDouglas Gilbert 485009ba24c1SDouglas Gilbert static bool got_shared_uuid; 4851bf476433SChristoph Hellwig static uuid_t shared_uuid; 485209ba24c1SDouglas Gilbert 4853f0d1cf93SDouglas Gilbert static int sdebug_device_create_zones(struct sdebug_dev_info *devip) 4854f0d1cf93SDouglas Gilbert { 4855f0d1cf93SDouglas Gilbert struct sdeb_zone_state *zsp; 4856f0d1cf93SDouglas Gilbert sector_t capacity = get_sdebug_capacity(); 4857f0d1cf93SDouglas Gilbert sector_t zstart = 0; 4858f0d1cf93SDouglas Gilbert unsigned int i; 4859f0d1cf93SDouglas Gilbert 4860f0d1cf93SDouglas Gilbert /* 486198e0a689SDamien Le Moal * Set the zone size: if sdeb_zbc_zone_size_mb is not set, figure out 486298e0a689SDamien Le Moal * a zone size allowing for at least 4 zones on the device. Otherwise, 4863f0d1cf93SDouglas Gilbert * use the specified zone size checking that at least 2 zones can be 4864f0d1cf93SDouglas Gilbert * created for the device. 4865f0d1cf93SDouglas Gilbert */ 486698e0a689SDamien Le Moal if (!sdeb_zbc_zone_size_mb) { 4867f0d1cf93SDouglas Gilbert devip->zsize = (DEF_ZBC_ZONE_SIZE_MB * SZ_1M) 4868f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4869f0d1cf93SDouglas Gilbert while (capacity < devip->zsize << 2 && devip->zsize >= 2) 4870f0d1cf93SDouglas Gilbert devip->zsize >>= 1; 4871f0d1cf93SDouglas Gilbert if (devip->zsize < 2) { 4872f0d1cf93SDouglas Gilbert pr_err("Device capacity too small\n"); 4873f0d1cf93SDouglas Gilbert return -EINVAL; 4874f0d1cf93SDouglas Gilbert } 4875f0d1cf93SDouglas Gilbert } else { 4876108e36f0SDamien Le Moal if (!is_power_of_2(sdeb_zbc_zone_size_mb)) { 4877108e36f0SDamien Le Moal pr_err("Zone size is not a power of 2\n"); 4878108e36f0SDamien Le Moal return -EINVAL; 4879108e36f0SDamien Le Moal } 488098e0a689SDamien Le Moal devip->zsize = (sdeb_zbc_zone_size_mb * SZ_1M) 4881f0d1cf93SDouglas Gilbert >> ilog2(sdebug_sector_size); 4882f0d1cf93SDouglas Gilbert if (devip->zsize >= capacity) { 4883f0d1cf93SDouglas Gilbert pr_err("Zone size too large for device capacity\n"); 4884f0d1cf93SDouglas Gilbert return -EINVAL; 4885f0d1cf93SDouglas Gilbert } 4886f0d1cf93SDouglas Gilbert } 4887f0d1cf93SDouglas Gilbert 4888f0d1cf93SDouglas Gilbert devip->zsize_shift = ilog2(devip->zsize); 4889f0d1cf93SDouglas Gilbert devip->nr_zones = (capacity + devip->zsize - 1) >> devip->zsize_shift; 4890f0d1cf93SDouglas Gilbert 4891aa8fecf9SDamien Le Moal if (sdeb_zbc_nr_conv >= devip->nr_zones) { 4892aa8fecf9SDamien Le Moal pr_err("Number of conventional zones too large\n"); 4893aa8fecf9SDamien Le Moal return -EINVAL; 4894aa8fecf9SDamien Le Moal } 4895aa8fecf9SDamien Le Moal devip->nr_conv_zones = sdeb_zbc_nr_conv; 4896aa8fecf9SDamien Le Moal 489764e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) { 489864e14eceSDamien Le Moal /* zbc_max_open_zones can be 0, meaning "not reported" */ 4899380603a5SDamien Le Moal if (sdeb_zbc_max_open >= devip->nr_zones - 1) 4900f0d1cf93SDouglas Gilbert devip->max_open = (devip->nr_zones - 1) / 2; 4901f0d1cf93SDouglas Gilbert else 4902380603a5SDamien Le Moal devip->max_open = sdeb_zbc_max_open; 490364e14eceSDamien Le Moal } 4904f0d1cf93SDouglas Gilbert 4905f0d1cf93SDouglas Gilbert devip->zstate = kcalloc(devip->nr_zones, 4906f0d1cf93SDouglas Gilbert sizeof(struct sdeb_zone_state), GFP_KERNEL); 4907f0d1cf93SDouglas Gilbert if (!devip->zstate) 4908f0d1cf93SDouglas Gilbert return -ENOMEM; 4909f0d1cf93SDouglas Gilbert 4910f0d1cf93SDouglas Gilbert for (i = 0; i < devip->nr_zones; i++) { 4911f0d1cf93SDouglas Gilbert zsp = &devip->zstate[i]; 4912f0d1cf93SDouglas Gilbert 4913f0d1cf93SDouglas Gilbert zsp->z_start = zstart; 4914f0d1cf93SDouglas Gilbert 4915aa8fecf9SDamien Le Moal if (i < devip->nr_conv_zones) { 491664e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_CNV; 4917f0d1cf93SDouglas Gilbert zsp->z_cond = ZBC_NOT_WRITE_POINTER; 4918f0d1cf93SDouglas Gilbert zsp->z_wp = (sector_t)-1; 4919f0d1cf93SDouglas Gilbert } else { 492064e14eceSDamien Le Moal if (devip->zmodel == BLK_ZONED_HM) 492164e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWR; 492264e14eceSDamien Le Moal else 492364e14eceSDamien Le Moal zsp->z_type = ZBC_ZONE_TYPE_SWP; 4924f0d1cf93SDouglas Gilbert zsp->z_cond = ZC1_EMPTY; 4925f0d1cf93SDouglas Gilbert zsp->z_wp = zsp->z_start; 4926f0d1cf93SDouglas Gilbert } 4927f0d1cf93SDouglas Gilbert 4928f0d1cf93SDouglas Gilbert if (zsp->z_start + devip->zsize < capacity) 4929f0d1cf93SDouglas Gilbert zsp->z_size = devip->zsize; 4930f0d1cf93SDouglas Gilbert else 4931f0d1cf93SDouglas Gilbert zsp->z_size = capacity - zsp->z_start; 4932f0d1cf93SDouglas Gilbert 4933f0d1cf93SDouglas Gilbert zstart += zsp->z_size; 4934f0d1cf93SDouglas Gilbert } 4935f0d1cf93SDouglas Gilbert 4936f0d1cf93SDouglas Gilbert return 0; 4937f0d1cf93SDouglas Gilbert } 4938f0d1cf93SDouglas Gilbert 4939fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 4940fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 49415cb2fc06SFUJITA Tomonori { 49425cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 49435cb2fc06SFUJITA Tomonori 49445cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 49455cb2fc06SFUJITA Tomonori if (devip) { 494609ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 4947bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 494809ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 494909ba24c1SDouglas Gilbert if (got_shared_uuid) 495009ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 495109ba24c1SDouglas Gilbert else { 4952bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 495309ba24c1SDouglas Gilbert got_shared_uuid = true; 495409ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 495509ba24c1SDouglas Gilbert } 495609ba24c1SDouglas Gilbert } 49575cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 4958f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) { 495964e14eceSDamien Le Moal devip->zmodel = sdeb_zbc_model; 4960f0d1cf93SDouglas Gilbert if (sdebug_device_create_zones(devip)) { 4961f0d1cf93SDouglas Gilbert kfree(devip); 4962f0d1cf93SDouglas Gilbert return NULL; 4963f0d1cf93SDouglas Gilbert } 496464e14eceSDamien Le Moal } else { 496564e14eceSDamien Le Moal devip->zmodel = BLK_ZONED_NONE; 4966f0d1cf93SDouglas Gilbert } 4967f0d1cf93SDouglas Gilbert devip->sdbg_host = sdbg_host; 4968fc13638aSDouglas Gilbert devip->create_ts = ktime_get_boottime(); 4969fc13638aSDouglas Gilbert atomic_set(&devip->stopped, (sdeb_tur_ms_to_ready > 0 ? 2 : 0)); 49705cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 49715cb2fc06SFUJITA Tomonori } 49725cb2fc06SFUJITA Tomonori return devip; 49735cb2fc06SFUJITA Tomonori } 49745cb2fc06SFUJITA Tomonori 4975f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 49761da177e4SLinus Torvalds { 49771da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 49781da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 4979f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 49801da177e4SLinus Torvalds 4981d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 49821da177e4SLinus Torvalds if (!sdbg_host) { 4983c1287970STomas Winkler pr_err("Host info NULL\n"); 49841da177e4SLinus Torvalds return NULL; 49851da177e4SLinus Torvalds } 4986ad0c7775SDouglas Gilbert 49871da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 49881da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 49891da177e4SLinus Torvalds (devip->target == sdev->id) && 49901da177e4SLinus Torvalds (devip->lun == sdev->lun)) 49911da177e4SLinus Torvalds return devip; 49921da177e4SLinus Torvalds else { 49931da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 49941da177e4SLinus Torvalds open_devip = devip; 49951da177e4SLinus Torvalds } 49961da177e4SLinus Torvalds } 49975cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 49985cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 49995cb2fc06SFUJITA Tomonori if (!open_devip) { 5000c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 50011da177e4SLinus Torvalds return NULL; 50021da177e4SLinus Torvalds } 50031da177e4SLinus Torvalds } 5004a75869d1SFUJITA Tomonori 50051da177e4SLinus Torvalds open_devip->channel = sdev->channel; 50061da177e4SLinus Torvalds open_devip->target = sdev->id; 50071da177e4SLinus Torvalds open_devip->lun = sdev->lun; 50081da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 5009cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 5010cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 5011c2248fc9SDouglas Gilbert open_devip->used = true; 50121da177e4SLinus Torvalds return open_devip; 50131da177e4SLinus Torvalds } 50141da177e4SLinus Torvalds 50158dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 50161da177e4SLinus Torvalds { 5017773642d9SDouglas Gilbert if (sdebug_verbose) 5018c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 50198dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 50208dea0d02SFUJITA Tomonori return 0; 50218dea0d02SFUJITA Tomonori } 50221da177e4SLinus Torvalds 50238dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 50248dea0d02SFUJITA Tomonori { 5025f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5026f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5027a34c4e98SFUJITA Tomonori 5028773642d9SDouglas Gilbert if (sdebug_verbose) 5029c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 50308dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 5031b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 5032b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 50332aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 50342aad3cd8SDouglas Gilbert pr_info("Exit early due to deflect_incoming\n"); 50352aad3cd8SDouglas Gilbert return 1; 50362aad3cd8SDouglas Gilbert } 5037b01f6f83SDouglas Gilbert if (devip == NULL) { 5038f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5039b01f6f83SDouglas Gilbert if (devip == NULL) 50408dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 5041f46eb0e9SDouglas Gilbert } 5042c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 5043773642d9SDouglas Gilbert if (sdebug_no_uld) 504478d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 50459b760fd8SDouglas Gilbert config_cdb_len(sdp); 50468dea0d02SFUJITA Tomonori return 0; 50478dea0d02SFUJITA Tomonori } 50488dea0d02SFUJITA Tomonori 50498dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 50508dea0d02SFUJITA Tomonori { 50518dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 50528dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 50538dea0d02SFUJITA Tomonori 5054773642d9SDouglas Gilbert if (sdebug_verbose) 5055c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 50568dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 50578dea0d02SFUJITA Tomonori if (devip) { 505825985edcSLucas De Marchi /* make this slot available for re-use */ 5059c2248fc9SDouglas Gilbert devip->used = false; 50608dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 50618dea0d02SFUJITA Tomonori } 50628dea0d02SFUJITA Tomonori } 50638dea0d02SFUJITA Tomonori 506410bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 506510bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 5066c4837394SDouglas Gilbert { 5067c4837394SDouglas Gilbert if (!sd_dp) 5068c4837394SDouglas Gilbert return; 506910bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 5070c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 507110bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 5072c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 5073c4837394SDouglas Gilbert } 5074c4837394SDouglas Gilbert 5075a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 5076a10bc12aSDouglas Gilbert returns false */ 5077a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 50788dea0d02SFUJITA Tomonori { 50798dea0d02SFUJITA Tomonori unsigned long iflags; 5080c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 508110bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5082c4837394SDouglas Gilbert struct sdebug_queue *sqp; 50838dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5084cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5085a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 50868dea0d02SFUJITA Tomonori 5087c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5088c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5089773642d9SDouglas Gilbert qmax = sdebug_max_queue; 5090cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 5091cbf67842SDouglas Gilbert if (r_qmax > qmax) 5092cbf67842SDouglas Gilbert qmax = r_qmax; 5093cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 5094c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5095c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5096a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 5097a10bc12aSDouglas Gilbert continue; 5098c4837394SDouglas Gilbert /* found */ 5099db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5100db525fceSDouglas Gilbert cmnd->device->hostdata; 5101db525fceSDouglas Gilbert if (devip) 5102db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5103db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5104a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 510510bde980SDouglas Gilbert if (sd_dp) { 5106d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5107d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 510810bde980SDouglas Gilbert } else 510910bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5110c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 511110bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 5112c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5113a10bc12aSDouglas Gilbert return true; 51148dea0d02SFUJITA Tomonori } 5115cbf67842SDouglas Gilbert } 5116c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5117c4837394SDouglas Gilbert } 5118a10bc12aSDouglas Gilbert return false; 51198dea0d02SFUJITA Tomonori } 51208dea0d02SFUJITA Tomonori 5121a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 51222aad3cd8SDouglas Gilbert static void stop_all_queued(bool done_with_no_conn) 51238dea0d02SFUJITA Tomonori { 51248dea0d02SFUJITA Tomonori unsigned long iflags; 5125c4837394SDouglas Gilbert int j, k; 512610bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 5127c4837394SDouglas Gilbert struct sdebug_queue *sqp; 51288dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 5129cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5130a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 51312aad3cd8SDouglas Gilbert struct scsi_cmnd *scp; 51328dea0d02SFUJITA Tomonori 5133c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5134c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5135c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5136c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 5137c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 51382aad3cd8SDouglas Gilbert scp = sqcp->a_cmnd; 51392aad3cd8SDouglas Gilbert if (!scp) 5140a10bc12aSDouglas Gilbert continue; 5141db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 5142db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 5143db525fceSDouglas Gilbert if (devip) 5144db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 5145db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 5146a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 514710bde980SDouglas Gilbert if (sd_dp) { 5148d9d23a5aSDouglas Gilbert l_defer_t = READ_ONCE(sd_dp->defer_t); 5149d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 515010bde980SDouglas Gilbert } else 515110bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 5152c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 515310bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 51542aad3cd8SDouglas Gilbert if (done_with_no_conn && l_defer_t != SDEB_DEFER_NONE) { 51552aad3cd8SDouglas Gilbert scp->result = DID_NO_CONNECT << 16; 51562aad3cd8SDouglas Gilbert scsi_done(scp); 51572aad3cd8SDouglas Gilbert } 5158c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5159c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 51608dea0d02SFUJITA Tomonori } 51618dea0d02SFUJITA Tomonori } 5162c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5163c4837394SDouglas Gilbert } 5164cbf67842SDouglas Gilbert } 5165cbf67842SDouglas Gilbert 5166cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 5167cbf67842SDouglas Gilbert static void free_all_queued(void) 5168cbf67842SDouglas Gilbert { 5169c4837394SDouglas Gilbert int j, k; 5170c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5171cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5172cbf67842SDouglas Gilbert 5173c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5174c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 5175c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 5176a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 5177a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 5178cbf67842SDouglas Gilbert } 51791da177e4SLinus Torvalds } 5180c4837394SDouglas Gilbert } 51811da177e4SLinus Torvalds 51821da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 51831da177e4SLinus Torvalds { 5184a10bc12aSDouglas Gilbert bool ok; 5185a10bc12aSDouglas Gilbert 51861da177e4SLinus Torvalds ++num_aborts; 5187cbf67842SDouglas Gilbert if (SCpnt) { 5188a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 5189a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5190a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5191a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 5192a10bc12aSDouglas Gilbert ok ? "" : " not"); 5193cbf67842SDouglas Gilbert } 51941da177e4SLinus Torvalds return SUCCESS; 51951da177e4SLinus Torvalds } 51961da177e4SLinus Torvalds 51971da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 51981da177e4SLinus Torvalds { 51991da177e4SLinus Torvalds ++num_dev_resets; 5200cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 5201cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 5202f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 5203f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 5204cbf67842SDouglas Gilbert 5205773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5206cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 52071da177e4SLinus Torvalds if (devip) 5208cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 52091da177e4SLinus Torvalds } 52101da177e4SLinus Torvalds return SUCCESS; 52111da177e4SLinus Torvalds } 52121da177e4SLinus Torvalds 5213cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 5214cbf67842SDouglas Gilbert { 5215cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 5216cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5217cbf67842SDouglas Gilbert struct scsi_device *sdp; 5218cbf67842SDouglas Gilbert struct Scsi_Host *hp; 5219cbf67842SDouglas Gilbert int k = 0; 5220cbf67842SDouglas Gilbert 5221cbf67842SDouglas Gilbert ++num_target_resets; 5222cbf67842SDouglas Gilbert if (!SCpnt) 5223cbf67842SDouglas Gilbert goto lie; 5224cbf67842SDouglas Gilbert sdp = SCpnt->device; 5225cbf67842SDouglas Gilbert if (!sdp) 5226cbf67842SDouglas Gilbert goto lie; 5227773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5228cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5229cbf67842SDouglas Gilbert hp = sdp->host; 5230cbf67842SDouglas Gilbert if (!hp) 5231cbf67842SDouglas Gilbert goto lie; 5232cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 5233cbf67842SDouglas Gilbert if (sdbg_host) { 5234cbf67842SDouglas Gilbert list_for_each_entry(devip, 5235cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 5236cbf67842SDouglas Gilbert dev_list) 5237cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 5238cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5239cbf67842SDouglas Gilbert ++k; 5240cbf67842SDouglas Gilbert } 5241cbf67842SDouglas Gilbert } 5242773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5243cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5244cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 5245cbf67842SDouglas Gilbert lie: 5246cbf67842SDouglas Gilbert return SUCCESS; 5247cbf67842SDouglas Gilbert } 5248cbf67842SDouglas Gilbert 52491da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 52501da177e4SLinus Torvalds { 52511da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5252cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 52531da177e4SLinus Torvalds struct scsi_device *sdp; 52541da177e4SLinus Torvalds struct Scsi_Host *hp; 5255cbf67842SDouglas Gilbert int k = 0; 52561da177e4SLinus Torvalds 52571da177e4SLinus Torvalds ++num_bus_resets; 5258cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 5259cbf67842SDouglas Gilbert goto lie; 5260cbf67842SDouglas Gilbert sdp = SCpnt->device; 5261773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 5262cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 5263cbf67842SDouglas Gilbert hp = sdp->host; 5264cbf67842SDouglas Gilbert if (hp) { 5265d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 52661da177e4SLinus Torvalds if (sdbg_host) { 5267cbf67842SDouglas Gilbert list_for_each_entry(devip, 52681da177e4SLinus Torvalds &sdbg_host->dev_info_list, 5269cbf67842SDouglas Gilbert dev_list) { 5270cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5271cbf67842SDouglas Gilbert ++k; 52721da177e4SLinus Torvalds } 52731da177e4SLinus Torvalds } 5274cbf67842SDouglas Gilbert } 5275773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5276cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 5277cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 5278cbf67842SDouglas Gilbert lie: 52791da177e4SLinus Torvalds return SUCCESS; 52801da177e4SLinus Torvalds } 52811da177e4SLinus Torvalds 52821da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 52831da177e4SLinus Torvalds { 52841da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 5285cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5286cbf67842SDouglas Gilbert int k = 0; 52871da177e4SLinus Torvalds 52881da177e4SLinus Torvalds ++num_host_resets; 5289773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 5290cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 52911da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 52921da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 5293cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 5294cbf67842SDouglas Gilbert dev_list) { 5295cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 5296cbf67842SDouglas Gilbert ++k; 5297cbf67842SDouglas Gilbert } 52981da177e4SLinus Torvalds } 52991da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 53002aad3cd8SDouglas Gilbert stop_all_queued(false); 5301773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 5302cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 5303cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 53041da177e4SLinus Torvalds return SUCCESS; 53051da177e4SLinus Torvalds } 53061da177e4SLinus Torvalds 530787c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 53081da177e4SLinus Torvalds { 53091442f76dSChristoph Hellwig struct msdos_partition *pp; 5310979e0dc3SJohn Pittman int starts[SDEBUG_MAX_PARTS + 2], max_part_secs; 53111da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 53121da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 53131da177e4SLinus Torvalds 53141da177e4SLinus Torvalds /* assume partition table already zeroed */ 5315773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 53161da177e4SLinus Torvalds return; 5317773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 5318773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 5319c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 53201da177e4SLinus Torvalds } 53218c657235SJohn Pittman num_sectors = (int)get_sdebug_capacity(); 53221da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 5323773642d9SDouglas Gilbert / sdebug_num_parts; 53241da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 53251da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 5326979e0dc3SJohn Pittman max_part_secs = sectors_per_part; 5327979e0dc3SJohn Pittman for (k = 1; k < sdebug_num_parts; ++k) { 53281da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 53291da177e4SLinus Torvalds * heads_by_sects; 5330979e0dc3SJohn Pittman if (starts[k] - starts[k - 1] < max_part_secs) 5331979e0dc3SJohn Pittman max_part_secs = starts[k] - starts[k - 1]; 5332979e0dc3SJohn Pittman } 5333773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 5334773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 53351da177e4SLinus Torvalds 53361da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 53371da177e4SLinus Torvalds ramp[511] = 0xAA; 53381442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 53391da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 53401da177e4SLinus Torvalds start_sec = starts[k]; 5341979e0dc3SJohn Pittman end_sec = starts[k] + max_part_secs - 1; 53421da177e4SLinus Torvalds pp->boot_ind = 0; 53431da177e4SLinus Torvalds 53441da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 53451da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 53461da177e4SLinus Torvalds / sdebug_sectors_per; 53471da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 53481da177e4SLinus Torvalds 53491da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 53501da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 53511da177e4SLinus Torvalds / sdebug_sectors_per; 53521da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 53531da177e4SLinus Torvalds 5354150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 5355150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 53561da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 53571da177e4SLinus Torvalds } 53581da177e4SLinus Torvalds } 53591da177e4SLinus Torvalds 53602aad3cd8SDouglas Gilbert static void sdeb_block_all_queues(void) 5361c4837394SDouglas Gilbert { 5362c4837394SDouglas Gilbert int j; 5363c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5364c4837394SDouglas Gilbert 5365c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 53662aad3cd8SDouglas Gilbert atomic_set(&sqp->blocked, (int)true); 53672aad3cd8SDouglas Gilbert } 53682aad3cd8SDouglas Gilbert 53692aad3cd8SDouglas Gilbert static void sdeb_unblock_all_queues(void) 53702aad3cd8SDouglas Gilbert { 53712aad3cd8SDouglas Gilbert int j; 53722aad3cd8SDouglas Gilbert struct sdebug_queue *sqp; 53732aad3cd8SDouglas Gilbert 53742aad3cd8SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 53752aad3cd8SDouglas Gilbert atomic_set(&sqp->blocked, (int)false); 53762aad3cd8SDouglas Gilbert } 53772aad3cd8SDouglas Gilbert 53782aad3cd8SDouglas Gilbert static void 53792aad3cd8SDouglas Gilbert sdeb_add_n_hosts(int num_hosts) 53802aad3cd8SDouglas Gilbert { 53812aad3cd8SDouglas Gilbert if (num_hosts < 1) 53822aad3cd8SDouglas Gilbert return; 53832aad3cd8SDouglas Gilbert do { 53842aad3cd8SDouglas Gilbert bool found; 53852aad3cd8SDouglas Gilbert unsigned long idx; 53862aad3cd8SDouglas Gilbert struct sdeb_store_info *sip; 53872aad3cd8SDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 53882aad3cd8SDouglas Gilbert 53892aad3cd8SDouglas Gilbert found = false; 53902aad3cd8SDouglas Gilbert if (want_phs) { 53912aad3cd8SDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, SDEB_XA_NOT_IN_USE) { 53922aad3cd8SDouglas Gilbert sdeb_most_recent_idx = (int)idx; 53932aad3cd8SDouglas Gilbert found = true; 53942aad3cd8SDouglas Gilbert break; 53952aad3cd8SDouglas Gilbert } 53962aad3cd8SDouglas Gilbert if (found) /* re-use case */ 53972aad3cd8SDouglas Gilbert sdebug_add_host_helper((int)idx); 53982aad3cd8SDouglas Gilbert else 53992aad3cd8SDouglas Gilbert sdebug_do_add_host(true /* make new store */); 54002aad3cd8SDouglas Gilbert } else { 54012aad3cd8SDouglas Gilbert sdebug_do_add_host(false); 54022aad3cd8SDouglas Gilbert } 54032aad3cd8SDouglas Gilbert } while (--num_hosts); 5404c4837394SDouglas Gilbert } 5405c4837394SDouglas Gilbert 5406c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 5407c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 5408c4837394SDouglas Gilbert */ 5409c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 5410c4837394SDouglas Gilbert { 5411c4837394SDouglas Gilbert int count, modulo; 5412c4837394SDouglas Gilbert 5413c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 5414c4837394SDouglas Gilbert if (modulo < 2) 5415c4837394SDouglas Gilbert return; 54162aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 5417c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 5418c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 54192aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 5420c4837394SDouglas Gilbert } 5421c4837394SDouglas Gilbert 5422c4837394SDouglas Gilbert static void clear_queue_stats(void) 5423c4837394SDouglas Gilbert { 5424c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 5425c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 5426c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 5427c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 5428c4837394SDouglas Gilbert } 5429c4837394SDouglas Gilbert 54303a90a63dSDouglas Gilbert static bool inject_on_this_cmd(void) 5431c4837394SDouglas Gilbert { 54323a90a63dSDouglas Gilbert if (sdebug_every_nth == 0) 54333a90a63dSDouglas Gilbert return false; 54343a90a63dSDouglas Gilbert return (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 5435c4837394SDouglas Gilbert } 5436c4837394SDouglas Gilbert 54372aad3cd8SDouglas Gilbert static int process_deflect_incoming(struct scsi_cmnd *scp) 54382aad3cd8SDouglas Gilbert { 54392aad3cd8SDouglas Gilbert u8 opcode = scp->cmnd[0]; 54402aad3cd8SDouglas Gilbert 54412aad3cd8SDouglas Gilbert if (opcode == SYNCHRONIZE_CACHE || opcode == SYNCHRONIZE_CACHE_16) 54422aad3cd8SDouglas Gilbert return 0; 54432aad3cd8SDouglas Gilbert return DID_NO_CONNECT << 16; 54442aad3cd8SDouglas Gilbert } 54452aad3cd8SDouglas Gilbert 5446a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 5447a2aede97SDouglas Gilbert 5448c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 5449c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 5450c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 5451c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 5452c4837394SDouglas Gilbert */ 5453fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 5454f66b8517SMartin Wilck int scsi_result, 54552aad3cd8SDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *), 5456f66b8517SMartin Wilck int delta_jiff, int ndelay) 54571da177e4SLinus Torvalds { 5458a2aede97SDouglas Gilbert bool new_sd_dp; 54593a90a63dSDouglas Gilbert bool inject = false; 54606ce913feSChristoph Hellwig bool polled = scsi_cmd_to_rq(cmnd)->cmd_flags & REQ_POLLED; 54613a90a63dSDouglas Gilbert int k, num_in_q, qdepth; 5462a2aede97SDouglas Gilbert unsigned long iflags; 5463a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 5464c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5465c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 5466299b6c07STomas Winkler struct scsi_device *sdp; 5467a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 54681da177e4SLinus Torvalds 5469b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 5470b01f6f83SDouglas Gilbert if (scsi_result == 0) 5471f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 5472f46eb0e9SDouglas Gilbert goto respond_in_thread; 54731da177e4SLinus Torvalds } 5474299b6c07STomas Winkler sdp = cmnd->device; 5475299b6c07STomas Winkler 54762aad3cd8SDouglas Gilbert if (delta_jiff == 0) { 54772aad3cd8SDouglas Gilbert sqp = get_queue(cmnd); 54782aad3cd8SDouglas Gilbert if (atomic_read(&sqp->blocked)) { 54792aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) 54802aad3cd8SDouglas Gilbert return process_deflect_incoming(cmnd); 54812aad3cd8SDouglas Gilbert else 54822aad3cd8SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 54832aad3cd8SDouglas Gilbert } 5484cd62b7daSDouglas Gilbert goto respond_in_thread; 54852aad3cd8SDouglas Gilbert } 54861da177e4SLinus Torvalds 5487c4837394SDouglas Gilbert sqp = get_queue(cmnd); 5488c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5489c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 5490c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 54912aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 54922aad3cd8SDouglas Gilbert scsi_result = process_deflect_incoming(cmnd); 54932aad3cd8SDouglas Gilbert goto respond_in_thread; 54942aad3cd8SDouglas Gilbert } 54952aad3cd8SDouglas Gilbert if (sdebug_verbose) 54962aad3cd8SDouglas Gilbert pr_info("blocked --> SCSI_MLQUEUE_HOST_BUSY\n"); 5497c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 5498c4837394SDouglas Gilbert } 5499cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5500cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 5501f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 5502cd62b7daSDouglas Gilbert if (scsi_result) { 5503c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5504cd62b7daSDouglas Gilbert goto respond_in_thread; 5505cd62b7daSDouglas Gilbert } else 5506cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5507c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 5508773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 5509f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 5510cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 5511cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 5512773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 5513cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 55143a90a63dSDouglas Gilbert inject = true; 5515cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 55161da177e4SLinus Torvalds } 5517cbf67842SDouglas Gilbert } 5518cbf67842SDouglas Gilbert 5519c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 5520f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 5521c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5522cd62b7daSDouglas Gilbert if (scsi_result) 5523cd62b7daSDouglas Gilbert goto respond_in_thread; 5524cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 5525773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 5526*7d5a129bSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: max_queue=%d exceeded: TASK SET FULL\n", 5527*7d5a129bSDouglas Gilbert __func__, sdebug_max_queue); 5528cd62b7daSDouglas Gilbert goto respond_in_thread; 55291da177e4SLinus Torvalds } 553074595c04SDouglas Gilbert set_bit(k, sqp->in_use_bm); 5531cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 5532c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 55331da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 5534c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 5535a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 5536c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5537c4b57d89SKashyap Desai 553874595c04SDouglas Gilbert if (!sd_dp) { 553910bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 554074595c04SDouglas Gilbert if (!sd_dp) { 554174595c04SDouglas Gilbert atomic_dec(&devip->num_in_q); 554274595c04SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 554310bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 554474595c04SDouglas Gilbert } 5545a2aede97SDouglas Gilbert new_sd_dp = true; 5546a2aede97SDouglas Gilbert } else { 5547a2aede97SDouglas Gilbert new_sd_dp = false; 554810bde980SDouglas Gilbert } 5549f66b8517SMartin Wilck 5550c10fa55fSJohn Garry /* Set the hostwide tag */ 5551c10fa55fSJohn Garry if (sdebug_host_max_queue) 5552c10fa55fSJohn Garry sd_dp->hc_idx = get_tag(cmnd); 5553c10fa55fSJohn Garry 55546ce913feSChristoph Hellwig if (polled) 5555a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 5556a2aede97SDouglas Gilbert 5557a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 55583a90a63dSDouglas Gilbert cmnd->result = pfp ? pfp(cmnd, devip) : 0; 5559f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 5560f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 5561f66b8517SMartin Wilck delta_jiff = ndelay = 0; 5562f66b8517SMartin Wilck } 5563f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 5564f66b8517SMartin Wilck cmnd->result = scsi_result; 55653a90a63dSDouglas Gilbert if (cmnd->result == 0 && unlikely(sdebug_opts & SDEBUG_OPT_TRANSPORT_ERR)) { 55663a90a63dSDouglas Gilbert if (atomic_read(&sdeb_inject_pending)) { 55673a90a63dSDouglas Gilbert mk_sense_buffer(cmnd, ABORTED_COMMAND, TRANSPORT_PROBLEM, ACK_NAK_TO); 55683a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 55693a90a63dSDouglas Gilbert cmnd->result = check_condition_result; 55703a90a63dSDouglas Gilbert } 55713a90a63dSDouglas Gilbert } 5572f66b8517SMartin Wilck 5573f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 5574f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 5575f66b8517SMartin Wilck __func__, cmnd->result); 5576f66b8517SMartin Wilck 557710bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 5578b333a819SDouglas Gilbert ktime_t kt; 5579cbf67842SDouglas Gilbert 5580b333a819SDouglas Gilbert if (delta_jiff > 0) { 55810c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 55820c4bc91dSDouglas Gilbert 55830c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 55840c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 55850c4bc91dSDouglas Gilbert } else if (sdebug_random) { 55860c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 55870c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 55880c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 55890c4bc91dSDouglas Gilbert ns <<= 12; 55900c4bc91dSDouglas Gilbert } 55910c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 55920c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 55930c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 55940c4bc91dSDouglas Gilbert (u32)ndelay; 5595a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 5596a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 5597a2aede97SDouglas Gilbert 5598a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 5599223f91b4SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 5600a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 5601a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 5602a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 5603223f91b4SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 5604a2aede97SDouglas Gilbert if (new_sd_dp) 5605a2aede97SDouglas Gilbert kfree(sd_dp); 5606a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 56076c2c7d6aSBart Van Assche scsi_done(cmnd); 5608a2aede97SDouglas Gilbert return 0; 5609a2aede97SDouglas Gilbert } 5610a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 5611a2aede97SDouglas Gilbert kt -= d; 5612a2aede97SDouglas Gilbert } 56130c4bc91dSDouglas Gilbert } 56146ce913feSChristoph Hellwig if (polled) { 56154a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ktime_add(ns_to_ktime(ns_from_boot), kt); 56164a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 56174a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 56184a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 56194a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 56204a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 56214a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 56224a0c6f43SDouglas Gilbert } 5623d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 56244a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 56254a0c6f43SDouglas Gilbert } else { 562610bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 562710bde980SDouglas Gilbert sd_dp->init_hrt = true; 5628a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5629a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 5630c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 5631a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 5632c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5633c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5634cbf67842SDouglas Gilbert } 5635d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_HRT); 5636a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 5637c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 56384a0c6f43SDouglas Gilbert } 56394a0c6f43SDouglas Gilbert if (sdebug_statistics) 56404a0c6f43SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 5641c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 56424a0c6f43SDouglas Gilbert if (unlikely((sdebug_opts & SDEBUG_OPT_CMD_ABORT) && 56434a0c6f43SDouglas Gilbert atomic_read(&sdeb_inject_pending))) 56444a0c6f43SDouglas Gilbert sd_dp->aborted = true; 56456ce913feSChristoph Hellwig if (polled) { 56464a0c6f43SDouglas Gilbert sd_dp->cmpl_ts = ns_to_ktime(ns_from_boot); 56474a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 56484a0c6f43SDouglas Gilbert if (!sd_dp->init_poll) { 56494a0c6f43SDouglas Gilbert sd_dp->init_poll = true; 56504a0c6f43SDouglas Gilbert sqcp->sd_dp = sd_dp; 56514a0c6f43SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 56524a0c6f43SDouglas Gilbert sd_dp->qc_idx = k; 56534a0c6f43SDouglas Gilbert } 5654d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_POLL); 56554a0c6f43SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 56564a0c6f43SDouglas Gilbert } else { 565710bde980SDouglas Gilbert if (!sd_dp->init_wq) { 565810bde980SDouglas Gilbert sd_dp->init_wq = true; 5659a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 5660c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 5661c4837394SDouglas Gilbert sd_dp->qc_idx = k; 5662a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 5663cbf67842SDouglas Gilbert } 5664d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_WQ); 56654a0c6f43SDouglas Gilbert schedule_work(&sd_dp->ew.work); 56664a0c6f43SDouglas Gilbert } 5667c4837394SDouglas Gilbert if (sdebug_statistics) 5668c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 56694a0c6f43SDouglas Gilbert if (unlikely(sd_dp->aborted)) { 5670a6e76e6fSBart Van Assche sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 5671a6e76e6fSBart Van Assche scsi_cmd_to_rq(cmnd)->tag); 5672a6e76e6fSBart Van Assche blk_abort_request(scsi_cmd_to_rq(cmnd)); 56733a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 0); 56744a0c6f43SDouglas Gilbert sd_dp->aborted = false; 56757382f9d8SDouglas Gilbert } 5676cbf67842SDouglas Gilbert } 56773a90a63dSDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && scsi_result == device_qfull_result)) 56783a90a63dSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: num_in_q=%d +1, %s%s\n", __func__, 56793a90a63dSDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), "status: TASK SET FULL"); 56801da177e4SLinus Torvalds return 0; 5681cd62b7daSDouglas Gilbert 5682cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 5683f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 5684f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 56852aad3cd8SDouglas Gilbert if (cmnd->result == 0 && scsi_result != 0) { 5686cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 56872aad3cd8SDouglas Gilbert if (sdebug_verbose) 56882aad3cd8SDouglas Gilbert pr_info("respond_in_thread: tag=0x%x, scp->result=0x%x\n", 56892aad3cd8SDouglas Gilbert blk_mq_unique_tag(scsi_cmd_to_rq(cmnd)), scsi_result); 56902aad3cd8SDouglas Gilbert } 56916c2c7d6aSBart Van Assche scsi_done(cmnd); 5692cd62b7daSDouglas Gilbert return 0; 56931da177e4SLinus Torvalds } 5694cbf67842SDouglas Gilbert 569523183910SDouglas Gilbert /* Note: The following macros create attribute files in the 569623183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 569723183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 569823183910SDouglas Gilbert as it can when the corresponding attribute in the 569923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 570023183910SDouglas Gilbert */ 5701773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 5702773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 57039b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 5704773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 5705c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 5706773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 5707773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 5708773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 5709773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 5710773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 5711773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 5712773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 5713773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 5714c10fa55fSJohn Garry module_param_named(host_max_queue, sdebug_host_max_queue, int, S_IRUGO); 5715e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 5716e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 5717e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 5718e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 57195d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 57205d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 57215d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 5722773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 5723773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 5724773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 5725773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 5726ad0c7775SDouglas Gilbert module_param_named(lun_format, sdebug_lun_am_i, int, S_IRUGO | S_IWUSR); 5727773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 5728773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 57295d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 57305d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 57315d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 57325d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 5733773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 5734773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 5735773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 5736773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 5737773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 5738773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 57395d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 5740773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 574187c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 574287c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 5743773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 5744773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 57450c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 5746773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 5747773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 5748773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 5749c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 5750773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 5751c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 5752c4b57d89SKashyap Desai module_param_named(poll_queues, poll_queues, int, S_IRUGO); 5753fc13638aSDouglas Gilbert module_param_named(tur_ms_to_ready, sdeb_tur_ms_to_ready, int, S_IRUGO); 5754773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 5755773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 5756773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 5757773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 575809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 57595d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 5760773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 576123183910SDouglas Gilbert S_IRUGO | S_IWUSR); 57629447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 5763773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 57645b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 57659267e0ebSDouglas Gilbert module_param_named(zbc, sdeb_zbc_model_s, charp, S_IRUGO); 5766380603a5SDamien Le Moal module_param_named(zone_max_open, sdeb_zbc_max_open, int, S_IRUGO); 5767aa8fecf9SDamien Le Moal module_param_named(zone_nr_conv, sdeb_zbc_nr_conv, int, S_IRUGO); 576898e0a689SDamien Le Moal module_param_named(zone_size_mb, sdeb_zbc_zone_size_mb, int, S_IRUGO); 57691da177e4SLinus Torvalds 57701da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 57711da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 57721da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 5773b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 57741da177e4SLinus Torvalds 57755d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 57765b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 57779b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 57780759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 5779cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 5780c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 57815b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 57825b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 5783c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 5784beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 578523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 57865b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 5787185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 5788c10fa55fSJohn Garry MODULE_PARM_DESC(host_max_queue, 5789c10fa55fSJohn Garry "host max # of queued cmds (0 to max(def) [max_queue fixed equal for !0])"); 5790e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 57919b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 57929b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 57935d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 57945d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 57955d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 57965b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 57975b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 57985b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 57995b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 5800ad0c7775SDouglas Gilbert MODULE_PARM_DESC(lun_format, "LUN format: 0->peripheral (def); 1 --> flat address method"); 5801fc09acb7SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 5802cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 5803d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 58045d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 5805cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 5806c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 580778d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 58081da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 5809c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 581032c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 581186e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 58125d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 58135d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 58145d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 5815fc09acb7SDouglas Gilbert MODULE_PARM_DESC(poll_queues, "support for iouring iopoll queues (1 to max(submit_queues - 1))"); 58161da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 58170c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 5818d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 5819760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 5820ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 5821c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 5822c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 5823c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 5824fc13638aSDouglas Gilbert MODULE_PARM_DESC(tur_ms_to_ready, "TEST UNIT READY millisecs before initial good status (def=0)"); 58255b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 58265b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 58276014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 58286014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 582909ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 583009ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 5831c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 58325b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 58339447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 58345b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 58359267e0ebSDouglas Gilbert MODULE_PARM_DESC(zbc, "'none' [0]; 'aware' [1]; 'managed' [2] (def=0). Can have 'host-' prefix"); 5836380603a5SDamien Le Moal MODULE_PARM_DESC(zone_max_open, "Maximum number of open zones; [0] for no limit (def=auto)"); 5837aa8fecf9SDamien Le Moal MODULE_PARM_DESC(zone_nr_conv, "Number of conventional zones (def=1)"); 583898e0a689SDamien Le Moal MODULE_PARM_DESC(zone_size_mb, "Zone size in MiB (def=auto)"); 58391da177e4SLinus Torvalds 5840760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 5841760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 58421da177e4SLinus Torvalds 58431da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 58441da177e4SLinus Torvalds { 5845c4837394SDouglas Gilbert int k; 5846c4837394SDouglas Gilbert 5847760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 5848760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 5849760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 5850c4837394SDouglas Gilbert return sdebug_info; 5851760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 5852760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 5853760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 5854760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 58551da177e4SLinus Torvalds return sdebug_info; 58561da177e4SLinus Torvalds } 58571da177e4SLinus Torvalds 5858cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 5859fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 5860fd32119bSDouglas Gilbert int length) 58611da177e4SLinus Torvalds { 58621da177e4SLinus Torvalds char arr[16]; 5863c8ed555aSAl Viro int opts; 58641da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 58651da177e4SLinus Torvalds 58661da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 58671da177e4SLinus Torvalds return -EACCES; 58681da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 58691da177e4SLinus Torvalds arr[minLen] = '\0'; 5870c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 58711da177e4SLinus Torvalds return -EINVAL; 5872773642d9SDouglas Gilbert sdebug_opts = opts; 5873773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5874773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5875773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 5876c4837394SDouglas Gilbert tweak_cmnd_count(); 58771da177e4SLinus Torvalds return length; 58781da177e4SLinus Torvalds } 5879c8ed555aSAl Viro 5880cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 5881cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 5882cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 5883c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 5884c8ed555aSAl Viro { 5885c4837394SDouglas Gilbert int f, j, l; 5886c4837394SDouglas Gilbert struct sdebug_queue *sqp; 588787c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 5888cbf67842SDouglas Gilbert 5889c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 5890c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 5891c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 5892c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 5893c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 5894c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 5895c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 5896c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 5897c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 5898c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 5899c4837394SDouglas Gilbert num_aborts); 5900c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 5901c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 5902c4837394SDouglas Gilbert num_host_resets); 5903c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 5904c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 5905458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 5906458df78bSBart Van Assche sdebug_statistics); 59074a0c6f43SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d, mq_polls=%d\n", 5908c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 5909c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 5910c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 59114a0c6f43SDouglas Gilbert atomic_read(&sdebug_a_tsf), 59124a0c6f43SDouglas Gilbert atomic_read(&sdeb_mq_poll_count)); 5913cbf67842SDouglas Gilbert 5914c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 5915c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 5916c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 5917c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 5918773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 5919c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 5920c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 5921c4837394SDouglas Gilbert "first,last bits", f, l); 5922c4837394SDouglas Gilbert } 5923cbf67842SDouglas Gilbert } 592487c715dcSDouglas Gilbert 592587c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 592687c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 592787c715dcSDouglas Gilbert bool niu; 592887c715dcSDouglas Gilbert int idx; 592987c715dcSDouglas Gilbert unsigned long l_idx; 593087c715dcSDouglas Gilbert struct sdeb_store_info *sip; 593187c715dcSDouglas Gilbert 593287c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 593387c715dcSDouglas Gilbert j = 0; 593487c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 593587c715dcSDouglas Gilbert idx = sdhp->si_idx; 593687c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 593787c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 593887c715dcSDouglas Gilbert ++j; 593987c715dcSDouglas Gilbert } 594087c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 594187c715dcSDouglas Gilbert sdeb_most_recent_idx); 594287c715dcSDouglas Gilbert j = 0; 594387c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 594487c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 594587c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 594687c715dcSDouglas Gilbert idx = (int)l_idx; 594787c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 594887c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 594987c715dcSDouglas Gilbert ++j; 595087c715dcSDouglas Gilbert } 595187c715dcSDouglas Gilbert } 5952c8ed555aSAl Viro return 0; 59531da177e4SLinus Torvalds } 59541da177e4SLinus Torvalds 595582069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 59561da177e4SLinus Torvalds { 5957c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 59581da177e4SLinus Torvalds } 5959c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 5960c4837394SDouglas Gilbert * of delay is jiffies. 5961c4837394SDouglas Gilbert */ 596282069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 596382069379SAkinobu Mita size_t count) 59641da177e4SLinus Torvalds { 5965c2206098SDouglas Gilbert int jdelay, res; 59661da177e4SLinus Torvalds 5967b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 5968cbf67842SDouglas Gilbert res = count; 5969c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 5970c4837394SDouglas Gilbert int j, k; 5971c4837394SDouglas Gilbert struct sdebug_queue *sqp; 5972cbf67842SDouglas Gilbert 59732aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 5974c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5975c4837394SDouglas Gilbert ++j, ++sqp) { 5976c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 5977c4837394SDouglas Gilbert sdebug_max_queue); 5978c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 5979c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 5980c4837394SDouglas Gilbert break; 5981c4837394SDouglas Gilbert } 5982c4837394SDouglas Gilbert } 5983c4837394SDouglas Gilbert if (res > 0) { 5984c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 5985773642d9SDouglas Gilbert sdebug_ndelay = 0; 59861da177e4SLinus Torvalds } 59872aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 5988cbf67842SDouglas Gilbert } 5989cbf67842SDouglas Gilbert return res; 59901da177e4SLinus Torvalds } 59911da177e4SLinus Torvalds return -EINVAL; 59921da177e4SLinus Torvalds } 599382069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 59941da177e4SLinus Torvalds 5995cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 5996cbf67842SDouglas Gilbert { 5997773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 5998cbf67842SDouglas Gilbert } 5999cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 6000c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 6001cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 6002cbf67842SDouglas Gilbert size_t count) 6003cbf67842SDouglas Gilbert { 6004c4837394SDouglas Gilbert int ndelay, res; 6005cbf67842SDouglas Gilbert 6006cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 6007c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 6008cbf67842SDouglas Gilbert res = count; 6009773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 6010c4837394SDouglas Gilbert int j, k; 6011c4837394SDouglas Gilbert struct sdebug_queue *sqp; 6012c4837394SDouglas Gilbert 60132aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 6014c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6015c4837394SDouglas Gilbert ++j, ++sqp) { 6016c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 6017c4837394SDouglas Gilbert sdebug_max_queue); 6018c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 6019c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 6020c4837394SDouglas Gilbert break; 6021c4837394SDouglas Gilbert } 6022c4837394SDouglas Gilbert } 6023c4837394SDouglas Gilbert if (res > 0) { 6024773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 6025c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 6026c2206098SDouglas Gilbert : DEF_JDELAY; 6027cbf67842SDouglas Gilbert } 60282aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 6029cbf67842SDouglas Gilbert } 6030cbf67842SDouglas Gilbert return res; 6031cbf67842SDouglas Gilbert } 6032cbf67842SDouglas Gilbert return -EINVAL; 6033cbf67842SDouglas Gilbert } 6034cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 6035cbf67842SDouglas Gilbert 603682069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 60371da177e4SLinus Torvalds { 6038773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 60391da177e4SLinus Torvalds } 60401da177e4SLinus Torvalds 604182069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 604282069379SAkinobu Mita size_t count) 60431da177e4SLinus Torvalds { 60441da177e4SLinus Torvalds int opts; 60451da177e4SLinus Torvalds char work[20]; 60461da177e4SLinus Torvalds 60479a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 60489a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 60499a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 60501da177e4SLinus Torvalds goto opts_done; 60511da177e4SLinus Torvalds } else { 60529a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 60531da177e4SLinus Torvalds goto opts_done; 60541da177e4SLinus Torvalds } 60551da177e4SLinus Torvalds } 60561da177e4SLinus Torvalds return -EINVAL; 60571da177e4SLinus Torvalds opts_done: 6058773642d9SDouglas Gilbert sdebug_opts = opts; 6059773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 6060773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 6061c4837394SDouglas Gilbert tweak_cmnd_count(); 60621da177e4SLinus Torvalds return count; 60631da177e4SLinus Torvalds } 606482069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 60651da177e4SLinus Torvalds 606682069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 60671da177e4SLinus Torvalds { 6068773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 60691da177e4SLinus Torvalds } 607082069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 607182069379SAkinobu Mita size_t count) 60721da177e4SLinus Torvalds { 60731da177e4SLinus Torvalds int n; 60741da177e4SLinus Torvalds 6075f0d1cf93SDouglas Gilbert /* Cannot change from or to TYPE_ZBC with sysfs */ 6076f0d1cf93SDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) 6077f0d1cf93SDouglas Gilbert return -EINVAL; 6078f0d1cf93SDouglas Gilbert 60791da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6080f0d1cf93SDouglas Gilbert if (n == TYPE_ZBC) 6081f0d1cf93SDouglas Gilbert return -EINVAL; 6082773642d9SDouglas Gilbert sdebug_ptype = n; 60831da177e4SLinus Torvalds return count; 60841da177e4SLinus Torvalds } 60851da177e4SLinus Torvalds return -EINVAL; 60861da177e4SLinus Torvalds } 608782069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 60881da177e4SLinus Torvalds 608982069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 60901da177e4SLinus Torvalds { 6091773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 60921da177e4SLinus Torvalds } 609382069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 609482069379SAkinobu Mita size_t count) 60951da177e4SLinus Torvalds { 60961da177e4SLinus Torvalds int n; 60971da177e4SLinus Torvalds 60981da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6099773642d9SDouglas Gilbert sdebug_dsense = n; 61001da177e4SLinus Torvalds return count; 61011da177e4SLinus Torvalds } 61021da177e4SLinus Torvalds return -EINVAL; 61031da177e4SLinus Torvalds } 610482069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 61051da177e4SLinus Torvalds 610682069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 610723183910SDouglas Gilbert { 6108773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 610923183910SDouglas Gilbert } 611082069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 611182069379SAkinobu Mita size_t count) 611223183910SDouglas Gilbert { 611387c715dcSDouglas Gilbert int n, idx; 611423183910SDouglas Gilbert 611523183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 611687c715dcSDouglas Gilbert bool want_store = (n == 0); 611787c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 611887c715dcSDouglas Gilbert 6119cbf67842SDouglas Gilbert n = (n > 0); 6120773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 612187c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 612287c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 6123cbf67842SDouglas Gilbert 612487c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 612587c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 612687c715dcSDouglas Gilbert idx = sdebug_add_store(); 612787c715dcSDouglas Gilbert if (idx < 0) 612887c715dcSDouglas Gilbert return idx; 612987c715dcSDouglas Gilbert } else { 613087c715dcSDouglas Gilbert idx = sdeb_first_idx; 613187c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 613287c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 6133cbf67842SDouglas Gilbert } 613487c715dcSDouglas Gilbert /* make all hosts use same store */ 613587c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 613687c715dcSDouglas Gilbert host_list) { 613787c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 613887c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 613987c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 614087c715dcSDouglas Gilbert sdhp->si_idx = idx; 614187c715dcSDouglas Gilbert } 614287c715dcSDouglas Gilbert } 614387c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 614487c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 614587c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 6146cbf67842SDouglas Gilbert } 6147773642d9SDouglas Gilbert sdebug_fake_rw = n; 614823183910SDouglas Gilbert return count; 614923183910SDouglas Gilbert } 615023183910SDouglas Gilbert return -EINVAL; 615123183910SDouglas Gilbert } 615282069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 615323183910SDouglas Gilbert 615482069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 6155c65b1445SDouglas Gilbert { 6156773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 6157c65b1445SDouglas Gilbert } 615882069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 615982069379SAkinobu Mita size_t count) 6160c65b1445SDouglas Gilbert { 6161c65b1445SDouglas Gilbert int n; 6162c65b1445SDouglas Gilbert 6163c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6164773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 6165c65b1445SDouglas Gilbert return count; 6166c65b1445SDouglas Gilbert } 6167c65b1445SDouglas Gilbert return -EINVAL; 6168c65b1445SDouglas Gilbert } 616982069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 6170c65b1445SDouglas Gilbert 617182069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 61721da177e4SLinus Torvalds { 6173773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 61741da177e4SLinus Torvalds } 617582069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 617682069379SAkinobu Mita size_t count) 61771da177e4SLinus Torvalds { 61781da177e4SLinus Torvalds int n; 61791da177e4SLinus Torvalds 61801da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6181773642d9SDouglas Gilbert sdebug_num_tgts = n; 61821da177e4SLinus Torvalds sdebug_max_tgts_luns(); 61831da177e4SLinus Torvalds return count; 61841da177e4SLinus Torvalds } 61851da177e4SLinus Torvalds return -EINVAL; 61861da177e4SLinus Torvalds } 618782069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 61881da177e4SLinus Torvalds 618982069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 61901da177e4SLinus Torvalds { 6191773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 61921da177e4SLinus Torvalds } 619382069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 61941da177e4SLinus Torvalds 619587c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 619687c715dcSDouglas Gilbert { 619787c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 619887c715dcSDouglas Gilbert } 619987c715dcSDouglas Gilbert 620087c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 620187c715dcSDouglas Gilbert size_t count) 620287c715dcSDouglas Gilbert { 620387c715dcSDouglas Gilbert bool v; 620487c715dcSDouglas Gilbert 620587c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 620687c715dcSDouglas Gilbert return -EINVAL; 620787c715dcSDouglas Gilbert 620887c715dcSDouglas Gilbert sdebug_per_host_store = v; 620987c715dcSDouglas Gilbert return count; 621087c715dcSDouglas Gilbert } 621187c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 621287c715dcSDouglas Gilbert 621382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 62141da177e4SLinus Torvalds { 6215773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 62161da177e4SLinus Torvalds } 621782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 62181da177e4SLinus Torvalds 621982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 62201da177e4SLinus Torvalds { 6221773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 62221da177e4SLinus Torvalds } 622382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 622482069379SAkinobu Mita size_t count) 62251da177e4SLinus Torvalds { 62261da177e4SLinus Torvalds int nth; 62273a90a63dSDouglas Gilbert char work[20]; 62281da177e4SLinus Torvalds 62293a90a63dSDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 62303a90a63dSDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 62313a90a63dSDouglas Gilbert if (kstrtoint(work + 2, 16, &nth) == 0) 62323a90a63dSDouglas Gilbert goto every_nth_done; 62333a90a63dSDouglas Gilbert } else { 62343a90a63dSDouglas Gilbert if (kstrtoint(work, 10, &nth) == 0) 62353a90a63dSDouglas Gilbert goto every_nth_done; 62363a90a63dSDouglas Gilbert } 62373a90a63dSDouglas Gilbert } 62383a90a63dSDouglas Gilbert return -EINVAL; 62393a90a63dSDouglas Gilbert 62403a90a63dSDouglas Gilbert every_nth_done: 6241773642d9SDouglas Gilbert sdebug_every_nth = nth; 6242c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 6243c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 6244c4837394SDouglas Gilbert sdebug_statistics = true; 6245c4837394SDouglas Gilbert } 6246c4837394SDouglas Gilbert tweak_cmnd_count(); 62471da177e4SLinus Torvalds return count; 62481da177e4SLinus Torvalds } 624982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 62501da177e4SLinus Torvalds 6251ad0c7775SDouglas Gilbert static ssize_t lun_format_show(struct device_driver *ddp, char *buf) 6252ad0c7775SDouglas Gilbert { 6253ad0c7775SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_lun_am); 6254ad0c7775SDouglas Gilbert } 6255ad0c7775SDouglas Gilbert static ssize_t lun_format_store(struct device_driver *ddp, const char *buf, 6256ad0c7775SDouglas Gilbert size_t count) 6257ad0c7775SDouglas Gilbert { 6258ad0c7775SDouglas Gilbert int n; 6259ad0c7775SDouglas Gilbert bool changed; 6260ad0c7775SDouglas Gilbert 6261ad0c7775SDouglas Gilbert if (kstrtoint(buf, 0, &n)) 6262ad0c7775SDouglas Gilbert return -EINVAL; 6263ad0c7775SDouglas Gilbert if (n >= 0) { 6264ad0c7775SDouglas Gilbert if (n > (int)SAM_LUN_AM_FLAT) { 6265ad0c7775SDouglas Gilbert pr_warn("only LUN address methods 0 and 1 are supported\n"); 6266ad0c7775SDouglas Gilbert return -EINVAL; 6267ad0c7775SDouglas Gilbert } 6268ad0c7775SDouglas Gilbert changed = ((int)sdebug_lun_am != n); 6269ad0c7775SDouglas Gilbert sdebug_lun_am = n; 6270ad0c7775SDouglas Gilbert if (changed && sdebug_scsi_level >= 5) { /* >= SPC-3 */ 6271ad0c7775SDouglas Gilbert struct sdebug_host_info *sdhp; 6272ad0c7775SDouglas Gilbert struct sdebug_dev_info *dp; 6273ad0c7775SDouglas Gilbert 6274ad0c7775SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 6275ad0c7775SDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 6276ad0c7775SDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 6277ad0c7775SDouglas Gilbert set_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 6278ad0c7775SDouglas Gilbert } 6279ad0c7775SDouglas Gilbert } 6280ad0c7775SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 6281ad0c7775SDouglas Gilbert } 6282ad0c7775SDouglas Gilbert return count; 6283ad0c7775SDouglas Gilbert } 6284ad0c7775SDouglas Gilbert return -EINVAL; 6285ad0c7775SDouglas Gilbert } 6286ad0c7775SDouglas Gilbert static DRIVER_ATTR_RW(lun_format); 6287ad0c7775SDouglas Gilbert 628882069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 62891da177e4SLinus Torvalds { 6290773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 62911da177e4SLinus Torvalds } 629282069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 629382069379SAkinobu Mita size_t count) 62941da177e4SLinus Torvalds { 62951da177e4SLinus Torvalds int n; 629619c8ead7SEwan D. Milne bool changed; 62971da177e4SLinus Torvalds 62981da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 62998d039e22SDouglas Gilbert if (n > 256) { 63008d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 63018d039e22SDouglas Gilbert return -EINVAL; 63028d039e22SDouglas Gilbert } 6303773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 6304773642d9SDouglas Gilbert sdebug_max_luns = n; 63051da177e4SLinus Torvalds sdebug_max_tgts_luns(); 6306773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 630719c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 630819c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 630919c8ead7SEwan D. Milne 631019c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 631119c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 631219c8ead7SEwan D. Milne host_list) { 631319c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 631419c8ead7SEwan D. Milne dev_list) { 631519c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 631619c8ead7SEwan D. Milne dp->uas_bm); 631719c8ead7SEwan D. Milne } 631819c8ead7SEwan D. Milne } 631919c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 632019c8ead7SEwan D. Milne } 63211da177e4SLinus Torvalds return count; 63221da177e4SLinus Torvalds } 63231da177e4SLinus Torvalds return -EINVAL; 63241da177e4SLinus Torvalds } 632582069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 63261da177e4SLinus Torvalds 632782069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 632878d4e5a0SDouglas Gilbert { 6329773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 633078d4e5a0SDouglas Gilbert } 6331cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 6332cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 633382069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 633482069379SAkinobu Mita size_t count) 633578d4e5a0SDouglas Gilbert { 6336c4837394SDouglas Gilbert int j, n, k, a; 6337c4837394SDouglas Gilbert struct sdebug_queue *sqp; 633878d4e5a0SDouglas Gilbert 633978d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 6340c10fa55fSJohn Garry (n <= SDEBUG_CANQUEUE) && 6341c10fa55fSJohn Garry (sdebug_host_max_queue == 0)) { 63422aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 6343c4837394SDouglas Gilbert k = 0; 6344c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 6345c4837394SDouglas Gilbert ++j, ++sqp) { 6346c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 6347c4837394SDouglas Gilbert if (a > k) 6348c4837394SDouglas Gilbert k = a; 6349c4837394SDouglas Gilbert } 6350773642d9SDouglas Gilbert sdebug_max_queue = n; 6351c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 6352cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6353cbf67842SDouglas Gilbert else if (k >= n) 6354cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 6355cbf67842SDouglas Gilbert else 6356cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 63572aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 635878d4e5a0SDouglas Gilbert return count; 635978d4e5a0SDouglas Gilbert } 636078d4e5a0SDouglas Gilbert return -EINVAL; 636178d4e5a0SDouglas Gilbert } 636282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 636378d4e5a0SDouglas Gilbert 6364c10fa55fSJohn Garry static ssize_t host_max_queue_show(struct device_driver *ddp, char *buf) 6365c10fa55fSJohn Garry { 6366c10fa55fSJohn Garry return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_host_max_queue); 6367c10fa55fSJohn Garry } 6368c10fa55fSJohn Garry 6369c10fa55fSJohn Garry /* 6370c10fa55fSJohn Garry * Since this is used for .can_queue, and we get the hc_idx tag from the bitmap 6371c10fa55fSJohn Garry * in range [0, sdebug_host_max_queue), we can't change it. 6372c10fa55fSJohn Garry */ 6373c10fa55fSJohn Garry static DRIVER_ATTR_RO(host_max_queue); 6374c10fa55fSJohn Garry 637582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 637678d4e5a0SDouglas Gilbert { 6377773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 637878d4e5a0SDouglas Gilbert } 637982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 638078d4e5a0SDouglas Gilbert 638182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 63821da177e4SLinus Torvalds { 6383773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 63841da177e4SLinus Torvalds } 638582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 63861da177e4SLinus Torvalds 638782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 6388c65b1445SDouglas Gilbert { 6389773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 6390c65b1445SDouglas Gilbert } 639182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 639282069379SAkinobu Mita size_t count) 6393c65b1445SDouglas Gilbert { 6394c65b1445SDouglas Gilbert int n; 63950d01c5dfSDouglas Gilbert bool changed; 6396c65b1445SDouglas Gilbert 6397f0d1cf93SDouglas Gilbert /* Ignore capacity change for ZBC drives for now */ 6398f0d1cf93SDouglas Gilbert if (sdeb_zbc_in_use) 6399f0d1cf93SDouglas Gilbert return -ENOTSUPP; 6400f0d1cf93SDouglas Gilbert 6401c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6402773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 6403773642d9SDouglas Gilbert sdebug_virtual_gb = n; 640428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 64050d01c5dfSDouglas Gilbert if (changed) { 64060d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 64070d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 640828898873SFUJITA Tomonori 64094bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 64100d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 64110d01c5dfSDouglas Gilbert host_list) { 64120d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 64130d01c5dfSDouglas Gilbert dev_list) { 64140d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 64150d01c5dfSDouglas Gilbert dp->uas_bm); 64160d01c5dfSDouglas Gilbert } 64170d01c5dfSDouglas Gilbert } 64184bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 64190d01c5dfSDouglas Gilbert } 6420c65b1445SDouglas Gilbert return count; 6421c65b1445SDouglas Gilbert } 6422c65b1445SDouglas Gilbert return -EINVAL; 6423c65b1445SDouglas Gilbert } 642482069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 6425c65b1445SDouglas Gilbert 642682069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 64271da177e4SLinus Torvalds { 642887c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 64292aad3cd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&sdebug_num_hosts)); 64301da177e4SLinus Torvalds } 64311da177e4SLinus Torvalds 64322aad3cd8SDouglas Gilbert /* 64332aad3cd8SDouglas Gilbert * Accept positive and negative values. Hex values (only positive) may be prefixed by '0x'. 64342aad3cd8SDouglas Gilbert * To remove all hosts use a large negative number (e.g. -9999). The value 0 does nothing. 64352aad3cd8SDouglas Gilbert * Returns -EBUSY if another add_host sysfs invocation is active. 64362aad3cd8SDouglas Gilbert */ 643782069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 643882069379SAkinobu Mita size_t count) 64391da177e4SLinus Torvalds { 64401da177e4SLinus Torvalds int delta_hosts; 64411da177e4SLinus Torvalds 64422aad3cd8SDouglas Gilbert if (count == 0 || kstrtoint(buf, 0, &delta_hosts)) 64431da177e4SLinus Torvalds return -EINVAL; 64442aad3cd8SDouglas Gilbert if (sdebug_verbose) 64452aad3cd8SDouglas Gilbert pr_info("prior num_hosts=%d, num_to_add=%d\n", 64462aad3cd8SDouglas Gilbert atomic_read(&sdebug_num_hosts), delta_hosts); 64472aad3cd8SDouglas Gilbert if (delta_hosts == 0) 64482aad3cd8SDouglas Gilbert return count; 64492aad3cd8SDouglas Gilbert if (mutex_trylock(&add_host_mutex) == 0) 64502aad3cd8SDouglas Gilbert return -EBUSY; 64511da177e4SLinus Torvalds if (delta_hosts > 0) { 64522aad3cd8SDouglas Gilbert sdeb_add_n_hosts(delta_hosts); 64532aad3cd8SDouglas Gilbert } else if (delta_hosts < 0) { 64542aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, true); 64552aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 64562aad3cd8SDouglas Gilbert if (delta_hosts >= atomic_read(&sdebug_num_hosts)) 64572aad3cd8SDouglas Gilbert stop_all_queued(true); 64581da177e4SLinus Torvalds do { 64592aad3cd8SDouglas Gilbert if (atomic_read(&sdebug_num_hosts) < 1) { 64602aad3cd8SDouglas Gilbert free_all_queued(); 646187c715dcSDouglas Gilbert break; 646287c715dcSDouglas Gilbert } 646387c715dcSDouglas Gilbert sdebug_do_remove_host(false); 64641da177e4SLinus Torvalds } while (++delta_hosts); 64652aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 64662aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, false); 64671da177e4SLinus Torvalds } 64682aad3cd8SDouglas Gilbert mutex_unlock(&add_host_mutex); 64692aad3cd8SDouglas Gilbert if (sdebug_verbose) 64702aad3cd8SDouglas Gilbert pr_info("post num_hosts=%d\n", atomic_read(&sdebug_num_hosts)); 64711da177e4SLinus Torvalds return count; 64721da177e4SLinus Torvalds } 647382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 64741da177e4SLinus Torvalds 647582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 647623183910SDouglas Gilbert { 6477773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 647823183910SDouglas Gilbert } 647982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 648082069379SAkinobu Mita size_t count) 648123183910SDouglas Gilbert { 648223183910SDouglas Gilbert int n; 648323183910SDouglas Gilbert 648423183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6485773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 648623183910SDouglas Gilbert return count; 648723183910SDouglas Gilbert } 648823183910SDouglas Gilbert return -EINVAL; 648923183910SDouglas Gilbert } 649082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 649123183910SDouglas Gilbert 6492c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 6493c4837394SDouglas Gilbert { 6494c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 6495c4837394SDouglas Gilbert } 6496c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 6497c4837394SDouglas Gilbert size_t count) 6498c4837394SDouglas Gilbert { 6499c4837394SDouglas Gilbert int n; 6500c4837394SDouglas Gilbert 6501c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 6502c4837394SDouglas Gilbert if (n > 0) 6503c4837394SDouglas Gilbert sdebug_statistics = true; 6504c4837394SDouglas Gilbert else { 6505c4837394SDouglas Gilbert clear_queue_stats(); 6506c4837394SDouglas Gilbert sdebug_statistics = false; 6507c4837394SDouglas Gilbert } 6508c4837394SDouglas Gilbert return count; 6509c4837394SDouglas Gilbert } 6510c4837394SDouglas Gilbert return -EINVAL; 6511c4837394SDouglas Gilbert } 6512c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 6513c4837394SDouglas Gilbert 651482069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 6515597136abSMartin K. Petersen { 6516773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 6517597136abSMartin K. Petersen } 651882069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 6519597136abSMartin K. Petersen 6520c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 6521c4837394SDouglas Gilbert { 6522c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 6523c4837394SDouglas Gilbert } 6524c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 6525c4837394SDouglas Gilbert 652682069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 6527c6a44287SMartin K. Petersen { 6528773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 6529c6a44287SMartin K. Petersen } 653082069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 6531c6a44287SMartin K. Petersen 653282069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 6533c6a44287SMartin K. Petersen { 6534773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 6535c6a44287SMartin K. Petersen } 653682069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 6537c6a44287SMartin K. Petersen 653882069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 6539c6a44287SMartin K. Petersen { 6540773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 6541c6a44287SMartin K. Petersen } 654282069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 6543c6a44287SMartin K. Petersen 654482069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 6545c6a44287SMartin K. Petersen { 6546773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 6547c6a44287SMartin K. Petersen } 654882069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 6549c6a44287SMartin K. Petersen 655082069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 655144d92694SMartin K. Petersen { 655287c715dcSDouglas Gilbert ssize_t count = 0; 655344d92694SMartin K. Petersen 65545b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 655544d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 655644d92694SMartin K. Petersen sdebug_store_sectors); 655744d92694SMartin K. Petersen 655887c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 655987c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 656087c715dcSDouglas Gilbert 656187c715dcSDouglas Gilbert if (sip) 6562c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 656387c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 656487c715dcSDouglas Gilbert } 656544d92694SMartin K. Petersen buf[count++] = '\n'; 6566c7badc90STejun Heo buf[count] = '\0'; 656744d92694SMartin K. Petersen 656844d92694SMartin K. Petersen return count; 656944d92694SMartin K. Petersen } 657082069379SAkinobu Mita static DRIVER_ATTR_RO(map); 657144d92694SMartin K. Petersen 65720c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 65730c4bc91dSDouglas Gilbert { 65740c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 65750c4bc91dSDouglas Gilbert } 65760c4bc91dSDouglas Gilbert 65770c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 65780c4bc91dSDouglas Gilbert size_t count) 65790c4bc91dSDouglas Gilbert { 65800c4bc91dSDouglas Gilbert bool v; 65810c4bc91dSDouglas Gilbert 65820c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 65830c4bc91dSDouglas Gilbert return -EINVAL; 65840c4bc91dSDouglas Gilbert 65850c4bc91dSDouglas Gilbert sdebug_random = v; 65860c4bc91dSDouglas Gilbert return count; 65870c4bc91dSDouglas Gilbert } 65880c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 65890c4bc91dSDouglas Gilbert 659082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 6591d986788bSMartin Pitt { 6592773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 6593d986788bSMartin Pitt } 659482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 659582069379SAkinobu Mita size_t count) 6596d986788bSMartin Pitt { 6597d986788bSMartin Pitt int n; 6598d986788bSMartin Pitt 6599d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6600773642d9SDouglas Gilbert sdebug_removable = (n > 0); 6601d986788bSMartin Pitt return count; 6602d986788bSMartin Pitt } 6603d986788bSMartin Pitt return -EINVAL; 6604d986788bSMartin Pitt } 660582069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 6606d986788bSMartin Pitt 6607cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 6608cbf67842SDouglas Gilbert { 6609773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 6610cbf67842SDouglas Gilbert } 6611185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 6612cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 6613cbf67842SDouglas Gilbert size_t count) 6614cbf67842SDouglas Gilbert { 6615185dd232SDouglas Gilbert int n; 6616cbf67842SDouglas Gilbert 6617cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6618185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 6619185dd232SDouglas Gilbert return count; 6620cbf67842SDouglas Gilbert } 6621cbf67842SDouglas Gilbert return -EINVAL; 6622cbf67842SDouglas Gilbert } 6623cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 6624cbf67842SDouglas Gilbert 6625c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 6626c2248fc9SDouglas Gilbert { 6627773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 6628c2248fc9SDouglas Gilbert } 6629c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 6630c2248fc9SDouglas Gilbert size_t count) 6631c2248fc9SDouglas Gilbert { 6632c2248fc9SDouglas Gilbert int n; 6633c2248fc9SDouglas Gilbert 6634c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 6635773642d9SDouglas Gilbert sdebug_strict = (n > 0); 6636c2248fc9SDouglas Gilbert return count; 6637c2248fc9SDouglas Gilbert } 6638c2248fc9SDouglas Gilbert return -EINVAL; 6639c2248fc9SDouglas Gilbert } 6640c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 6641c2248fc9SDouglas Gilbert 664209ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 664309ba24c1SDouglas Gilbert { 664409ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 664509ba24c1SDouglas Gilbert } 664609ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 664709ba24c1SDouglas Gilbert 66489b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 66499b760fd8SDouglas Gilbert { 66509b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 66519b760fd8SDouglas Gilbert } 66529b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 66539b760fd8SDouglas Gilbert size_t count) 66549b760fd8SDouglas Gilbert { 66559b760fd8SDouglas Gilbert int ret, n; 66569b760fd8SDouglas Gilbert 66579b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 66589b760fd8SDouglas Gilbert if (ret) 66599b760fd8SDouglas Gilbert return ret; 66609b760fd8SDouglas Gilbert sdebug_cdb_len = n; 66619b760fd8SDouglas Gilbert all_config_cdb_len(); 66629b760fd8SDouglas Gilbert return count; 66639b760fd8SDouglas Gilbert } 66649b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 66659b760fd8SDouglas Gilbert 66669267e0ebSDouglas Gilbert static const char * const zbc_model_strs_a[] = { 66679267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "none", 66689267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "host-aware", 66699267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "host-managed", 66709267e0ebSDouglas Gilbert }; 66719267e0ebSDouglas Gilbert 66729267e0ebSDouglas Gilbert static const char * const zbc_model_strs_b[] = { 66739267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "no", 66749267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "aware", 66759267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "managed", 66769267e0ebSDouglas Gilbert }; 66779267e0ebSDouglas Gilbert 66789267e0ebSDouglas Gilbert static const char * const zbc_model_strs_c[] = { 66799267e0ebSDouglas Gilbert [BLK_ZONED_NONE] = "0", 66809267e0ebSDouglas Gilbert [BLK_ZONED_HA] = "1", 66819267e0ebSDouglas Gilbert [BLK_ZONED_HM] = "2", 66829267e0ebSDouglas Gilbert }; 66839267e0ebSDouglas Gilbert 66849267e0ebSDouglas Gilbert static int sdeb_zbc_model_str(const char *cp) 66859267e0ebSDouglas Gilbert { 66869267e0ebSDouglas Gilbert int res = sysfs_match_string(zbc_model_strs_a, cp); 66879267e0ebSDouglas Gilbert 66889267e0ebSDouglas Gilbert if (res < 0) { 66899267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_b, cp); 66909267e0ebSDouglas Gilbert if (res < 0) { 66919267e0ebSDouglas Gilbert res = sysfs_match_string(zbc_model_strs_c, cp); 669247742bdeSDan Carpenter if (res < 0) 66939267e0ebSDouglas Gilbert return -EINVAL; 66949267e0ebSDouglas Gilbert } 66959267e0ebSDouglas Gilbert } 66969267e0ebSDouglas Gilbert return res; 66979267e0ebSDouglas Gilbert } 66989267e0ebSDouglas Gilbert 66999267e0ebSDouglas Gilbert static ssize_t zbc_show(struct device_driver *ddp, char *buf) 67009267e0ebSDouglas Gilbert { 67019267e0ebSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%s\n", 67029267e0ebSDouglas Gilbert zbc_model_strs_a[sdeb_zbc_model]); 67039267e0ebSDouglas Gilbert } 67049267e0ebSDouglas Gilbert static DRIVER_ATTR_RO(zbc); 6705cbf67842SDouglas Gilbert 6706fc13638aSDouglas Gilbert static ssize_t tur_ms_to_ready_show(struct device_driver *ddp, char *buf) 6707fc13638aSDouglas Gilbert { 6708fc13638aSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdeb_tur_ms_to_ready); 6709fc13638aSDouglas Gilbert } 6710fc13638aSDouglas Gilbert static DRIVER_ATTR_RO(tur_ms_to_ready); 6711fc13638aSDouglas Gilbert 671282069379SAkinobu Mita /* Note: The following array creates attribute files in the 671323183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 671423183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 671523183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 671687c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 671723183910SDouglas Gilbert */ 67186ecaff7fSRandy Dunlap 671982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 672082069379SAkinobu Mita &driver_attr_delay.attr, 672182069379SAkinobu Mita &driver_attr_opts.attr, 672282069379SAkinobu Mita &driver_attr_ptype.attr, 672382069379SAkinobu Mita &driver_attr_dsense.attr, 672482069379SAkinobu Mita &driver_attr_fake_rw.attr, 6725c10fa55fSJohn Garry &driver_attr_host_max_queue.attr, 672682069379SAkinobu Mita &driver_attr_no_lun_0.attr, 672782069379SAkinobu Mita &driver_attr_num_tgts.attr, 672882069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 672982069379SAkinobu Mita &driver_attr_num_parts.attr, 673082069379SAkinobu Mita &driver_attr_every_nth.attr, 6731ad0c7775SDouglas Gilbert &driver_attr_lun_format.attr, 673282069379SAkinobu Mita &driver_attr_max_luns.attr, 673382069379SAkinobu Mita &driver_attr_max_queue.attr, 673482069379SAkinobu Mita &driver_attr_no_uld.attr, 673582069379SAkinobu Mita &driver_attr_scsi_level.attr, 673682069379SAkinobu Mita &driver_attr_virtual_gb.attr, 673782069379SAkinobu Mita &driver_attr_add_host.attr, 673887c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 673982069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 674082069379SAkinobu Mita &driver_attr_sector_size.attr, 6741c4837394SDouglas Gilbert &driver_attr_statistics.attr, 6742c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 674382069379SAkinobu Mita &driver_attr_dix.attr, 674482069379SAkinobu Mita &driver_attr_dif.attr, 674582069379SAkinobu Mita &driver_attr_guard.attr, 674682069379SAkinobu Mita &driver_attr_ato.attr, 674782069379SAkinobu Mita &driver_attr_map.attr, 67480c4bc91dSDouglas Gilbert &driver_attr_random.attr, 674982069379SAkinobu Mita &driver_attr_removable.attr, 6750cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 6751cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 6752c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 675309ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 67549b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 6755fc13638aSDouglas Gilbert &driver_attr_tur_ms_to_ready.attr, 67569267e0ebSDouglas Gilbert &driver_attr_zbc.attr, 675782069379SAkinobu Mita NULL, 675882069379SAkinobu Mita }; 675982069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 67601da177e4SLinus Torvalds 676111ddcecaSAkinobu Mita static struct device *pseudo_primary; 67628dea0d02SFUJITA Tomonori 67631da177e4SLinus Torvalds static int __init scsi_debug_init(void) 67641da177e4SLinus Torvalds { 676587c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 67665f2578e5SFUJITA Tomonori unsigned long sz; 676787c715dcSDouglas Gilbert int k, ret, hosts_to_add; 676887c715dcSDouglas Gilbert int idx = -1; 67691da177e4SLinus Torvalds 677087c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 677187c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 6772cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 6773cbf67842SDouglas Gilbert 6774773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 6775c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 6776773642d9SDouglas Gilbert sdebug_ndelay = 0; 6777773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 6778c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 6779cbf67842SDouglas Gilbert 6780773642d9SDouglas Gilbert switch (sdebug_sector_size) { 6781597136abSMartin K. Petersen case 512: 6782597136abSMartin K. Petersen case 1024: 6783597136abSMartin K. Petersen case 2048: 6784597136abSMartin K. Petersen case 4096: 6785597136abSMartin K. Petersen break; 6786597136abSMartin K. Petersen default: 6787773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 6788597136abSMartin K. Petersen return -EINVAL; 6789597136abSMartin K. Petersen } 6790597136abSMartin K. Petersen 6791773642d9SDouglas Gilbert switch (sdebug_dif) { 67928475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 6793f46eb0e9SDouglas Gilbert break; 67948475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 67958475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 67968475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6797f46eb0e9SDouglas Gilbert have_dif_prot = true; 6798c6a44287SMartin K. Petersen break; 6799c6a44287SMartin K. Petersen 6800c6a44287SMartin K. Petersen default: 6801c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 6802c6a44287SMartin K. Petersen return -EINVAL; 6803c6a44287SMartin K. Petersen } 6804c6a44287SMartin K. Petersen 6805aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 6806aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 6807aa5334c4SMaurizio Lombardi return -EINVAL; 6808aa5334c4SMaurizio Lombardi } 6809aa5334c4SMaurizio Lombardi 6810773642d9SDouglas Gilbert if (sdebug_guard > 1) { 6811c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 6812c6a44287SMartin K. Petersen return -EINVAL; 6813c6a44287SMartin K. Petersen } 6814c6a44287SMartin K. Petersen 6815773642d9SDouglas Gilbert if (sdebug_ato > 1) { 6816c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 6817c6a44287SMartin K. Petersen return -EINVAL; 6818c6a44287SMartin K. Petersen } 6819c6a44287SMartin K. Petersen 6820773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 6821773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 6822ea61fca5SMartin K. Petersen return -EINVAL; 6823ea61fca5SMartin K. Petersen } 6824ad0c7775SDouglas Gilbert 6825ad0c7775SDouglas Gilbert sdebug_lun_am = sdebug_lun_am_i; 6826ad0c7775SDouglas Gilbert if (sdebug_lun_am > SAM_LUN_AM_FLAT) { 6827ad0c7775SDouglas Gilbert pr_warn("Invalid LUN format %u, using default\n", (int)sdebug_lun_am); 6828ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_PERIPHERAL; 6829ad0c7775SDouglas Gilbert } 6830ad0c7775SDouglas Gilbert 68318d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 6832ad0c7775SDouglas Gilbert if (sdebug_max_luns > 16384) { 6833ad0c7775SDouglas Gilbert pr_warn("max_luns can be no more than 16384, use default\n"); 68348d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 68358d039e22SDouglas Gilbert } 6836ad0c7775SDouglas Gilbert sdebug_lun_am = SAM_LUN_AM_FLAT; 6837ad0c7775SDouglas Gilbert } 6838ea61fca5SMartin K. Petersen 6839773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 6840773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 6841ea61fca5SMartin K. Petersen return -EINVAL; 6842ea61fca5SMartin K. Petersen } 6843ea61fca5SMartin K. Petersen 6844c4837394SDouglas Gilbert if (submit_queues < 1) { 6845c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 6846c4837394SDouglas Gilbert return -EINVAL; 6847c4837394SDouglas Gilbert } 6848c87bf24cSJohn Garry 6849c87bf24cSJohn Garry if ((sdebug_max_queue > SDEBUG_CANQUEUE) || (sdebug_max_queue < 1)) { 6850c87bf24cSJohn Garry pr_err("max_queue must be in range [1, %d]\n", SDEBUG_CANQUEUE); 6851c87bf24cSJohn Garry return -EINVAL; 6852c87bf24cSJohn Garry } 6853c87bf24cSJohn Garry 6854c10fa55fSJohn Garry if ((sdebug_host_max_queue > SDEBUG_CANQUEUE) || 6855c10fa55fSJohn Garry (sdebug_host_max_queue < 0)) { 6856c10fa55fSJohn Garry pr_err("host_max_queue must be in range [0 %d]\n", 6857c10fa55fSJohn Garry SDEBUG_CANQUEUE); 6858c10fa55fSJohn Garry return -EINVAL; 6859c10fa55fSJohn Garry } 6860c10fa55fSJohn Garry 6861c10fa55fSJohn Garry if (sdebug_host_max_queue && 6862c10fa55fSJohn Garry (sdebug_max_queue != sdebug_host_max_queue)) { 6863c10fa55fSJohn Garry sdebug_max_queue = sdebug_host_max_queue; 6864c10fa55fSJohn Garry pr_warn("fixing max submit queue depth to host max queue depth, %d\n", 6865c10fa55fSJohn Garry sdebug_max_queue); 6866c10fa55fSJohn Garry } 6867c10fa55fSJohn Garry 6868c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 6869c4837394SDouglas Gilbert GFP_KERNEL); 6870c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 6871c4837394SDouglas Gilbert return -ENOMEM; 6872c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 6873c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 6874c4837394SDouglas Gilbert 6875f0d1cf93SDouglas Gilbert /* 68769267e0ebSDouglas Gilbert * check for host managed zoned block device specified with 68779267e0ebSDouglas Gilbert * ptype=0x14 or zbc=XXX. 6878f0d1cf93SDouglas Gilbert */ 68799267e0ebSDouglas Gilbert if (sdebug_ptype == TYPE_ZBC) { 68809267e0ebSDouglas Gilbert sdeb_zbc_model = BLK_ZONED_HM; 68819267e0ebSDouglas Gilbert } else if (sdeb_zbc_model_s && *sdeb_zbc_model_s) { 68829267e0ebSDouglas Gilbert k = sdeb_zbc_model_str(sdeb_zbc_model_s); 68839267e0ebSDouglas Gilbert if (k < 0) { 68849267e0ebSDouglas Gilbert ret = k; 68853b01d7eaSDinghao Liu goto free_q_arr; 68869267e0ebSDouglas Gilbert } 68879267e0ebSDouglas Gilbert sdeb_zbc_model = k; 68889267e0ebSDouglas Gilbert switch (sdeb_zbc_model) { 68899267e0ebSDouglas Gilbert case BLK_ZONED_NONE: 689064e14eceSDamien Le Moal case BLK_ZONED_HA: 68919267e0ebSDouglas Gilbert sdebug_ptype = TYPE_DISK; 68929267e0ebSDouglas Gilbert break; 68939267e0ebSDouglas Gilbert case BLK_ZONED_HM: 68949267e0ebSDouglas Gilbert sdebug_ptype = TYPE_ZBC; 68959267e0ebSDouglas Gilbert break; 68969267e0ebSDouglas Gilbert default: 68979267e0ebSDouglas Gilbert pr_err("Invalid ZBC model\n"); 68983b01d7eaSDinghao Liu ret = -EINVAL; 68993b01d7eaSDinghao Liu goto free_q_arr; 69009267e0ebSDouglas Gilbert } 69019267e0ebSDouglas Gilbert } 69029267e0ebSDouglas Gilbert if (sdeb_zbc_model != BLK_ZONED_NONE) { 6903f0d1cf93SDouglas Gilbert sdeb_zbc_in_use = true; 69049267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 69059267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_ZBC_DEV_SIZE_MB; 69069267e0ebSDouglas Gilbert } 6907f0d1cf93SDouglas Gilbert 69089267e0ebSDouglas Gilbert if (sdebug_dev_size_mb == DEF_DEV_SIZE_PRE_INIT) 69099267e0ebSDouglas Gilbert sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 6910773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 6911773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 6912773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 6913773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 691428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 69151da177e4SLinus Torvalds 69161da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 69171da177e4SLinus Torvalds sdebug_heads = 8; 69181da177e4SLinus Torvalds sdebug_sectors_per = 32; 6919773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 69201da177e4SLinus Torvalds sdebug_heads = 64; 6921773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 6922fa785f0aSAndy Shevchenko sdebug_heads = 32; 69231da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 69241da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 69251da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 69261da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 69271da177e4SLinus Torvalds sdebug_heads = 255; 69281da177e4SLinus Torvalds sdebug_sectors_per = 63; 69291da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 69301da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 69311da177e4SLinus Torvalds } 69325b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 6933773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 6934773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 69356014759cSMartin K. Petersen 6936773642d9SDouglas Gilbert sdebug_unmap_max_desc = 6937773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 69386014759cSMartin K. Petersen 6939773642d9SDouglas Gilbert sdebug_unmap_granularity = 6940773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 69416014759cSMartin K. Petersen 6942773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 6943773642d9SDouglas Gilbert sdebug_unmap_granularity <= 6944773642d9SDouglas Gilbert sdebug_unmap_alignment) { 6945c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 6946c4837394SDouglas Gilbert ret = -EINVAL; 694787c715dcSDouglas Gilbert goto free_q_arr; 694844d92694SMartin K. Petersen } 694944d92694SMartin K. Petersen } 695087c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 695187c715dcSDouglas Gilbert if (want_store) { 695287c715dcSDouglas Gilbert idx = sdebug_add_store(); 695387c715dcSDouglas Gilbert if (idx < 0) { 695487c715dcSDouglas Gilbert ret = idx; 695587c715dcSDouglas Gilbert goto free_q_arr; 695687c715dcSDouglas Gilbert } 695744d92694SMartin K. Petersen } 695844d92694SMartin K. Petersen 69599b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 69609b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 6961c1287970STomas Winkler pr_warn("root_device_register() error\n"); 69629b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 69636ecaff7fSRandy Dunlap goto free_vm; 69646ecaff7fSRandy Dunlap } 69656ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 69666ecaff7fSRandy Dunlap if (ret < 0) { 6967c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 69686ecaff7fSRandy Dunlap goto dev_unreg; 69696ecaff7fSRandy Dunlap } 69706ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 69716ecaff7fSRandy Dunlap if (ret < 0) { 6972c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 69736ecaff7fSRandy Dunlap goto bus_unreg; 69746ecaff7fSRandy Dunlap } 69751da177e4SLinus Torvalds 697687c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 6977773642d9SDouglas Gilbert sdebug_add_host = 0; 69781da177e4SLinus Torvalds 697987c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 69802aad3cd8SDouglas Gilbert if (smp_load_acquire(&sdebug_deflect_incoming)) { 69812aad3cd8SDouglas Gilbert pr_info("exit early as sdebug_deflect_incoming is set\n"); 69822aad3cd8SDouglas Gilbert return 0; 69832aad3cd8SDouglas Gilbert } 698487c715dcSDouglas Gilbert if (want_store && k == 0) { 698587c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 698687c715dcSDouglas Gilbert if (ret < 0) { 698787c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 698887c715dcSDouglas Gilbert k, -ret); 698987c715dcSDouglas Gilbert break; 699087c715dcSDouglas Gilbert } 699187c715dcSDouglas Gilbert } else { 699287c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 699387c715dcSDouglas Gilbert sdebug_per_host_store); 699487c715dcSDouglas Gilbert if (ret < 0) { 699587c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 69961da177e4SLinus Torvalds break; 69971da177e4SLinus Torvalds } 69981da177e4SLinus Torvalds } 699987c715dcSDouglas Gilbert } 7000773642d9SDouglas Gilbert if (sdebug_verbose) 70012aad3cd8SDouglas Gilbert pr_info("built %d host(s)\n", atomic_read(&sdebug_num_hosts)); 7002c1287970STomas Winkler 70032aad3cd8SDouglas Gilbert /* 70042aad3cd8SDouglas Gilbert * Even though all the hosts have been established, due to async device (LU) scanning 70052aad3cd8SDouglas Gilbert * by the scsi mid-level, there may still be devices (LUs) being set up. 70062aad3cd8SDouglas Gilbert */ 70071da177e4SLinus Torvalds return 0; 70086ecaff7fSRandy Dunlap 70096ecaff7fSRandy Dunlap bus_unreg: 70106ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 70116ecaff7fSRandy Dunlap dev_unreg: 70129b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 70136ecaff7fSRandy Dunlap free_vm: 701487c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 7015c4837394SDouglas Gilbert free_q_arr: 7016c4837394SDouglas Gilbert kfree(sdebug_q_arr); 70176ecaff7fSRandy Dunlap return ret; 70181da177e4SLinus Torvalds } 70191da177e4SLinus Torvalds 70201da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 70211da177e4SLinus Torvalds { 70222aad3cd8SDouglas Gilbert int k; 70231da177e4SLinus Torvalds 70242aad3cd8SDouglas Gilbert /* Possible race with LUs still being set up; stop them asap */ 70252aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 70262aad3cd8SDouglas Gilbert smp_store_release(&sdebug_deflect_incoming, true); 70272aad3cd8SDouglas Gilbert stop_all_queued(false); 70282aad3cd8SDouglas Gilbert for (k = 0; atomic_read(&sdebug_num_hosts) > 0; k++) 702987c715dcSDouglas Gilbert sdebug_do_remove_host(true); 703052ab9768SLuis Henriques free_all_queued(); 70312aad3cd8SDouglas Gilbert if (sdebug_verbose) 70322aad3cd8SDouglas Gilbert pr_info("removed %d hosts\n", k); 70331da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 70341da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 70359b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 70361da177e4SLinus Torvalds 703787c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 703887c715dcSDouglas Gilbert xa_destroy(per_store_ap); 7039f852c596SMaurizio Lombardi kfree(sdebug_q_arr); 70401da177e4SLinus Torvalds } 70411da177e4SLinus Torvalds 70421da177e4SLinus Torvalds device_initcall(scsi_debug_init); 70431da177e4SLinus Torvalds module_exit(scsi_debug_exit); 70441da177e4SLinus Torvalds 70451da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 70461da177e4SLinus Torvalds { 70471da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 70481da177e4SLinus Torvalds 70491da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 70501da177e4SLinus Torvalds kfree(sdbg_host); 70511da177e4SLinus Torvalds } 70521da177e4SLinus Torvalds 705387c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 705487c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 70551da177e4SLinus Torvalds { 705687c715dcSDouglas Gilbert if (idx < 0) 705787c715dcSDouglas Gilbert return; 705887c715dcSDouglas Gilbert if (!sip) { 705987c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 706087c715dcSDouglas Gilbert return; 706187c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 706287c715dcSDouglas Gilbert if (!sip) 706387c715dcSDouglas Gilbert return; 706487c715dcSDouglas Gilbert } 706587c715dcSDouglas Gilbert vfree(sip->map_storep); 706687c715dcSDouglas Gilbert vfree(sip->dif_storep); 706787c715dcSDouglas Gilbert vfree(sip->storep); 706887c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 706987c715dcSDouglas Gilbert kfree(sip); 707087c715dcSDouglas Gilbert } 707187c715dcSDouglas Gilbert 707287c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 707387c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 707487c715dcSDouglas Gilbert { 707587c715dcSDouglas Gilbert unsigned long idx; 707687c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 707787c715dcSDouglas Gilbert 707887c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 707987c715dcSDouglas Gilbert if (apart_from_first) 708087c715dcSDouglas Gilbert apart_from_first = false; 708187c715dcSDouglas Gilbert else 708287c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 708387c715dcSDouglas Gilbert } 708487c715dcSDouglas Gilbert if (apart_from_first) 708587c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 708687c715dcSDouglas Gilbert } 708787c715dcSDouglas Gilbert 708887c715dcSDouglas Gilbert /* 708987c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 709087c715dcSDouglas Gilbert * Limit the number of stores to 65536. 709187c715dcSDouglas Gilbert */ 709287c715dcSDouglas Gilbert static int sdebug_add_store(void) 709387c715dcSDouglas Gilbert { 709487c715dcSDouglas Gilbert int res; 709587c715dcSDouglas Gilbert u32 n_idx; 709687c715dcSDouglas Gilbert unsigned long iflags; 709787c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 709887c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 709987c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 710087c715dcSDouglas Gilbert 710187c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 710287c715dcSDouglas Gilbert if (!sip) 710387c715dcSDouglas Gilbert return -ENOMEM; 710487c715dcSDouglas Gilbert 710587c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 710687c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 710787c715dcSDouglas Gilbert if (unlikely(res < 0)) { 710887c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 710987c715dcSDouglas Gilbert kfree(sip); 711087c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 711187c715dcSDouglas Gilbert return res; 711287c715dcSDouglas Gilbert } 711387c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 711487c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 711587c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 711687c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 711787c715dcSDouglas Gilbert 711887c715dcSDouglas Gilbert res = -ENOMEM; 711987c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 712087c715dcSDouglas Gilbert if (!sip->storep) { 712187c715dcSDouglas Gilbert pr_err("user data oom\n"); 712287c715dcSDouglas Gilbert goto err; 712387c715dcSDouglas Gilbert } 712487c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 712587c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 712687c715dcSDouglas Gilbert 712787c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 712887c715dcSDouglas Gilbert if (sdebug_dix) { 712987c715dcSDouglas Gilbert int dif_size; 713087c715dcSDouglas Gilbert 713187c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 713287c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 713387c715dcSDouglas Gilbert 713487c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 713587c715dcSDouglas Gilbert sip->dif_storep); 713687c715dcSDouglas Gilbert 713787c715dcSDouglas Gilbert if (!sip->dif_storep) { 713887c715dcSDouglas Gilbert pr_err("DIX oom\n"); 713987c715dcSDouglas Gilbert goto err; 714087c715dcSDouglas Gilbert } 714187c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 714287c715dcSDouglas Gilbert } 714387c715dcSDouglas Gilbert /* Logical Block Provisioning */ 714487c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 714587c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 714687c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 714787c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 714887c715dcSDouglas Gilbert 714987c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 715087c715dcSDouglas Gilbert 715187c715dcSDouglas Gilbert if (!sip->map_storep) { 715287c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 715387c715dcSDouglas Gilbert goto err; 715487c715dcSDouglas Gilbert } 715587c715dcSDouglas Gilbert 715687c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 715787c715dcSDouglas Gilbert 715887c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 715987c715dcSDouglas Gilbert if (sdebug_num_parts) 716087c715dcSDouglas Gilbert map_region(sip, 0, 2); 716187c715dcSDouglas Gilbert } 716287c715dcSDouglas Gilbert 716387c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 716487c715dcSDouglas Gilbert return (int)n_idx; 716587c715dcSDouglas Gilbert err: 716687c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 716787c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 716887c715dcSDouglas Gilbert return res; 716987c715dcSDouglas Gilbert } 717087c715dcSDouglas Gilbert 717187c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 717287c715dcSDouglas Gilbert { 717387c715dcSDouglas Gilbert int k, devs_per_host, idx; 717487c715dcSDouglas Gilbert int error = -ENOMEM; 71751da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 71768b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 71771da177e4SLinus Torvalds 717824669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 717987c715dcSDouglas Gilbert if (!sdbg_host) 71801da177e4SLinus Torvalds return -ENOMEM; 718187c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 718287c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 718387c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 718487c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 71851da177e4SLinus Torvalds 71861da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 71871da177e4SLinus Torvalds 7188773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 71891da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 71905cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 719187c715dcSDouglas Gilbert if (!sdbg_devinfo) 71921da177e4SLinus Torvalds goto clean; 71931da177e4SLinus Torvalds } 71941da177e4SLinus Torvalds 71951da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 71961da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 71971da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 71981da177e4SLinus Torvalds 71991da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 72009b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 72011da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 72022aad3cd8SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", atomic_read(&sdebug_num_hosts)); 72031da177e4SLinus Torvalds 72041da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 72051da177e4SLinus Torvalds if (error) 72061da177e4SLinus Torvalds goto clean; 72071da177e4SLinus Torvalds 72082aad3cd8SDouglas Gilbert atomic_inc(&sdebug_num_hosts); 720987c715dcSDouglas Gilbert return 0; 72101da177e4SLinus Torvalds 72111da177e4SLinus Torvalds clean: 72128b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 72138b40228fSFUJITA Tomonori dev_list) { 72141da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7215f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 72161da177e4SLinus Torvalds kfree(sdbg_devinfo); 72171da177e4SLinus Torvalds } 72181da177e4SLinus Torvalds kfree(sdbg_host); 721987c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 72201da177e4SLinus Torvalds return error; 72211da177e4SLinus Torvalds } 72221da177e4SLinus Torvalds 722387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 72241da177e4SLinus Torvalds { 722587c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 722687c715dcSDouglas Gilbert 722787c715dcSDouglas Gilbert if (mk_new_store) { 722887c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 722987c715dcSDouglas Gilbert if (ph_idx < 0) 723087c715dcSDouglas Gilbert return ph_idx; 723187c715dcSDouglas Gilbert } 723287c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 723387c715dcSDouglas Gilbert } 723487c715dcSDouglas Gilbert 723587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 723687c715dcSDouglas Gilbert { 723787c715dcSDouglas Gilbert int idx = -1; 72381da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 723987c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 72401da177e4SLinus Torvalds 72411da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 72421da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 72431da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 72441da177e4SLinus Torvalds struct sdebug_host_info, host_list); 724587c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 72461da177e4SLinus Torvalds } 724787c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 724887c715dcSDouglas Gilbert bool unique = true; 724987c715dcSDouglas Gilbert 725087c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 725187c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 725287c715dcSDouglas Gilbert continue; 725387c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 725487c715dcSDouglas Gilbert unique = false; 725587c715dcSDouglas Gilbert break; 725687c715dcSDouglas Gilbert } 725787c715dcSDouglas Gilbert } 725887c715dcSDouglas Gilbert if (unique) { 725987c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 726087c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 726187c715dcSDouglas Gilbert --sdeb_most_recent_idx; 726287c715dcSDouglas Gilbert } 726387c715dcSDouglas Gilbert } 726487c715dcSDouglas Gilbert if (sdbg_host) 726587c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 72661da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 72671da177e4SLinus Torvalds 72681da177e4SLinus Torvalds if (!sdbg_host) 72691da177e4SLinus Torvalds return; 72701da177e4SLinus Torvalds 72711da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 72722aad3cd8SDouglas Gilbert atomic_dec(&sdebug_num_hosts); 72731da177e4SLinus Torvalds } 72741da177e4SLinus Torvalds 7275fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 7276cbf67842SDouglas Gilbert { 7277cbf67842SDouglas Gilbert int num_in_q = 0; 7278cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 7279cbf67842SDouglas Gilbert 72802aad3cd8SDouglas Gilbert sdeb_block_all_queues(); 7281cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 7282cbf67842SDouglas Gilbert if (NULL == devip) { 72832aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 7284cbf67842SDouglas Gilbert return -ENODEV; 7285cbf67842SDouglas Gilbert } 7286cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 7287c40ecc12SChristoph Hellwig 7288fc09acb7SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE) { 7289fc09acb7SDouglas Gilbert qdepth = SDEBUG_CANQUEUE; 7290fc09acb7SDouglas Gilbert pr_warn("%s: requested qdepth [%d] exceeds canqueue [%d], trim\n", __func__, 7291fc09acb7SDouglas Gilbert qdepth, SDEBUG_CANQUEUE); 7292fc09acb7SDouglas Gilbert } 7293cbf67842SDouglas Gilbert if (qdepth < 1) 7294cbf67842SDouglas Gilbert qdepth = 1; 7295fc09acb7SDouglas Gilbert if (qdepth != sdev->queue_depth) 7296db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 7297cbf67842SDouglas Gilbert 7298773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 7299c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 7300c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 7301cbf67842SDouglas Gilbert } 73022aad3cd8SDouglas Gilbert sdeb_unblock_all_queues(); 7303cbf67842SDouglas Gilbert return sdev->queue_depth; 7304cbf67842SDouglas Gilbert } 7305cbf67842SDouglas Gilbert 7306c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 7307817fd66bSDouglas Gilbert { 7308c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 7309773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 7310773642d9SDouglas Gilbert sdebug_every_nth = -1; 7311773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 7312c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 7313773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 7314817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 7315c4837394SDouglas Gilbert return true; /* time out reads and writes */ 7316817fd66bSDouglas Gilbert } 7317c4837394SDouglas Gilbert return false; 7318817fd66bSDouglas Gilbert } 7319817fd66bSDouglas Gilbert 7320fc13638aSDouglas Gilbert /* Response to TUR or media access command when device stopped */ 7321fc13638aSDouglas Gilbert static int resp_not_ready(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7322fc13638aSDouglas Gilbert { 7323fc13638aSDouglas Gilbert int stopped_state; 7324fc13638aSDouglas Gilbert u64 diff_ns = 0; 7325fc13638aSDouglas Gilbert ktime_t now_ts = ktime_get_boottime(); 7326fc13638aSDouglas Gilbert struct scsi_device *sdp = scp->device; 7327fc13638aSDouglas Gilbert 7328fc13638aSDouglas Gilbert stopped_state = atomic_read(&devip->stopped); 7329fc13638aSDouglas Gilbert if (stopped_state == 2) { 7330fc13638aSDouglas Gilbert if (ktime_to_ns(now_ts) > ktime_to_ns(devip->create_ts)) { 7331fc13638aSDouglas Gilbert diff_ns = ktime_to_ns(ktime_sub(now_ts, devip->create_ts)); 7332fc13638aSDouglas Gilbert if (diff_ns >= ((u64)sdeb_tur_ms_to_ready * 1000000)) { 7333fc13638aSDouglas Gilbert /* tur_ms_to_ready timer extinguished */ 7334fc13638aSDouglas Gilbert atomic_set(&devip->stopped, 0); 7335fc13638aSDouglas Gilbert return 0; 7336fc13638aSDouglas Gilbert } 7337fc13638aSDouglas Gilbert } 7338fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x1); 7339fc13638aSDouglas Gilbert if (sdebug_verbose) 7340fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, 7341fc13638aSDouglas Gilbert "%s: Not ready: in process of becoming ready\n", my_name); 7342fc13638aSDouglas Gilbert if (scp->cmnd[0] == TEST_UNIT_READY) { 7343fc13638aSDouglas Gilbert u64 tur_nanosecs_to_ready = (u64)sdeb_tur_ms_to_ready * 1000000; 7344fc13638aSDouglas Gilbert 7345fc13638aSDouglas Gilbert if (diff_ns <= tur_nanosecs_to_ready) 7346fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready - diff_ns; 7347fc13638aSDouglas Gilbert else 7348fc13638aSDouglas Gilbert diff_ns = tur_nanosecs_to_ready; 7349fc13638aSDouglas Gilbert /* As per 20-061r2 approved for spc6 by T10 on 20200716 */ 7350fc13638aSDouglas Gilbert do_div(diff_ns, 1000000); /* diff_ns becomes milliseconds */ 7351fc13638aSDouglas Gilbert scsi_set_sense_information(scp->sense_buffer, SCSI_SENSE_BUFFERSIZE, 7352fc13638aSDouglas Gilbert diff_ns); 7353fc13638aSDouglas Gilbert return check_condition_result; 7354fc13638aSDouglas Gilbert } 7355fc13638aSDouglas Gilbert } 7356fc13638aSDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 7357fc13638aSDouglas Gilbert if (sdebug_verbose) 7358fc13638aSDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Not ready: initializing command required\n", 7359fc13638aSDouglas Gilbert my_name); 7360fc13638aSDouglas Gilbert return check_condition_result; 7361fc13638aSDouglas Gilbert } 7362fc13638aSDouglas Gilbert 7363c4b57d89SKashyap Desai static int sdebug_map_queues(struct Scsi_Host *shost) 7364c4b57d89SKashyap Desai { 7365c4b57d89SKashyap Desai int i, qoff; 7366c4b57d89SKashyap Desai 7367c4b57d89SKashyap Desai if (shost->nr_hw_queues == 1) 7368c4b57d89SKashyap Desai return 0; 7369c4b57d89SKashyap Desai 7370c4b57d89SKashyap Desai for (i = 0, qoff = 0; i < HCTX_MAX_TYPES; i++) { 7371c4b57d89SKashyap Desai struct blk_mq_queue_map *map = &shost->tag_set.map[i]; 7372c4b57d89SKashyap Desai 7373c4b57d89SKashyap Desai map->nr_queues = 0; 7374c4b57d89SKashyap Desai 7375c4b57d89SKashyap Desai if (i == HCTX_TYPE_DEFAULT) 7376c4b57d89SKashyap Desai map->nr_queues = submit_queues - poll_queues; 7377c4b57d89SKashyap Desai else if (i == HCTX_TYPE_POLL) 7378c4b57d89SKashyap Desai map->nr_queues = poll_queues; 7379c4b57d89SKashyap Desai 7380c4b57d89SKashyap Desai if (!map->nr_queues) { 7381c4b57d89SKashyap Desai BUG_ON(i == HCTX_TYPE_DEFAULT); 7382c4b57d89SKashyap Desai continue; 7383c4b57d89SKashyap Desai } 7384c4b57d89SKashyap Desai 7385c4b57d89SKashyap Desai map->queue_offset = qoff; 7386c4b57d89SKashyap Desai blk_mq_map_queues(map); 7387c4b57d89SKashyap Desai 7388c4b57d89SKashyap Desai qoff += map->nr_queues; 7389c4b57d89SKashyap Desai } 7390c4b57d89SKashyap Desai 7391c4b57d89SKashyap Desai return 0; 7392c4b57d89SKashyap Desai 7393c4b57d89SKashyap Desai } 7394c4b57d89SKashyap Desai 7395c4b57d89SKashyap Desai static int sdebug_blk_mq_poll(struct Scsi_Host *shost, unsigned int queue_num) 7396c4b57d89SKashyap Desai { 73974a0c6f43SDouglas Gilbert bool first; 73984a0c6f43SDouglas Gilbert bool retiring = false; 73994a0c6f43SDouglas Gilbert int num_entries = 0; 74004a0c6f43SDouglas Gilbert unsigned int qc_idx = 0; 7401c4b57d89SKashyap Desai unsigned long iflags; 74024a0c6f43SDouglas Gilbert ktime_t kt_from_boot = ktime_get_boottime(); 7403c4b57d89SKashyap Desai struct sdebug_queue *sqp; 7404c4b57d89SKashyap Desai struct sdebug_queued_cmd *sqcp; 7405c4b57d89SKashyap Desai struct scsi_cmnd *scp; 7406c4b57d89SKashyap Desai struct sdebug_dev_info *devip; 74074a0c6f43SDouglas Gilbert struct sdebug_defer *sd_dp; 7408c4b57d89SKashyap Desai 7409c4b57d89SKashyap Desai sqp = sdebug_q_arr + queue_num; 7410c4b57d89SKashyap Desai spin_lock_irqsave(&sqp->qc_lock, iflags); 74114a0c6f43SDouglas Gilbert 74124a0c6f43SDouglas Gilbert for (first = true; first || qc_idx + 1 < sdebug_max_queue; ) { 74134a0c6f43SDouglas Gilbert if (first) { 7414c4b57d89SKashyap Desai qc_idx = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 74154a0c6f43SDouglas Gilbert first = false; 74164a0c6f43SDouglas Gilbert } else { 74174a0c6f43SDouglas Gilbert qc_idx = find_next_bit(sqp->in_use_bm, sdebug_max_queue, qc_idx + 1); 74184a0c6f43SDouglas Gilbert } 74194a0c6f43SDouglas Gilbert if (unlikely(qc_idx >= sdebug_max_queue)) 74204a0c6f43SDouglas Gilbert break; 7421c4b57d89SKashyap Desai 7422c4b57d89SKashyap Desai sqcp = &sqp->qc_arr[qc_idx]; 74234a0c6f43SDouglas Gilbert sd_dp = sqcp->sd_dp; 74244a0c6f43SDouglas Gilbert if (unlikely(!sd_dp)) 74254a0c6f43SDouglas Gilbert continue; 7426c4b57d89SKashyap Desai scp = sqcp->a_cmnd; 7427c4b57d89SKashyap Desai if (unlikely(scp == NULL)) { 74284a0c6f43SDouglas Gilbert pr_err("scp is NULL, queue_num=%d, qc_idx=%u from %s\n", 7429c4b57d89SKashyap Desai queue_num, qc_idx, __func__); 74304a0c6f43SDouglas Gilbert break; 7431c4b57d89SKashyap Desai } 7432d9d23a5aSDouglas Gilbert if (READ_ONCE(sd_dp->defer_t) == SDEB_DEFER_POLL) { 74334a0c6f43SDouglas Gilbert if (kt_from_boot < sd_dp->cmpl_ts) 74344a0c6f43SDouglas Gilbert continue; 74354a0c6f43SDouglas Gilbert 74366ce913feSChristoph Hellwig } else /* ignoring non REQ_POLLED requests */ 74374a0c6f43SDouglas Gilbert continue; 7438c4b57d89SKashyap Desai devip = (struct sdebug_dev_info *)scp->device->hostdata; 7439c4b57d89SKashyap Desai if (likely(devip)) 7440c4b57d89SKashyap Desai atomic_dec(&devip->num_in_q); 7441c4b57d89SKashyap Desai else 7442c4b57d89SKashyap Desai pr_err("devip=NULL from %s\n", __func__); 7443c4b57d89SKashyap Desai if (unlikely(atomic_read(&retired_max_queue) > 0)) 74444a0c6f43SDouglas Gilbert retiring = true; 7445c4b57d89SKashyap Desai 7446c4b57d89SKashyap Desai sqcp->a_cmnd = NULL; 7447c4b57d89SKashyap Desai if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 74484a0c6f43SDouglas Gilbert pr_err("Unexpected completion sqp %p queue_num=%d qc_idx=%u from %s\n", 7449c4b57d89SKashyap Desai sqp, queue_num, qc_idx, __func__); 74504a0c6f43SDouglas Gilbert break; 7451c4b57d89SKashyap Desai } 7452c4b57d89SKashyap Desai if (unlikely(retiring)) { /* user has reduced max_queue */ 7453c4b57d89SKashyap Desai int k, retval; 7454c4b57d89SKashyap Desai 7455c4b57d89SKashyap Desai retval = atomic_read(&retired_max_queue); 7456c4b57d89SKashyap Desai if (qc_idx >= retval) { 7457c4b57d89SKashyap Desai pr_err("index %d too large\n", retval); 74584a0c6f43SDouglas Gilbert break; 7459c4b57d89SKashyap Desai } 7460c4b57d89SKashyap Desai k = find_last_bit(sqp->in_use_bm, retval); 7461c4b57d89SKashyap Desai if ((k < sdebug_max_queue) || (k == retval)) 7462c4b57d89SKashyap Desai atomic_set(&retired_max_queue, 0); 7463c4b57d89SKashyap Desai else 7464c4b57d89SKashyap Desai atomic_set(&retired_max_queue, k + 1); 7465c4b57d89SKashyap Desai } 7466d9d23a5aSDouglas Gilbert WRITE_ONCE(sd_dp->defer_t, SDEB_DEFER_NONE); 7467c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 74686c2c7d6aSBart Van Assche scsi_done(scp); /* callback to mid level */ 74694a0c6f43SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 7470c4b57d89SKashyap Desai num_entries++; 74714a0c6f43SDouglas Gilbert } 7472c4b57d89SKashyap Desai spin_unlock_irqrestore(&sqp->qc_lock, iflags); 74734a0c6f43SDouglas Gilbert if (num_entries > 0) 74744a0c6f43SDouglas Gilbert atomic_add(num_entries, &sdeb_mq_poll_count); 7475c4b57d89SKashyap Desai return num_entries; 7476c4b57d89SKashyap Desai } 7477c4b57d89SKashyap Desai 7478fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 7479fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 7480c2248fc9SDouglas Gilbert { 7481c2248fc9SDouglas Gilbert u8 sdeb_i; 7482c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 7483c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 7484c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 7485c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 7486c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 7487c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 7488f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 7489c2248fc9SDouglas Gilbert int k, na; 7490c2248fc9SDouglas Gilbert int errsts = 0; 7491ad0c7775SDouglas Gilbert u64 lun_index = sdp->lun & 0x3FFF; 7492c2248fc9SDouglas Gilbert u32 flags; 7493c2248fc9SDouglas Gilbert u16 sa; 7494c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 7495c2248fc9SDouglas Gilbert bool has_wlun_rl; 74963a90a63dSDouglas Gilbert bool inject_now; 7497c2248fc9SDouglas Gilbert 7498c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 74993a90a63dSDouglas Gilbert if (sdebug_statistics) { 7500c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 75013a90a63dSDouglas Gilbert inject_now = inject_on_this_cmd(); 75023a90a63dSDouglas Gilbert } else { 75033a90a63dSDouglas Gilbert inject_now = false; 75043a90a63dSDouglas Gilbert } 7505f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 7506f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 7507c2248fc9SDouglas Gilbert char b[120]; 7508c2248fc9SDouglas Gilbert int n, len, sb; 7509c2248fc9SDouglas Gilbert 7510c2248fc9SDouglas Gilbert len = scp->cmd_len; 7511c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 7512c2248fc9SDouglas Gilbert if (len > 32) 7513c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 7514c2248fc9SDouglas Gilbert else { 7515c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 7516c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 7517c2248fc9SDouglas Gilbert (u32)cmd[k]); 7518c2248fc9SDouglas Gilbert } 7519458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 7520a6e76e6fSBart Van Assche blk_mq_unique_tag(scsi_cmd_to_rq(scp)), b); 7521c2248fc9SDouglas Gilbert } 75223a90a63dSDouglas Gilbert if (unlikely(inject_now && (sdebug_opts & SDEBUG_OPT_HOST_BUSY))) 75237ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 752434d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 7525ad0c7775SDouglas Gilbert if (unlikely(lun_index >= sdebug_max_luns && !has_wlun_rl)) 7526f46eb0e9SDouglas Gilbert goto err_out; 7527c2248fc9SDouglas Gilbert 7528c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 7529c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 7530c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 7531f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 7532f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 7533c2248fc9SDouglas Gilbert if (NULL == devip) 7534f46eb0e9SDouglas Gilbert goto err_out; 7535c2248fc9SDouglas Gilbert } 75363a90a63dSDouglas Gilbert if (unlikely(inject_now && !atomic_read(&sdeb_inject_pending))) 75373a90a63dSDouglas Gilbert atomic_set(&sdeb_inject_pending, 1); 75383a90a63dSDouglas Gilbert 7539c2248fc9SDouglas Gilbert na = oip->num_attached; 7540c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 7541c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 7542c2248fc9SDouglas Gilbert r_oip = oip; 7543c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 7544c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 7545c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 7546c2248fc9SDouglas Gilbert else 7547c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 7548c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7549c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 7550c2248fc9SDouglas Gilbert break; 7551c2248fc9SDouglas Gilbert } 7552c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 7553c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 7554c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 7555c2248fc9SDouglas Gilbert break; 7556c2248fc9SDouglas Gilbert } 7557c2248fc9SDouglas Gilbert } 7558c2248fc9SDouglas Gilbert if (k > na) { 7559c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 7560c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 7561c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 7562c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 7563c2248fc9SDouglas Gilbert else 7564c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7565c2248fc9SDouglas Gilbert goto check_cond; 7566c2248fc9SDouglas Gilbert } 7567c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 7568c2248fc9SDouglas Gilbert flags = oip->flags; 7569f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 7570c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7571c2248fc9SDouglas Gilbert goto check_cond; 7572c2248fc9SDouglas Gilbert } 7573f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 7574773642d9SDouglas Gilbert if (sdebug_verbose) 7575773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 7576773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 7577c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 7578c2248fc9SDouglas Gilbert goto check_cond; 7579c2248fc9SDouglas Gilbert } 7580f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 7581c2248fc9SDouglas Gilbert u8 rem; 7582c2248fc9SDouglas Gilbert int j; 7583c2248fc9SDouglas Gilbert 7584c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 7585c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 7586c2248fc9SDouglas Gilbert if (rem) { 7587c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 7588c2248fc9SDouglas Gilbert if (0x80 & rem) 7589c2248fc9SDouglas Gilbert break; 7590c2248fc9SDouglas Gilbert } 7591c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 7592c2248fc9SDouglas Gilbert goto check_cond; 7593c2248fc9SDouglas Gilbert } 7594c2248fc9SDouglas Gilbert } 7595c2248fc9SDouglas Gilbert } 7596f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 7597b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 7598b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 7599f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 7600c2248fc9SDouglas Gilbert if (errsts) 7601c2248fc9SDouglas Gilbert goto check_cond; 7602c2248fc9SDouglas Gilbert } 7603fc13638aSDouglas Gilbert if (unlikely(((F_M_ACCESS & flags) || scp->cmnd[0] == TEST_UNIT_READY) && 7604fc13638aSDouglas Gilbert atomic_read(&devip->stopped))) { 7605fc13638aSDouglas Gilbert errsts = resp_not_ready(scp, devip); 7606fc13638aSDouglas Gilbert if (errsts) 7607c2248fc9SDouglas Gilbert goto fini; 7608c2248fc9SDouglas Gilbert } 7609773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 7610c2248fc9SDouglas Gilbert goto fini; 7611f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 7612c4837394SDouglas Gilbert if (fake_timeout(scp)) 7613c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 7614c2248fc9SDouglas Gilbert } 7615f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 7616f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 7617f66b8517SMartin Wilck else 7618f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 7619c2248fc9SDouglas Gilbert 7620c2248fc9SDouglas Gilbert fini: 762167da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 7622f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 762375aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 762475aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 762580c49563SDouglas Gilbert /* 762675aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 762775aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 762875aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 762975aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 763080c49563SDouglas Gilbert */ 763180c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 76324f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 763380c49563SDouglas Gilbert 76344f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 7635f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 763680c49563SDouglas Gilbert } else 7637f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 763810bde980SDouglas Gilbert sdebug_ndelay); 7639c2248fc9SDouglas Gilbert check_cond: 7640f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 7641f46eb0e9SDouglas Gilbert err_out: 7642f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 7643c2248fc9SDouglas Gilbert } 7644c2248fc9SDouglas Gilbert 76459e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 7646c8ed555aSAl Viro .show_info = scsi_debug_show_info, 7647c8ed555aSAl Viro .write_info = scsi_debug_write_info, 76489e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 76499e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 76509e603ca0SFUJITA Tomonori .info = scsi_debug_info, 76519e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 76529e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 76539e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 76549e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 7655185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 7656cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 7657c4b57d89SKashyap Desai .map_queues = sdebug_map_queues, 7658c4b57d89SKashyap Desai .mq_poll = sdebug_blk_mq_poll, 76599e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 76609e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 7661cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 7662cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 76639e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 7664c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 76659e603ca0SFUJITA Tomonori .this_id = 7, 766665e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 7667cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 76686bb5e6e7SAkinobu Mita .max_sectors = -1U, 766950c2e910SChristoph Hellwig .max_segment_size = -1U, 76709e603ca0SFUJITA Tomonori .module = THIS_MODULE, 7671c40ecc12SChristoph Hellwig .track_queue_depth = 1, 76729e603ca0SFUJITA Tomonori }; 76739e603ca0SFUJITA Tomonori 76741da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 76751da177e4SLinus Torvalds { 76761da177e4SLinus Torvalds int error = 0; 76771da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 76781da177e4SLinus Torvalds struct Scsi_Host *hpnt; 7679f46eb0e9SDouglas Gilbert int hprot; 76801da177e4SLinus Torvalds 76811da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 76821da177e4SLinus Torvalds 7683773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 7684fc09acb7SDouglas Gilbert sdebug_driver_template.cmd_per_lun = sdebug_max_queue; 76852a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 76864af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 76874af14d11SChristoph Hellwig 76881da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 76891da177e4SLinus Torvalds if (NULL == hpnt) { 7690c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 76911da177e4SLinus Torvalds error = -ENODEV; 76921da177e4SLinus Torvalds return error; 76931da177e4SLinus Torvalds } 7694c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 76959b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 7696c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 7697c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 7698c4837394SDouglas Gilbert } 7699c10fa55fSJohn Garry /* 7700c10fa55fSJohn Garry * Decide whether to tell scsi subsystem that we want mq. The 7701f7c4cdc7SJohn Garry * following should give the same answer for each host. 7702c10fa55fSJohn Garry */ 7703c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 7704f7c4cdc7SJohn Garry if (sdebug_host_max_queue) 7705f7c4cdc7SJohn Garry hpnt->host_tagset = 1; 77061da177e4SLinus Torvalds 7707c4b57d89SKashyap Desai /* poll queues are possible for nr_hw_queues > 1 */ 7708c4b57d89SKashyap Desai if (hpnt->nr_hw_queues == 1 || (poll_queues < 1)) { 7709c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 0. poll_q/nr_hw = (%d/%d)\n", 7710c4b57d89SKashyap Desai my_name, poll_queues, hpnt->nr_hw_queues); 7711c4b57d89SKashyap Desai poll_queues = 0; 7712c4b57d89SKashyap Desai } 7713c4b57d89SKashyap Desai 7714c4b57d89SKashyap Desai /* 7715c4b57d89SKashyap Desai * Poll queues don't need interrupts, but we need at least one I/O queue 7716c4b57d89SKashyap Desai * left over for non-polled I/O. 7717c4b57d89SKashyap Desai * If condition not met, trim poll_queues to 1 (just for simplicity). 7718c4b57d89SKashyap Desai */ 7719c4b57d89SKashyap Desai if (poll_queues >= submit_queues) { 7720fc09acb7SDouglas Gilbert if (submit_queues < 3) 7721c4b57d89SKashyap Desai pr_warn("%s: trim poll_queues to 1\n", my_name); 7722fc09acb7SDouglas Gilbert else 7723fc09acb7SDouglas Gilbert pr_warn("%s: trim poll_queues to 1. Perhaps try poll_queues=%d\n", 7724fc09acb7SDouglas Gilbert my_name, submit_queues - 1); 7725c4b57d89SKashyap Desai poll_queues = 1; 7726c4b57d89SKashyap Desai } 7727c4b57d89SKashyap Desai if (poll_queues) 7728c4b57d89SKashyap Desai hpnt->nr_maps = 3; 7729c4b57d89SKashyap Desai 77301da177e4SLinus Torvalds sdbg_host->shost = hpnt; 77311da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 7732773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 7733773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 77341da177e4SLinus Torvalds else 7735773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 7736773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 7737f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 77381da177e4SLinus Torvalds 7739f46eb0e9SDouglas Gilbert hprot = 0; 7740c6a44287SMartin K. Petersen 7741773642d9SDouglas Gilbert switch (sdebug_dif) { 7742c6a44287SMartin K. Petersen 77438475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 7744f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 7745773642d9SDouglas Gilbert if (sdebug_dix) 7746f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 7747c6a44287SMartin K. Petersen break; 7748c6a44287SMartin K. Petersen 77498475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 7750f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 7751773642d9SDouglas Gilbert if (sdebug_dix) 7752f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 7753c6a44287SMartin K. Petersen break; 7754c6a44287SMartin K. Petersen 77558475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 7756f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 7757773642d9SDouglas Gilbert if (sdebug_dix) 7758f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 7759c6a44287SMartin K. Petersen break; 7760c6a44287SMartin K. Petersen 7761c6a44287SMartin K. Petersen default: 7762773642d9SDouglas Gilbert if (sdebug_dix) 7763f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 7764c6a44287SMartin K. Petersen break; 7765c6a44287SMartin K. Petersen } 7766c6a44287SMartin K. Petersen 7767f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 7768c6a44287SMartin K. Petersen 7769f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 7770c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 7771f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 7772f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 7773f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 7774f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 7775f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 7776f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 7777f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 7778c6a44287SMartin K. Petersen 7779773642d9SDouglas Gilbert if (sdebug_guard == 1) 7780c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 7781c6a44287SMartin K. Petersen else 7782c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 7783c6a44287SMartin K. Petersen 7784773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 7785773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 7786c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 7787c4837394SDouglas Gilbert sdebug_statistics = true; 77881da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 77891da177e4SLinus Torvalds if (error) { 7790c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 77911da177e4SLinus Torvalds error = -ENODEV; 77921da177e4SLinus Torvalds scsi_host_put(hpnt); 779387c715dcSDouglas Gilbert } else { 77941da177e4SLinus Torvalds scsi_scan_host(hpnt); 779587c715dcSDouglas Gilbert } 77961da177e4SLinus Torvalds 77971da177e4SLinus Torvalds return error; 77981da177e4SLinus Torvalds } 77991da177e4SLinus Torvalds 7800fc7a6209SUwe Kleine-König static void sdebug_driver_remove(struct device *dev) 78011da177e4SLinus Torvalds { 78021da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 78038b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 78041da177e4SLinus Torvalds 78051da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 78061da177e4SLinus Torvalds 78071da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 78081da177e4SLinus Torvalds 78098b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 78108b40228fSFUJITA Tomonori dev_list) { 78111da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 7812f0d1cf93SDouglas Gilbert kfree(sdbg_devinfo->zstate); 78131da177e4SLinus Torvalds kfree(sdbg_devinfo); 78141da177e4SLinus Torvalds } 78151da177e4SLinus Torvalds 78161da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 78171da177e4SLinus Torvalds } 78181da177e4SLinus Torvalds 78198dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 78208dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 78211da177e4SLinus Torvalds { 78228dea0d02SFUJITA Tomonori return 1; 78238dea0d02SFUJITA Tomonori } 78241da177e4SLinus Torvalds 78258dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 78268dea0d02SFUJITA Tomonori .name = "pseudo", 78278dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 78288dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 78298dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 783082069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 78318dea0d02SFUJITA Tomonori }; 7832