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 * 1080c49563SDouglas Gilbert * Copyright (C) 2001 - 2018 Douglas Gilbert 111da177e4SLinus Torvalds * 1278d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.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> 36cbf67842SDouglas Gilbert #include <linux/interrupt.h> 37cbf67842SDouglas Gilbert #include <linux/atomic.h> 38cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 3909ba24c1SDouglas Gilbert #include <linux/uuid.h> 406ebf105cSChristoph Hellwig #include <linux/t10-pi.h> 411442f76dSChristoph Hellwig #include <linux/msdos_partition.h> 420c4bc91dSDouglas Gilbert #include <linux/random.h> 4387c715dcSDouglas Gilbert #include <linux/xarray.h> 44ed9f3e25SDouglas Gilbert #include <linux/prefetch.h> 45c6a44287SMartin K. Petersen 46c6a44287SMartin K. Petersen #include <net/checksum.h> 479ff26eefSFUJITA Tomonori 4844d92694SMartin K. Petersen #include <asm/unaligned.h> 4944d92694SMartin K. Petersen 509ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 531da177e4SLinus Torvalds #include <scsi/scsi_host.h> 541da177e4SLinus Torvalds #include <scsi/scsicam.h> 55a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 56cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 57395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 581da177e4SLinus Torvalds 59c6a44287SMartin K. Petersen #include "sd.h" 601da177e4SLinus Torvalds #include "scsi_logging.h" 611da177e4SLinus Torvalds 62773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 6380c49563SDouglas Gilbert #define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */ 6440d07b52SDouglas Gilbert static const char *sdebug_version_date = "20190125"; 65cbf67842SDouglas Gilbert 66cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 671da177e4SLinus Torvalds 686f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 69c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 70c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 71c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 721da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 73c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 741da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7522017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 761da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 77c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 789447b6ceSMartin K. Petersen #define WRITE_PROTECTED 0x27 79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 96481b5e5cSDouglas Gilbert #define WRITE_ERROR_ASC 0xc 971da177e4SLinus Torvalds 986f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 996f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 1006f3cbf55SDouglas Gilbert 1011da177e4SLinus Torvalds /* Default values for driver parameters */ 1021da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1031da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1041da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1051da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1061da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1071da177e4SLinus Torvalds */ 1085b94e232SMartin K. Petersen #define DEF_ATO 1 1099b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10 110c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1111da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1125b94e232SMartin K. Petersen #define DEF_DIF 0 1135b94e232SMartin K. Petersen #define DEF_DIX 0 11487c715dcSDouglas Gilbert #define DEF_PER_HOST_STORE false 1155b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1161da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1175b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1185b94e232SMartin K. Petersen #define DEF_GUARD 0 119cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1205b94e232SMartin K. Petersen #define DEF_LBPU 0 1215b94e232SMartin K. Petersen #define DEF_LBPWS 0 1225b94e232SMartin K. Petersen #define DEF_LBPWS10 0 123be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1245b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 125cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1265b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1271da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1281da177e4SLinus Torvalds #define DEF_OPTS 0 12932c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1305b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 13186e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 132b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 1330c4bc91dSDouglas Gilbert #define DEF_RANDOM false 134d986788bSMartin Pitt #define DEF_REMOVABLE false 135760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1365b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1375b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1385b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1396014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1406014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1415b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1425b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1435b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 144c2248fc9SDouglas Gilbert #define DEF_STRICT 0 145c4837394SDouglas Gilbert #define DEF_STATISTICS false 146c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 14709ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 148c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1491da177e4SLinus Torvalds 150b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 151b01f6f83SDouglas Gilbert 152773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 153773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 154773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 155773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 156773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 157773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 158773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 159773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 160773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 161773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 162773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 163773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 164773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 165773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 166773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 167773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1687ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 1697382f9d8SDouglas Gilbert #define SDEBUG_OPT_CMD_ABORT 0x10000 170773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 171773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 172773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 173773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 174773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1757ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1767382f9d8SDouglas Gilbert SDEBUG_OPT_HOST_BUSY | \ 1777382f9d8SDouglas Gilbert SDEBUG_OPT_CMD_ABORT) 1781da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 179fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1801da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 181773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1826f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 183773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1847382f9d8SDouglas Gilbert * - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and 1857382f9d8SDouglas Gilbert * CMD_ABORT 1861da177e4SLinus Torvalds * 1877382f9d8SDouglas Gilbert * When "every_nth" < 0 then after "- every_nth" commands the selected 1887382f9d8SDouglas Gilbert * error will be injected. The error will be injected on every subsequent 1897382f9d8SDouglas Gilbert * command until some other action occurs; for example, the user writing 1907382f9d8SDouglas Gilbert * a new value (other than -1 or 1) to every_nth: 1917382f9d8SDouglas Gilbert * echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth 1921da177e4SLinus Torvalds */ 1931da177e4SLinus Torvalds 194cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 195cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 196cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 197cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 198cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 199cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 200cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 2010d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 20219c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 203acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 204acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 205acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 206cbf67842SDouglas Gilbert 207773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2081da177e4SLinus Torvalds * sector on read commands: */ 2091da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 21032f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2111da177e4SLinus Torvalds 2121da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2131da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2141da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2151da177e4SLinus Torvalds 216c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 217c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 218c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 219c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 220c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 221c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 222c4837394SDouglas Gilbert */ 223c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 224c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 225cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 226cbf67842SDouglas Gilbert 227fd32119bSDouglas Gilbert #define F_D_IN 1 228fd32119bSDouglas Gilbert #define F_D_OUT 2 229fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 230fd32119bSDouglas Gilbert #define F_D_UNKN 8 231fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 232fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 233fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 234fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 235fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 236fd32119bSDouglas Gilbert #define F_INV_OP 0x200 237fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 238fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 2394f2c8bf6SDouglas Gilbert #define F_SSU_DELAY 0x1000 2404f2c8bf6SDouglas Gilbert #define F_SYNC_DELAY 0x2000 241fd32119bSDouglas Gilbert 242fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 24346f64e70SDouglas Gilbert #define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW) 244fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 2454f2c8bf6SDouglas Gilbert #define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY) 246fd32119bSDouglas Gilbert 247fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 248fd32119bSDouglas Gilbert 249b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 250fd32119bSDouglas Gilbert 25187c715dcSDouglas Gilbert #define SDEB_XA_NOT_IN_USE XA_MARK_1 25287c715dcSDouglas Gilbert 253fd32119bSDouglas Gilbert 254fd32119bSDouglas Gilbert struct sdebug_dev_info { 255fd32119bSDouglas Gilbert struct list_head dev_list; 256fd32119bSDouglas Gilbert unsigned int channel; 257fd32119bSDouglas Gilbert unsigned int target; 258fd32119bSDouglas Gilbert u64 lun; 259bf476433SChristoph Hellwig uuid_t lu_name; 260fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 261fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 262fd32119bSDouglas Gilbert atomic_t num_in_q; 263c4837394SDouglas Gilbert atomic_t stopped; 264fd32119bSDouglas Gilbert bool used; 265fd32119bSDouglas Gilbert }; 266fd32119bSDouglas Gilbert 267fd32119bSDouglas Gilbert struct sdebug_host_info { 268fd32119bSDouglas Gilbert struct list_head host_list; 26987c715dcSDouglas Gilbert int si_idx; /* sdeb_store_info (per host) xarray index */ 270fd32119bSDouglas Gilbert struct Scsi_Host *shost; 271fd32119bSDouglas Gilbert struct device dev; 272fd32119bSDouglas Gilbert struct list_head dev_info_list; 273fd32119bSDouglas Gilbert }; 274fd32119bSDouglas Gilbert 27587c715dcSDouglas Gilbert /* There is an xarray of pointers to this struct's objects, one per host */ 27687c715dcSDouglas Gilbert struct sdeb_store_info { 27787c715dcSDouglas Gilbert rwlock_t macc_lck; /* for atomic media access on this store */ 27887c715dcSDouglas Gilbert u8 *storep; /* user data storage (ram) */ 27987c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep; /* protection info */ 28087c715dcSDouglas Gilbert void *map_storep; /* provisioning map */ 28187c715dcSDouglas Gilbert }; 28287c715dcSDouglas Gilbert 283fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 284fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 285fd32119bSDouglas Gilbert 28610bde980SDouglas Gilbert enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1, 28710bde980SDouglas Gilbert SDEB_DEFER_WQ = 2}; 28810bde980SDouglas Gilbert 289fd32119bSDouglas Gilbert struct sdebug_defer { 290fd32119bSDouglas Gilbert struct hrtimer hrt; 291fd32119bSDouglas Gilbert struct execute_work ew; 292c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 293c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 294c4837394SDouglas Gilbert int issuing_cpu; 29510bde980SDouglas Gilbert bool init_hrt; 29610bde980SDouglas Gilbert bool init_wq; 2977382f9d8SDouglas Gilbert bool aborted; /* true when blk_abort_request() already called */ 29810bde980SDouglas Gilbert enum sdeb_defer_type defer_t; 299fd32119bSDouglas Gilbert }; 300fd32119bSDouglas Gilbert 301fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 302c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 303c4837394SDouglas Gilbert * instance indicates this slot is in use. 304c4837394SDouglas Gilbert */ 305fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 306fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 307c4837394SDouglas Gilbert unsigned int inj_recovered:1; 308c4837394SDouglas Gilbert unsigned int inj_transport:1; 309c4837394SDouglas Gilbert unsigned int inj_dif:1; 310c4837394SDouglas Gilbert unsigned int inj_dix:1; 311c4837394SDouglas Gilbert unsigned int inj_short:1; 3127ee6d1b4SBart Van Assche unsigned int inj_host_busy:1; 3137382f9d8SDouglas Gilbert unsigned int inj_cmd_abort:1; 314fd32119bSDouglas Gilbert }; 315fd32119bSDouglas Gilbert 316c4837394SDouglas Gilbert struct sdebug_queue { 317c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 318c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 319c4837394SDouglas Gilbert spinlock_t qc_lock; 320c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 321fd32119bSDouglas Gilbert }; 322fd32119bSDouglas Gilbert 323c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 324c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 325c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 326c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 327c4837394SDouglas Gilbert 328fd32119bSDouglas Gilbert struct opcode_info_t { 329b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 330b01f6f83SDouglas Gilbert /* for terminating element */ 331fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 332fd32119bSDouglas Gilbert u16 sa; /* service action */ 333fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 334fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 335fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 3369a051019SDouglas Gilbert u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */ 3379a051019SDouglas Gilbert /* 1 to min(cdb_len, 15); ignore cdb[15...] */ 338fd32119bSDouglas Gilbert }; 339fd32119bSDouglas Gilbert 340fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 341c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 342c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 343c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 344c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 345c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 346c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 347c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 348c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 349c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 350c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 351c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 352c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 353c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 35446f64e70SDouglas Gilbert SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */ 35546f64e70SDouglas Gilbert SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */ 356c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 357c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 358c3e2fe92SDouglas Gilbert SDEB_I_VERIFY = 16, /* VERIFY(10), VERIFY(16) */ 359481b5e5cSDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */ 360c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 361c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 362c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 363c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 364c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 365c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 366c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 367c208556aSBart Van Assche SDEB_I_WRITE_BUFFER = 25, 368c208556aSBart Van Assche SDEB_I_WRITE_SAME = 26, /* 10, 16 */ 369c208556aSBart Van Assche SDEB_I_SYNC_CACHE = 27, /* 10, 16 */ 370c208556aSBart Van Assche SDEB_I_COMP_WRITE = 28, 371ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH = 29, /* 10, 16 */ 372ed9f3e25SDouglas Gilbert SDEB_I_LAST_ELEM_P1 = 30, /* keep this last (previous + 1) */ 373c2248fc9SDouglas Gilbert }; 374c2248fc9SDouglas Gilbert 375c4837394SDouglas Gilbert 376c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 377c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 378c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 379c2248fc9SDouglas Gilbert 0, 0, 0, 0, 380c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 381c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 382c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 383c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 384c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 385c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 386c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 387c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 388ed9f3e25SDouglas Gilbert 0, 0, 0, 0, SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, 0, 389c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 390c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 391c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 392c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 393c208556aSBart Van Assche 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 394c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 395c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 396fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 397c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 398c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 399c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 400c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 401c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 402c3e2fe92SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 403c3e2fe92SDouglas Gilbert 0, 0, 0, SDEB_I_VERIFY, 404ed9f3e25SDouglas Gilbert SDEB_I_PRE_FETCH, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 40546f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16, 406c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 407c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 408c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 40946f64e70SDouglas Gilbert SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE, 41046f64e70SDouglas Gilbert 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0, 411c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 412c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 413c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 414c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 415c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 416c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 417c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 418c2248fc9SDouglas Gilbert }; 419c2248fc9SDouglas Gilbert 42080c49563SDouglas Gilbert /* 42180c49563SDouglas Gilbert * The following "response" functions return the SCSI mid-level's 4 byte 42280c49563SDouglas Gilbert * tuple-in-an-int. To handle commands with an IMMED bit, for a faster 42380c49563SDouglas Gilbert * command completion, they can mask their return value with 42480c49563SDouglas Gilbert * SDEG_RES_IMMED_MASK . 42580c49563SDouglas Gilbert */ 42680c49563SDouglas Gilbert #define SDEG_RES_IMMED_MASK 0x40000000 42780c49563SDouglas Gilbert 428c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 429c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 430c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 431c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 432c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 433c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 434c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 435c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 436c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 437481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *); 438c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 439c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 440c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 441c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 442c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 44338d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 44438d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 445c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *, struct sdebug_dev_info *); 446c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 447c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 44838d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 449acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 45080c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *); 451ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *, struct sdebug_dev_info *); 452c2248fc9SDouglas Gilbert 45387c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store); 45487c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx); 45587c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end); 45687c715dcSDouglas Gilbert static int sdebug_add_store(void); 45787c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip); 45887c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first); 45987c715dcSDouglas Gilbert 46046f64e70SDouglas Gilbert /* 46146f64e70SDouglas Gilbert * The following are overflow arrays for cdbs that "hit" the same index in 46246f64e70SDouglas Gilbert * the opcode_info_arr array. The most time sensitive (or commonly used) cdb 46346f64e70SDouglas Gilbert * should be placed in opcode_info_arr[], the others should be placed here. 46446f64e70SDouglas Gilbert */ 46546f64e70SDouglas Gilbert static const struct opcode_info_t msense_iarr[] = { 466c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 467c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 468c2248fc9SDouglas Gilbert }; 469c2248fc9SDouglas Gilbert 47046f64e70SDouglas Gilbert static const struct opcode_info_t mselect_iarr[] = { 471c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 472c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 473c2248fc9SDouglas Gilbert }; 474c2248fc9SDouglas Gilbert 47546f64e70SDouglas Gilbert static const struct opcode_info_t read_iarr[] = { 47646f64e70SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */ 477b7e24581SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 478c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 47946f64e70SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */ 480c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 48146f64e70SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */ 482b7e24581SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 483c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 484c2248fc9SDouglas Gilbert }; 485c2248fc9SDouglas Gilbert 48646f64e70SDouglas Gilbert static const struct opcode_info_t write_iarr[] = { 48746f64e70SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */ 48846f64e70SDouglas Gilbert NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 48946f64e70SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 49046f64e70SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */ 49146f64e70SDouglas Gilbert NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 49246f64e70SDouglas Gilbert 0, 0, 0} }, 49346f64e70SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */ 49446f64e70SDouglas Gilbert NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 49546f64e70SDouglas Gilbert 0xbf, 0xc7, 0, 0, 0, 0} }, 496c2248fc9SDouglas Gilbert }; 497c2248fc9SDouglas Gilbert 498c3e2fe92SDouglas Gilbert static const struct opcode_info_t verify_iarr[] = { 499c3e2fe92SDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify,/* VERIFY(10) */ 500c3e2fe92SDouglas Gilbert NULL, {10, 0xf7, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff, 0xc7, 501c3e2fe92SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 502c3e2fe92SDouglas Gilbert }; 503c3e2fe92SDouglas Gilbert 50446f64e70SDouglas Gilbert static const struct opcode_info_t sa_in_16_iarr[] = { 505c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 506c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 50746f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */ 508c2248fc9SDouglas Gilbert }; 509c2248fc9SDouglas Gilbert 51046f64e70SDouglas Gilbert static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */ 51146f64e70SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0, 512b7e24581SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa, 513c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 514481b5e5cSDouglas Gilbert {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 515481b5e5cSDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8, 516481b5e5cSDouglas Gilbert 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */ 517c2248fc9SDouglas Gilbert }; 518c2248fc9SDouglas Gilbert 51946f64e70SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */ 52038d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 521c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 52246f64e70SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */ 52338d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 524c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 52546f64e70SDouglas Gilbert 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */ 526c2248fc9SDouglas Gilbert }; 527c2248fc9SDouglas Gilbert 52846f64e70SDouglas Gilbert static const struct opcode_info_t write_same_iarr[] = { 52946f64e70SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL, 530c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 53146f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */ 532c2248fc9SDouglas Gilbert }; 533c2248fc9SDouglas Gilbert 53446f64e70SDouglas Gilbert static const struct opcode_info_t reserve_iarr[] = { 535c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 536c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 537c2248fc9SDouglas Gilbert }; 538c2248fc9SDouglas Gilbert 53946f64e70SDouglas Gilbert static const struct opcode_info_t release_iarr[] = { 540c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 541c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 542c2248fc9SDouglas Gilbert }; 543c2248fc9SDouglas Gilbert 54480c49563SDouglas Gilbert static const struct opcode_info_t sync_cache_iarr[] = { 5454f2c8bf6SDouglas Gilbert {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL, 54680c49563SDouglas Gilbert {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 54780c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */ 54880c49563SDouglas Gilbert }; 54980c49563SDouglas Gilbert 550ed9f3e25SDouglas Gilbert static const struct opcode_info_t pre_fetch_iarr[] = { 551ed9f3e25SDouglas Gilbert {0, 0x90, 0, F_SYNC_DELAY | F_M_ACCESS, resp_pre_fetch, NULL, 552ed9f3e25SDouglas Gilbert {16, 0x2, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 553ed9f3e25SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* PRE-FETCH (16) */ 554ed9f3e25SDouglas Gilbert }; 555ed9f3e25SDouglas Gilbert 556c2248fc9SDouglas Gilbert 557c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 558c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 559c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 560ed9f3e25SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEM_P1 + 1] = { 561c2248fc9SDouglas Gilbert /* 0 */ 56246f64e70SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */ 563c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 56446f64e70SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */ 565c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 566c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 567c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 56846f64e70SDouglas Gilbert 0, 0} }, /* REPORT LUNS */ 569c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 570c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 571c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 572c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 57346f64e70SDouglas Gilbert /* 5 */ 57446f64e70SDouglas Gilbert {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */ 57546f64e70SDouglas Gilbert resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0, 57646f64e70SDouglas Gilbert 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 57746f64e70SDouglas Gilbert {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */ 57846f64e70SDouglas Gilbert resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 57946f64e70SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 58046f64e70SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */ 581c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 582c2248fc9SDouglas Gilbert 0, 0, 0} }, 58346f64e70SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */ 584c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 585c2248fc9SDouglas Gilbert 0, 0} }, 58646f64e70SDouglas Gilbert {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */ 58746f64e70SDouglas Gilbert resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 58846f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 589c2248fc9SDouglas Gilbert /* 10 */ 59046f64e70SDouglas Gilbert {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO, 59146f64e70SDouglas Gilbert resp_write_dt0, write_iarr, /* WRITE(16) */ 59246f64e70SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59380c49563SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} }, 5944f2c8bf6SDouglas Gilbert {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */ 595c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 59646f64e70SDouglas Gilbert {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN, 59746f64e70SDouglas Gilbert resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */ 59846f64e70SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 59946f64e70SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} }, 600481b5e5cSDouglas Gilbert {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat, 601481b5e5cSDouglas Gilbert NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 602481b5e5cSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */ 60346f64e70SDouglas Gilbert {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN, 60446f64e70SDouglas Gilbert resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */ 60546f64e70SDouglas Gilbert maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 60646f64e70SDouglas Gilbert 0xff, 0, 0xc7, 0, 0, 0, 0} }, 60746f64e70SDouglas Gilbert /* 15 */ 608c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 609c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 610c3e2fe92SDouglas Gilbert {ARRAY_SIZE(verify_iarr), 0x8f, 0, 611c3e2fe92SDouglas Gilbert F_D_OUT_MAYBE | FF_MEDIA_IO, resp_verify, /* VERIFY(16) */ 612c3e2fe92SDouglas Gilbert verify_iarr, {16, 0xf6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 613c3e2fe92SDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, 61446f64e70SDouglas Gilbert {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO, 61546f64e70SDouglas Gilbert resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */ 61646f64e70SDouglas Gilbert {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff, 61746f64e70SDouglas Gilbert 0xff, 0xff} }, 61846f64e70SDouglas Gilbert {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT, 61946f64e70SDouglas Gilbert NULL, reserve_iarr, /* RESERVE(10) <no response function> */ 620c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 621c2248fc9SDouglas Gilbert 0} }, 62246f64e70SDouglas Gilbert {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT, 62346f64e70SDouglas Gilbert NULL, release_iarr, /* RELEASE(10) <no response function> */ 624c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 625c2248fc9SDouglas Gilbert 0} }, 626c2248fc9SDouglas Gilbert /* 20 */ 627f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 628f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 629c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 630c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 631c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 632c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 633c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 634c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 63546f64e70SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */ 636b7e24581SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 63746f64e70SDouglas Gilbert /* 25 */ 638acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 639acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 640acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 64146f64e70SDouglas Gilbert {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, 64246f64e70SDouglas Gilbert resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */ 64346f64e70SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 64446f64e70SDouglas Gilbert 0, 0, 0, 0, 0} }, 6454f2c8bf6SDouglas Gilbert {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS, 64680c49563SDouglas Gilbert resp_sync_cache, sync_cache_iarr, 647b7e24581SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 64880c49563SDouglas Gilbert 0, 0, 0, 0} }, /* SYNC_CACHE (10) */ 64946f64e70SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL, 650c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 651b7e24581SDouglas Gilbert 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */ 652ed9f3e25SDouglas Gilbert {ARRAY_SIZE(pre_fetch_iarr), 0x34, 0, F_SYNC_DELAY | F_M_ACCESS, 653ed9f3e25SDouglas Gilbert resp_pre_fetch, pre_fetch_iarr, 654ed9f3e25SDouglas Gilbert {10, 0x2, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 655ed9f3e25SDouglas Gilbert 0, 0, 0, 0} }, /* PRE-FETCH (10) */ 656c2248fc9SDouglas Gilbert 657ed9f3e25SDouglas Gilbert /* 30 */ 658c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 659c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 660c2248fc9SDouglas Gilbert }; 661c2248fc9SDouglas Gilbert 66287c715dcSDouglas Gilbert static int sdebug_num_hosts; 66387c715dcSDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; /* in sysfs this is relative */ 664773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 6659b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 666c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 667773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 668773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 669773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 670773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 671773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 672773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 673773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 674773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 675773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 676c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 677d9da891aSLaurence Oberman static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR; 678d9da891aSLaurence Oberman static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM; 679cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 680c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 681773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 682773642d9SDouglas Gilbert static int sdebug_no_uld; 683773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 684773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 685773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 686773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 687773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 68886e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 689b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 690773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 691773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 692773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 693773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 694773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 695773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 696773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 697773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 698773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 699773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 700773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 701773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 702773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 70309ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 7040c4bc91dSDouglas Gilbert static bool sdebug_random = DEF_RANDOM; 70587c715dcSDouglas Gilbert static bool sdebug_per_host_store = DEF_PER_HOST_STORE; 706773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 707773642d9SDouglas Gilbert static bool sdebug_clustering; 708773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 709773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 710817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 711773642d9SDouglas Gilbert static bool sdebug_verbose; 712f46eb0e9SDouglas Gilbert static bool have_dif_prot; 7134f2c8bf6SDouglas Gilbert static bool write_since_sync; 714c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 7159447b6ceSMartin K. Petersen static bool sdebug_wp; 7161da177e4SLinus Torvalds 717c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 7181da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 7191da177e4SLinus Torvalds 7201da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 7211da177e4SLinus Torvalds may still need them */ 7221da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 7231da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 7241da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 7251da177e4SLinus Torvalds 7261da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 7271da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 7281da177e4SLinus Torvalds 72987c715dcSDouglas Gilbert static struct xarray per_store_arr; 73087c715dcSDouglas Gilbert static struct xarray *per_store_ap = &per_store_arr; 73187c715dcSDouglas Gilbert static int sdeb_first_idx = -1; /* invalid index ==> none created */ 73287c715dcSDouglas Gilbert static int sdeb_most_recent_idx = -1; 73387c715dcSDouglas Gilbert static DEFINE_RWLOCK(sdeb_fake_rw_lck); /* need a RW lock when fake_rw=1 */ 7341da177e4SLinus Torvalds 73544d92694SMartin K. Petersen static unsigned long map_size; 736cbf67842SDouglas Gilbert static int num_aborts; 737cbf67842SDouglas Gilbert static int num_dev_resets; 738cbf67842SDouglas Gilbert static int num_target_resets; 739cbf67842SDouglas Gilbert static int num_bus_resets; 740cbf67842SDouglas Gilbert static int num_host_resets; 741c6a44287SMartin K. Petersen static int dix_writes; 742c6a44287SMartin K. Petersen static int dix_reads; 743c6a44287SMartin K. Petersen static int dif_errors; 7441da177e4SLinus Torvalds 745c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 746c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 747fd32119bSDouglas Gilbert 7481da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 74987c715dcSDouglas Gilbert static DEFINE_RWLOCK(atomic_rw2); 75087c715dcSDouglas Gilbert 75187c715dcSDouglas Gilbert static rwlock_t *ramdisk_lck_a[2]; 7521da177e4SLinus Torvalds 753cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 754cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 7551da177e4SLinus Torvalds 7561da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 7571da177e4SLinus Torvalds 7581da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 7591da177e4SLinus Torvalds .name = sdebug_proc_name, 7601da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 7611da177e4SLinus Torvalds }; 7621da177e4SLinus Torvalds 7631da177e4SLinus Torvalds static const int check_condition_result = 7641da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 7651da177e4SLinus Torvalds 766c6a44287SMartin K. Petersen static const int illegal_condition_result = 767c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 768c6a44287SMartin K. Petersen 769cbf67842SDouglas Gilbert static const int device_qfull_result = 770cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 771cbf67842SDouglas Gilbert 772ed9f3e25SDouglas Gilbert static const int condition_met_result = SAM_STAT_CONDITION_MET; 773ed9f3e25SDouglas Gilbert 774fd32119bSDouglas Gilbert 775760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 776760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 777760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 778760f3b03SDouglas Gilbert */ 779760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 780fd32119bSDouglas Gilbert { 781fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 782fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 783fd32119bSDouglas Gilbert } 784c65b1445SDouglas Gilbert 78587c715dcSDouglas Gilbert static void *lba2fake_store(struct sdeb_store_info *sip, 78687c715dcSDouglas Gilbert unsigned long long lba) 78714faa944SAkinobu Mita { 78887c715dcSDouglas Gilbert struct sdeb_store_info *lsip = sip; 78914faa944SAkinobu Mita 79087c715dcSDouglas Gilbert lba = do_div(lba, sdebug_store_sectors); 79187c715dcSDouglas Gilbert if (!sip || !sip->storep) { 79287c715dcSDouglas Gilbert WARN_ON_ONCE(true); 79387c715dcSDouglas Gilbert lsip = xa_load(per_store_ap, 0); /* should never be NULL */ 79487c715dcSDouglas Gilbert } 79587c715dcSDouglas Gilbert return lsip->storep + lba * sdebug_sector_size; 79614faa944SAkinobu Mita } 79714faa944SAkinobu Mita 79887c715dcSDouglas Gilbert static struct t10_pi_tuple *dif_store(struct sdeb_store_info *sip, 79987c715dcSDouglas Gilbert sector_t sector) 80014faa944SAkinobu Mita { 80149413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 80214faa944SAkinobu Mita 80387c715dcSDouglas Gilbert return sip->dif_storep + sector; 80414faa944SAkinobu Mita } 80514faa944SAkinobu Mita 8068dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 8078dea0d02SFUJITA Tomonori { 8088dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 8098dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 8108dea0d02SFUJITA Tomonori 8118dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 8128dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 8138dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 8148dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 815773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 816773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 8178dea0d02SFUJITA Tomonori else 818773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 819773642d9SDouglas Gilbert /* sdebug_max_luns; */ 820f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 8218dea0d02SFUJITA Tomonori } 8228dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 8238dea0d02SFUJITA Tomonori } 8248dea0d02SFUJITA Tomonori 82522017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 82622017ed2SDouglas Gilbert 82722017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 828fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 829fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 83022017ed2SDouglas Gilbert int in_byte, int in_bit) 83122017ed2SDouglas Gilbert { 83222017ed2SDouglas Gilbert unsigned char *sbuff; 83322017ed2SDouglas Gilbert u8 sks[4]; 83422017ed2SDouglas Gilbert int sl, asc; 83522017ed2SDouglas Gilbert 83622017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 83722017ed2SDouglas Gilbert if (!sbuff) { 83822017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 83922017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 84022017ed2SDouglas Gilbert return; 84122017ed2SDouglas Gilbert } 84222017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 84322017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 844773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 84522017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 84622017ed2SDouglas Gilbert sks[0] = 0x80; 84722017ed2SDouglas Gilbert if (c_d) 84822017ed2SDouglas Gilbert sks[0] |= 0x40; 84922017ed2SDouglas Gilbert if (in_bit >= 0) { 85022017ed2SDouglas Gilbert sks[0] |= 0x8; 85122017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 85222017ed2SDouglas Gilbert } 85322017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 854773642d9SDouglas Gilbert if (sdebug_dsense) { 85522017ed2SDouglas Gilbert sl = sbuff[7] + 8; 85622017ed2SDouglas Gilbert sbuff[7] = sl; 85722017ed2SDouglas Gilbert sbuff[sl] = 0x2; 85822017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 85922017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 86022017ed2SDouglas Gilbert } else 86122017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 862773642d9SDouglas Gilbert if (sdebug_verbose) 86322017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 86422017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 86522017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 86622017ed2SDouglas Gilbert } 86722017ed2SDouglas Gilbert 868cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 8698dea0d02SFUJITA Tomonori { 8708dea0d02SFUJITA Tomonori unsigned char *sbuff; 8718dea0d02SFUJITA Tomonori 872cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 873cbf67842SDouglas Gilbert if (!sbuff) { 874cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 875cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 876cbf67842SDouglas Gilbert return; 877cbf67842SDouglas Gilbert } 878cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 8798dea0d02SFUJITA Tomonori 880773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 8818dea0d02SFUJITA Tomonori 882773642d9SDouglas Gilbert if (sdebug_verbose) 883cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 884cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 885cbf67842SDouglas Gilbert my_name, key, asc, asq); 8868dea0d02SFUJITA Tomonori } 8871da177e4SLinus Torvalds 888fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 88922017ed2SDouglas Gilbert { 89022017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 89122017ed2SDouglas Gilbert } 89222017ed2SDouglas Gilbert 8936f4e626fSNathan Chancellor static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd, 8946f4e626fSNathan Chancellor void __user *arg) 8951da177e4SLinus Torvalds { 896773642d9SDouglas Gilbert if (sdebug_verbose) { 897cbf67842SDouglas Gilbert if (0x1261 == cmd) 898cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 899cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 900cbf67842SDouglas Gilbert else if (0x5331 == cmd) 901cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 902cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 903cbf67842SDouglas Gilbert __func__); 904cbf67842SDouglas Gilbert else 905cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 906cbf67842SDouglas Gilbert __func__, cmd); 9071da177e4SLinus Torvalds } 9081da177e4SLinus Torvalds return -EINVAL; 9091da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 9129b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 9139b760fd8SDouglas Gilbert { 9149b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 9159b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 9169b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 9179b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 9189b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 9199b760fd8SDouglas Gilbert break; 9209b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 9219b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 9229b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 9239b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 9249b760fd8SDouglas Gilbert break; 9259b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 9269b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 9279b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 9289b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 9299b760fd8SDouglas Gilbert break; 9309b760fd8SDouglas Gilbert case 16: 9319b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 9329b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 9339b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 9349b760fd8SDouglas Gilbert break; 9359b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 9369b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 9379b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 9389b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 9399b760fd8SDouglas Gilbert break; 9409b760fd8SDouglas Gilbert default: 9419b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 9429b760fd8SDouglas Gilbert sdebug_cdb_len); 9439b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 9449b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 9459b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 9469b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 9479b760fd8SDouglas Gilbert break; 9489b760fd8SDouglas Gilbert } 9499b760fd8SDouglas Gilbert } 9509b760fd8SDouglas Gilbert 9519b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 9529b760fd8SDouglas Gilbert { 9539b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 9549b760fd8SDouglas Gilbert struct Scsi_Host *shost; 9559b760fd8SDouglas Gilbert struct scsi_device *sdev; 9569b760fd8SDouglas Gilbert 9579b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 9589b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 9599b760fd8SDouglas Gilbert shost = sdbg_host->shost; 9609b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 9619b760fd8SDouglas Gilbert config_cdb_len(sdev); 9629b760fd8SDouglas Gilbert } 9639b760fd8SDouglas Gilbert } 9649b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 9659b760fd8SDouglas Gilbert } 9669b760fd8SDouglas Gilbert 96719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 96819c8ead7SEwan D. Milne { 96919c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 97019c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 97119c8ead7SEwan D. Milne 97219c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 97319c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 97419c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 97519c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 97619c8ead7SEwan D. Milne (devip->target == dp->target)) 97719c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 97819c8ead7SEwan D. Milne } 97919c8ead7SEwan D. Milne } 98019c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 98119c8ead7SEwan D. Milne } 98219c8ead7SEwan D. Milne 983f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 9841da177e4SLinus Torvalds { 985cbf67842SDouglas Gilbert int k; 986cbf67842SDouglas Gilbert 987cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 988cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 989cbf67842SDouglas Gilbert const char *cp = NULL; 990cbf67842SDouglas Gilbert 991cbf67842SDouglas Gilbert switch (k) { 992cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 993f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 994f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 995773642d9SDouglas Gilbert if (sdebug_verbose) 996cbf67842SDouglas Gilbert cp = "power on reset"; 997cbf67842SDouglas Gilbert break; 998cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 999f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 1000f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 1001773642d9SDouglas Gilbert if (sdebug_verbose) 1002cbf67842SDouglas Gilbert cp = "bus reset"; 1003cbf67842SDouglas Gilbert break; 1004cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 1005f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1006f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 1007773642d9SDouglas Gilbert if (sdebug_verbose) 1008cbf67842SDouglas Gilbert cp = "mode parameters changed"; 1009cbf67842SDouglas Gilbert break; 10100d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 1011f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 1012f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 1013773642d9SDouglas Gilbert if (sdebug_verbose) 10140d01c5dfSDouglas Gilbert cp = "capacity data changed"; 1015f49accf1SEwan D. Milne break; 1016acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 1017f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1018b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 1019b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 1020773642d9SDouglas Gilbert if (sdebug_verbose) 1021acafd0b9SEwan D. Milne cp = "microcode has been changed"; 1022acafd0b9SEwan D. Milne break; 1023acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 1024f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 1025acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 1026acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 1027773642d9SDouglas Gilbert if (sdebug_verbose) 1028acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 1029acafd0b9SEwan D. Milne break; 103019c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 103119c8ead7SEwan D. Milne /* 103219c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 103319c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 103419c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 103519c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 1036773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 103719c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 103819c8ead7SEwan D. Milne */ 1039773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 104019c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 1041f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 104219c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 104319c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 1044773642d9SDouglas Gilbert if (sdebug_verbose) 104519c8ead7SEwan D. Milne cp = "reported luns data has changed"; 104619c8ead7SEwan D. Milne break; 1047cbf67842SDouglas Gilbert default: 1048773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 1049773642d9SDouglas Gilbert if (sdebug_verbose) 1050cbf67842SDouglas Gilbert cp = "unknown"; 1051cbf67842SDouglas Gilbert break; 1052cbf67842SDouglas Gilbert } 1053cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 1054773642d9SDouglas Gilbert if (sdebug_verbose) 1055f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 1056cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 1057cbf67842SDouglas Gilbert my_name, cp); 10581da177e4SLinus Torvalds return check_condition_result; 10591da177e4SLinus Torvalds } 10601da177e4SLinus Torvalds return 0; 10611da177e4SLinus Torvalds } 10621da177e4SLinus Torvalds 1063fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 10641da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 10651da177e4SLinus Torvalds int arr_len) 10661da177e4SLinus Torvalds { 106721a61829SFUJITA Tomonori int act_len; 1068ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 10691da177e4SLinus Torvalds 1070072d0bb3SFUJITA Tomonori if (!sdb->length) 10711da177e4SLinus Torvalds return 0; 1072ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1073773642d9SDouglas Gilbert return DID_ERROR << 16; 107421a61829SFUJITA Tomonori 107521a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 107621a61829SFUJITA Tomonori arr, arr_len); 107742d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - act_len); 107821a61829SFUJITA Tomonori 10791da177e4SLinus Torvalds return 0; 10801da177e4SLinus Torvalds } 10811da177e4SLinus Torvalds 1082fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 1083fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 1084fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 1085fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 1086fb0cc8d1SDouglas Gilbert */ 1087fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 1088fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 1089fb0cc8d1SDouglas Gilbert { 10909237f04eSDamien Le Moal unsigned int act_len, n; 1091ae3d56d8SChristoph Hellwig struct scsi_data_buffer *sdb = &scp->sdb; 1092fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 1093fb0cc8d1SDouglas Gilbert 1094fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 1095fb0cc8d1SDouglas Gilbert return 0; 1096ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_FROM_DEVICE) 1097fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 1098fb0cc8d1SDouglas Gilbert 1099fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 1100fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 1101fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 110242d387beSBart Van Assche __func__, off_dst, scsi_bufflen(scp), act_len, 110342d387beSBart Van Assche scsi_get_resid(scp)); 11049237f04eSDamien Le Moal n = scsi_bufflen(scp) - (off_dst + act_len); 110587c715dcSDouglas Gilbert scsi_set_resid(scp, min_t(int, scsi_get_resid(scp), n)); 1106fb0cc8d1SDouglas Gilbert return 0; 1107fb0cc8d1SDouglas Gilbert } 1108fb0cc8d1SDouglas Gilbert 1109fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1110fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1111fb0cc8d1SDouglas Gilbert */ 11121da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 111321a61829SFUJITA Tomonori int arr_len) 11141da177e4SLinus Torvalds { 111521a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 11161da177e4SLinus Torvalds return 0; 1117ae3d56d8SChristoph Hellwig if (scp->sc_data_direction != DMA_TO_DEVICE) 11181da177e4SLinus Torvalds return -1; 111921a61829SFUJITA Tomonori 112021a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 11211da177e4SLinus Torvalds } 11221da177e4SLinus Torvalds 11231da177e4SLinus Torvalds 1124e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1125e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 11269b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 11271b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 11281b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 11291b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 11301b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 11311da177e4SLinus Torvalds 1132cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1133760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 11345a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 113509ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1136bf476433SChristoph Hellwig const uuid_t *lu_name) 11371da177e4SLinus Torvalds { 1138c65b1445SDouglas Gilbert int num, port_a; 1139c65b1445SDouglas Gilbert char b[32]; 11401da177e4SLinus Torvalds 1141c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 11421da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 11431da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 11441da177e4SLinus Torvalds arr[1] = 0x1; 11451da177e4SLinus Torvalds arr[2] = 0x0; 1146e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1147e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 11481da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 11491da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 11501da177e4SLinus Torvalds arr[3] = num; 11511da177e4SLinus Torvalds num += 4; 1152c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 115309ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 115409ba24c1SDouglas Gilbert /* Locally assigned UUID */ 115509ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 115609ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 115709ba24c1SDouglas Gilbert arr[num++] = 0x0; 115809ba24c1SDouglas Gilbert arr[num++] = 0x12; 115909ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 116009ba24c1SDouglas Gilbert arr[num++] = 0x0; 116109ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 116209ba24c1SDouglas Gilbert num += 16; 116309ba24c1SDouglas Gilbert } else { 11641b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1165c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1166c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1167c65b1445SDouglas Gilbert arr[num++] = 0x0; 1168c65b1445SDouglas Gilbert arr[num++] = 0x8; 11691b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1170773642d9SDouglas Gilbert num += 8; 117109ba24c1SDouglas Gilbert } 1172c65b1445SDouglas Gilbert /* Target relative port number */ 1173c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1174c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1175c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1176c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1177c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1178c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1179c65b1445SDouglas Gilbert arr[num++] = 0x0; 1180c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1181c65b1445SDouglas Gilbert } 11821b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1183c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1184c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1185c65b1445SDouglas Gilbert arr[num++] = 0x0; 1186c65b1445SDouglas Gilbert arr[num++] = 0x8; 11871b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1188773642d9SDouglas Gilbert num += 8; 11891b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 11905a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 11915a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 11925a09e398SHannes Reinecke arr[num++] = 0x0; 11935a09e398SHannes Reinecke arr[num++] = 0x4; 11945a09e398SHannes Reinecke arr[num++] = 0; 11955a09e398SHannes Reinecke arr[num++] = 0; 1196773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1197773642d9SDouglas Gilbert num += 2; 11981b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1199c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1200c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1201c65b1445SDouglas Gilbert arr[num++] = 0x0; 1202c65b1445SDouglas Gilbert arr[num++] = 0x8; 12031b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1204773642d9SDouglas Gilbert num += 8; 1205c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1206c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1207c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1208c65b1445SDouglas Gilbert arr[num++] = 0x0; 1209c65b1445SDouglas Gilbert arr[num++] = 24; 12101b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1211c65b1445SDouglas Gilbert num += 12; 1212c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1213c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1214c65b1445SDouglas Gilbert num += 8; 1215c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1216c65b1445SDouglas Gilbert num += 4; 1217c65b1445SDouglas Gilbert return num; 1218c65b1445SDouglas Gilbert } 1219c65b1445SDouglas Gilbert 1220c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1221c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1222c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1223c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1224c65b1445SDouglas Gilbert }; 1225c65b1445SDouglas Gilbert 1226cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1227760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1228c65b1445SDouglas Gilbert { 1229c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1230c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1231c65b1445SDouglas Gilbert } 1232c65b1445SDouglas Gilbert 1233cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1234760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1235c65b1445SDouglas Gilbert { 1236c65b1445SDouglas Gilbert int num = 0; 1237c65b1445SDouglas Gilbert const char *na1 = "https://www.kernel.org/config"; 1238c65b1445SDouglas Gilbert const char *na2 = "http://www.kernel.org/log"; 1239c65b1445SDouglas Gilbert int plen, olen; 1240c65b1445SDouglas Gilbert 1241c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1242c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1243c65b1445SDouglas Gilbert arr[num++] = 0x0; 1244c65b1445SDouglas Gilbert olen = strlen(na1); 1245c65b1445SDouglas Gilbert plen = olen + 1; 1246c65b1445SDouglas Gilbert if (plen % 4) 1247c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1248c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1249c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1250c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1251c65b1445SDouglas Gilbert num += plen; 1252c65b1445SDouglas Gilbert 1253c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1254c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1255c65b1445SDouglas Gilbert arr[num++] = 0x0; 1256c65b1445SDouglas Gilbert olen = strlen(na2); 1257c65b1445SDouglas Gilbert plen = olen + 1; 1258c65b1445SDouglas Gilbert if (plen % 4) 1259c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1260c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1261c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1262c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1263c65b1445SDouglas Gilbert num += plen; 1264c65b1445SDouglas Gilbert 1265c65b1445SDouglas Gilbert return num; 1266c65b1445SDouglas Gilbert } 1267c65b1445SDouglas Gilbert 1268c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1269760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1270c65b1445SDouglas Gilbert { 1271c65b1445SDouglas Gilbert int num = 0; 1272c65b1445SDouglas Gilbert int port_a, port_b; 1273c65b1445SDouglas Gilbert 1274c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1275c65b1445SDouglas Gilbert port_b = port_a + 1; 1276c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1277c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1278c65b1445SDouglas Gilbert arr[num++] = 0x0; 1279c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1280c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1281c65b1445SDouglas Gilbert num += 6; 1282c65b1445SDouglas Gilbert arr[num++] = 0x0; 1283c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1284c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1285c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1286c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1287c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1288c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 12891b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1290773642d9SDouglas Gilbert num += 8; 1291c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1292c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1293c65b1445SDouglas Gilbert arr[num++] = 0x0; 1294c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1295c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1296c65b1445SDouglas Gilbert num += 6; 1297c65b1445SDouglas Gilbert arr[num++] = 0x0; 1298c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1299c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1300c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1301c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1302c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1303c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 13041b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1305773642d9SDouglas Gilbert num += 8; 1306c65b1445SDouglas Gilbert 1307c65b1445SDouglas Gilbert return num; 1308c65b1445SDouglas Gilbert } 1309c65b1445SDouglas Gilbert 1310c65b1445SDouglas Gilbert 1311c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1312c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1313c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1314c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1315c65b1445SDouglas Gilbert '1','2','3','4', 1316c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1317c65b1445SDouglas Gilbert 0xec,0,0,0, 1318c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1319c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1320c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1321c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1322c65b1445SDouglas Gilbert 0x53,0x41, 1323c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1324c65b1445SDouglas Gilbert 0x20,0x20, 1325c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1326c65b1445SDouglas Gilbert 0x10,0x80, 1327c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1328c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1329c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1330c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1331c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1332c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1333c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1334c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1335c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1336c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1337c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1338c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1339c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1340c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1341c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1342c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1343c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1344c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1345c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1346c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1347c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1348c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1349c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1350c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1351c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1352c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1353c65b1445SDouglas Gilbert }; 1354c65b1445SDouglas Gilbert 1355cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1356760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1357c65b1445SDouglas Gilbert { 1358c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1359c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1360c65b1445SDouglas Gilbert } 1361c65b1445SDouglas Gilbert 1362c65b1445SDouglas Gilbert 1363c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 13641e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 13651e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 13661e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 13671e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1368c65b1445SDouglas Gilbert }; 1369c65b1445SDouglas Gilbert 1370cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1371760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1372c65b1445SDouglas Gilbert { 1373ea61fca5SMartin K. Petersen unsigned int gran; 1374ea61fca5SMartin K. Petersen 1375c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1376e308b3d1SMartin K. Petersen 1377e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 137886e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 137986e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 138086e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 138186e6828aSLukas Herbolt else 1382773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1383773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1384e308b3d1SMartin K. Petersen 1385e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1386773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1387773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 138844d92694SMartin K. Petersen 1389e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1390773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1391e308b3d1SMartin K. Petersen 1392773642d9SDouglas Gilbert if (sdebug_lbpu) { 1393e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1394773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1395e308b3d1SMartin K. Petersen 1396e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1397773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 139844d92694SMartin K. Petersen } 139944d92694SMartin K. Petersen 1400e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1401773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1402773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 140344d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 140444d92694SMartin K. Petersen } 140544d92694SMartin K. Petersen 1406e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1407773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 14086014759cSMartin K. Petersen 14095b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1410773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 14115b94e232SMartin K. Petersen 14125b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 141344d92694SMartin K. Petersen 1414c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 14151da177e4SLinus Torvalds } 14161da177e4SLinus Torvalds 14171e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1418760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1419eac6e8e4SMatthew Wilcox { 1420eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1421eac6e8e4SMatthew Wilcox arr[0] = 0; 14221e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 14231e49f785SDouglas Gilbert arr[2] = 0; 14241e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1425eac6e8e4SMatthew Wilcox 1426eac6e8e4SMatthew Wilcox return 0x3c; 1427eac6e8e4SMatthew Wilcox } 14281da177e4SLinus Torvalds 1429760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1430760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 14316014759cSMartin K. Petersen { 14323f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 14336014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1434773642d9SDouglas Gilbert if (sdebug_lbpu) 14356014759cSMartin K. Petersen arr[1] = 1 << 7; 1436773642d9SDouglas Gilbert if (sdebug_lbpws) 14376014759cSMartin K. Petersen arr[1] |= 1 << 6; 1438773642d9SDouglas Gilbert if (sdebug_lbpws10) 14395b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1440760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1441760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1442760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1443760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1444760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 14453f0bc3b3SMartin K. Petersen return 0x4; 14466014759cSMartin K. Petersen } 14476014759cSMartin K. Petersen 14481da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1449c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 14501da177e4SLinus Torvalds 1451c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 14521da177e4SLinus Torvalds { 14531da177e4SLinus Torvalds unsigned char pq_pdt; 14545a09e398SHannes Reinecke unsigned char *arr; 145501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 14565a09e398SHannes Reinecke int alloc_len, n, ret; 1457760f3b03SDouglas Gilbert bool have_wlun, is_disk; 14581da177e4SLinus Torvalds 1459773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 14606f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 14616f3cbf55SDouglas Gilbert if (! arr) 14626f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1463760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1464b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1465c2248fc9SDouglas Gilbert if (have_wlun) 1466b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1467b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1468b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1469c65b1445SDouglas Gilbert else 1470773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 14711da177e4SLinus Torvalds arr[0] = pq_pdt; 14721da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 147322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 14745a09e398SHannes Reinecke kfree(arr); 14751da177e4SLinus Torvalds return check_condition_result; 14761da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 14775a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1478c65b1445SDouglas Gilbert char lu_id_str[6]; 1479c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 14801da177e4SLinus Torvalds 14815a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 14825a09e398SHannes Reinecke (devip->channel & 0x7f); 1483b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 148423183910SDouglas Gilbert host_no = 0; 1485c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1486c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1487c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1488c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1489c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 14901da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1491c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1492c65b1445SDouglas Gilbert n = 4; 1493c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1494c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1495c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1496c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1497c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1498c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1499c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1500c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1501760f3b03SDouglas Gilbert if (is_disk) { /* SBC only */ 1502c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1503760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1504760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1505760f3b03SDouglas Gilbert arr[n++] = 0xb2; /* Logical Block Prov */ 1506760f3b03SDouglas Gilbert } 1507c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 15081da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1509c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 15101da177e4SLinus Torvalds arr[3] = len; 1511c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 15121da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1513c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1514760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 15155a09e398SHannes Reinecke target_dev_id, lu_id_num, 151609ba24c1SDouglas Gilbert lu_id_str, len, 151709ba24c1SDouglas Gilbert &devip->lu_name); 1518c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1519c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1520760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1521c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1522c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1523760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1524c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1525c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1526c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 15278475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1528c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1529760f3b03SDouglas Gilbert else if (have_dif_prot) 1530c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1531c6a44287SMartin K. Petersen else 1532c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1533c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1534c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1535c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1536c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1537c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1538c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1539c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1540c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1541c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1542c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1543760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1544760f3b03SDouglas Gilbert } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ 1545c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1546760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1547773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1548760f3b03SDouglas Gilbert } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ 1549c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1550760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1551760f3b03SDouglas Gilbert } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ 1552eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1553760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1554760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 15556014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1556760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 15571da177e4SLinus Torvalds } else { 155822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 15595a09e398SHannes Reinecke kfree(arr); 15601da177e4SLinus Torvalds return check_condition_result; 15611da177e4SLinus Torvalds } 1562773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 15635a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1564c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 15655a09e398SHannes Reinecke kfree(arr); 15665a09e398SHannes Reinecke return ret; 15671da177e4SLinus Torvalds } 15681da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1569773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1570773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 15711da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 15721da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1573f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1574b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 157570bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1576c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 15771da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1578c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1579e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1580e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1581e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 15829b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 15839b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 15841da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1585760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1586760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1587c65b1445SDouglas Gilbert n = 62; 1588760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1589760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1590760f3b03SDouglas Gilbert n += 2; 1591760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1592760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1593760f3b03SDouglas Gilbert n += 2; 15941da177e4SLinus Torvalds } 1595760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 15965a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 159787c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_LONG_INQ_SZ)); 15985a09e398SHannes Reinecke kfree(arr); 15995a09e398SHannes Reinecke return ret; 16001da177e4SLinus Torvalds } 16011da177e4SLinus Torvalds 1602fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1603fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1604fd32119bSDouglas Gilbert 16051da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd *scp, 16061da177e4SLinus Torvalds struct sdebug_dev_info *devip) 16071da177e4SLinus Torvalds { 16081da177e4SLinus Torvalds unsigned char *sbuff; 160901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1610cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 16112492fc09STomas Winkler bool dsense; 16121da177e4SLinus Torvalds int len = 18; 16131da177e4SLinus Torvalds 1614c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1615c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1616cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1617c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1618c2248fc9SDouglas Gilbert if (dsense) { 1619c65b1445SDouglas Gilbert arr[0] = 0x72; 1620c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1621c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1622c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1623c2248fc9SDouglas Gilbert len = 8; 1624c65b1445SDouglas Gilbert } else { 1625c65b1445SDouglas Gilbert arr[0] = 0x70; 1626c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1627c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1628c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1629c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1630c65b1445SDouglas Gilbert } 1631c65b1445SDouglas Gilbert } else { 1632cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1633773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1634c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1635c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1636c2248fc9SDouglas Gilbert if (dsense) { 1637c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1638c2248fc9SDouglas Gilbert arr[0] = 0x72; 1639c2248fc9SDouglas Gilbert len = 8; 1640c2248fc9SDouglas Gilbert } else { 1641c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1642c2248fc9SDouglas Gilbert arr[0] = 0x70; 1643c2248fc9SDouglas Gilbert arr[7] = 0xa; 1644c2248fc9SDouglas Gilbert } 1645c2248fc9SDouglas Gilbert } else if (dsense) { 1646c2248fc9SDouglas Gilbert memset(arr, 0, 8); 16471da177e4SLinus Torvalds arr[0] = 0x72; 16481da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 16491da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 16501da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 16511da177e4SLinus Torvalds len = 8; 1652c2248fc9SDouglas Gilbert } else { 1653c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1654c2248fc9SDouglas Gilbert arr[0] = 0x70; 1655c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1656c2248fc9SDouglas Gilbert arr[7] = 0xa; 1657c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1658c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1659c65b1445SDouglas Gilbert } 1660c2248fc9SDouglas Gilbert 1661c65b1445SDouglas Gilbert } 1662cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 16631da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 16641da177e4SLinus Torvalds } 16651da177e4SLinus Torvalds 1666c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *scp, 1667c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1668c65b1445SDouglas Gilbert { 166901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1670c4837394SDouglas Gilbert int power_cond, stop; 16714f2c8bf6SDouglas Gilbert bool changing; 1672c65b1445SDouglas Gilbert 1673c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1674c65b1445SDouglas Gilbert if (power_cond) { 167522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1676c65b1445SDouglas Gilbert return check_condition_result; 1677c65b1445SDouglas Gilbert } 1678c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 16794f2c8bf6SDouglas Gilbert changing = atomic_read(&devip->stopped) == !stop; 1680c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 16814f2c8bf6SDouglas Gilbert if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */ 16824f2c8bf6SDouglas Gilbert return SDEG_RES_IMMED_MASK; 16834f2c8bf6SDouglas Gilbert else 16844f2c8bf6SDouglas Gilbert return 0; 1685c65b1445SDouglas Gilbert } 1686c65b1445SDouglas Gilbert 168728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 168828898873SFUJITA Tomonori { 1689773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1690773642d9SDouglas Gilbert 1691773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1692773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1693773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 169428898873SFUJITA Tomonori else 169528898873SFUJITA Tomonori return sdebug_store_sectors; 169628898873SFUJITA Tomonori } 169728898873SFUJITA Tomonori 16981da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 16991da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd *scp, 17001da177e4SLinus Torvalds struct sdebug_dev_info *devip) 17011da177e4SLinus Torvalds { 17021da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1703c65b1445SDouglas Gilbert unsigned int capac; 17041da177e4SLinus Torvalds 1705c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 170628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 17071da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1708c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1709c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1710773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1711773642d9SDouglas Gilbert } else 1712773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1713773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 17141da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 17151da177e4SLinus Torvalds } 17161da177e4SLinus Torvalds 1717c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1718c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *scp, 1719c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 1720c65b1445SDouglas Gilbert { 172101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1722c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1723773642d9SDouglas Gilbert int alloc_len; 1724c65b1445SDouglas Gilbert 1725773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1726c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 172728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1728c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1729773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1730773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1731773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1732773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 173344d92694SMartin K. Petersen 1734be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 17355b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1736760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1737760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1738760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1739760f3b03SDouglas Gilbert */ 1740760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1741760f3b03SDouglas Gilbert arr[14] |= 0x40; 1742be1dd78dSEric Sandeen } 174344d92694SMartin K. Petersen 1744773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1745c6a44287SMartin K. Petersen 1746760f3b03SDouglas Gilbert if (have_dif_prot) { 1747773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1748c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1749c6a44287SMartin K. Petersen } 1750c6a44287SMartin K. Petersen 1751c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 175287c715dcSDouglas Gilbert min_t(int, alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1753c65b1445SDouglas Gilbert } 1754c65b1445SDouglas Gilbert 17555a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 17565a09e398SHannes Reinecke 17575a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd *scp, 17585a09e398SHannes Reinecke struct sdebug_dev_info *devip) 17595a09e398SHannes Reinecke { 176001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 17615a09e398SHannes Reinecke unsigned char *arr; 17625a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 17635a09e398SHannes Reinecke int n, ret, alen, rlen; 17645a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 17655a09e398SHannes Reinecke 1766773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 17676f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 17686f3cbf55SDouglas Gilbert if (! arr) 17696f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 17705a09e398SHannes Reinecke /* 17715a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 17725a09e398SHannes Reinecke * real and a fake port with no device connected. 17735a09e398SHannes Reinecke * So we create two port groups with one port each 17745a09e398SHannes Reinecke * and set the group with port B to unavailable. 17755a09e398SHannes Reinecke */ 17765a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 17775a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 17785a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 17795a09e398SHannes Reinecke (devip->channel & 0x7f); 17805a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 17815a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 17825a09e398SHannes Reinecke 17835a09e398SHannes Reinecke /* 17845a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 17855a09e398SHannes Reinecke */ 17865a09e398SHannes Reinecke n = 4; 1787b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 17885a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 17895a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 17905a09e398SHannes Reinecke } else { 17915a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1792773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 17935a09e398SHannes Reinecke } 1794773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1795773642d9SDouglas Gilbert n += 2; 17965a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 17975a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 17985a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 17995a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 18005a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 18015a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1802773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1803773642d9SDouglas Gilbert n += 2; 18045a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 18055a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1806773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1807773642d9SDouglas Gilbert n += 2; 18085a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 18095a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 18105a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 18115a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 18125a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 18135a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1814773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1815773642d9SDouglas Gilbert n += 2; 18165a09e398SHannes Reinecke 18175a09e398SHannes Reinecke rlen = n - 4; 1818773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 18195a09e398SHannes Reinecke 18205a09e398SHannes Reinecke /* 18215a09e398SHannes Reinecke * Return the smallest value of either 18225a09e398SHannes Reinecke * - The allocated length 18235a09e398SHannes Reinecke * - The constructed command length 18245a09e398SHannes Reinecke * - The maximum array size 18255a09e398SHannes Reinecke */ 182687c715dcSDouglas Gilbert rlen = min_t(int, alen, n); 18275a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 182887c715dcSDouglas Gilbert min_t(int, rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 18295a09e398SHannes Reinecke kfree(arr); 18305a09e398SHannes Reinecke return ret; 18315a09e398SHannes Reinecke } 18325a09e398SHannes Reinecke 1833fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1834fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 183538d5c833SDouglas Gilbert { 183638d5c833SDouglas Gilbert bool rctd; 183738d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 183838d5c833SDouglas Gilbert u16 req_sa, u; 183938d5c833SDouglas Gilbert u32 alloc_len, a_len; 184038d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 184138d5c833SDouglas Gilbert const struct opcode_info_t *oip; 184238d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 184338d5c833SDouglas Gilbert u8 *arr; 184438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 184538d5c833SDouglas Gilbert 184638d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 184738d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 184838d5c833SDouglas Gilbert req_opcode = cmd[3]; 184938d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 185038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 18516d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 185238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 185338d5c833SDouglas Gilbert return check_condition_result; 185438d5c833SDouglas Gilbert } 185538d5c833SDouglas Gilbert if (alloc_len > 8192) 185638d5c833SDouglas Gilbert a_len = 8192; 185738d5c833SDouglas Gilbert else 185838d5c833SDouglas Gilbert a_len = alloc_len; 185999531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 186038d5c833SDouglas Gilbert if (NULL == arr) { 186138d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 186238d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 186338d5c833SDouglas Gilbert return check_condition_result; 186438d5c833SDouglas Gilbert } 186538d5c833SDouglas Gilbert switch (reporting_opts) { 186638d5c833SDouglas Gilbert case 0: /* all commands */ 186738d5c833SDouglas Gilbert /* count number of commands */ 186838d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 186938d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 187038d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 187138d5c833SDouglas Gilbert continue; 187238d5c833SDouglas Gilbert count += (oip->num_attached + 1); 187338d5c833SDouglas Gilbert } 187438d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 187538d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 187638d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 187738d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 187838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 187938d5c833SDouglas Gilbert continue; 188038d5c833SDouglas Gilbert na = oip->num_attached; 188138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 188238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 188338d5c833SDouglas Gilbert if (rctd) 188438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 188538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 188638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 188738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 188838d5c833SDouglas Gilbert if (rctd) 188938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 189038d5c833SDouglas Gilbert r_oip = oip; 189138d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 189238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 189338d5c833SDouglas Gilbert continue; 189438d5c833SDouglas Gilbert offset += bump; 189538d5c833SDouglas Gilbert arr[offset] = oip->opcode; 189638d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 189738d5c833SDouglas Gilbert if (rctd) 189838d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 189938d5c833SDouglas Gilbert if (FF_SA & oip->flags) 190038d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 190138d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 190238d5c833SDouglas Gilbert arr + offset + 6); 190338d5c833SDouglas Gilbert if (rctd) 190438d5c833SDouglas Gilbert put_unaligned_be16(0xa, 190538d5c833SDouglas Gilbert arr + offset + 8); 190638d5c833SDouglas Gilbert } 190738d5c833SDouglas Gilbert oip = r_oip; 190838d5c833SDouglas Gilbert offset += bump; 190938d5c833SDouglas Gilbert } 191038d5c833SDouglas Gilbert break; 191138d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 191238d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 191338d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 191438d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 191538d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 191638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 191738d5c833SDouglas Gilbert supp = 1; 191838d5c833SDouglas Gilbert offset = 4; 191938d5c833SDouglas Gilbert } else { 192038d5c833SDouglas Gilbert if (1 == reporting_opts) { 192138d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 192238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 192338d5c833SDouglas Gilbert 2, 2); 192438d5c833SDouglas Gilbert kfree(arr); 192538d5c833SDouglas Gilbert return check_condition_result; 192638d5c833SDouglas Gilbert } 192738d5c833SDouglas Gilbert req_sa = 0; 192838d5c833SDouglas Gilbert } else if (2 == reporting_opts && 192938d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 193038d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 193138d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 193238d5c833SDouglas Gilbert return check_condition_result; 193338d5c833SDouglas Gilbert } 193438d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 193538d5c833SDouglas Gilbert req_opcode == oip->opcode) 193638d5c833SDouglas Gilbert supp = 3; 193738d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 193838d5c833SDouglas Gilbert na = oip->num_attached; 193938d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 194038d5c833SDouglas Gilbert ++k, ++oip) { 194138d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 194238d5c833SDouglas Gilbert break; 194338d5c833SDouglas Gilbert } 194438d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 194538d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 194638d5c833SDouglas Gilbert na = oip->num_attached; 194738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 194838d5c833SDouglas Gilbert ++k, ++oip) { 194938d5c833SDouglas Gilbert if (req_sa == oip->sa) 195038d5c833SDouglas Gilbert break; 195138d5c833SDouglas Gilbert } 195238d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 195338d5c833SDouglas Gilbert } else 195438d5c833SDouglas Gilbert supp = 3; 195538d5c833SDouglas Gilbert if (3 == supp) { 195638d5c833SDouglas Gilbert u = oip->len_mask[0]; 195738d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 195838d5c833SDouglas Gilbert arr[4] = oip->opcode; 195938d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 196038d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 196138d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 196238d5c833SDouglas Gilbert offset = 4 + u; 196338d5c833SDouglas Gilbert } else 196438d5c833SDouglas Gilbert offset = 4; 196538d5c833SDouglas Gilbert } 196638d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 196738d5c833SDouglas Gilbert if (rctd) { 196838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 196938d5c833SDouglas Gilbert offset += 12; 197038d5c833SDouglas Gilbert } 197138d5c833SDouglas Gilbert break; 197238d5c833SDouglas Gilbert default: 197338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 197438d5c833SDouglas Gilbert kfree(arr); 197538d5c833SDouglas Gilbert return check_condition_result; 197638d5c833SDouglas Gilbert } 197738d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 197838d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 197938d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 198038d5c833SDouglas Gilbert kfree(arr); 198138d5c833SDouglas Gilbert return errsts; 198238d5c833SDouglas Gilbert } 198338d5c833SDouglas Gilbert 1984fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1985fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 198638d5c833SDouglas Gilbert { 198738d5c833SDouglas Gilbert bool repd; 198838d5c833SDouglas Gilbert u32 alloc_len, len; 198938d5c833SDouglas Gilbert u8 arr[16]; 199038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 199138d5c833SDouglas Gilbert 199238d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 199338d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 199438d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 199538d5c833SDouglas Gilbert if (alloc_len < 4) { 199638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 199738d5c833SDouglas Gilbert return check_condition_result; 199838d5c833SDouglas Gilbert } 199938d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 200038d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 200138d5c833SDouglas Gilbert if (repd) { 200238d5c833SDouglas Gilbert arr[3] = 0xc; 200338d5c833SDouglas Gilbert len = 16; 200438d5c833SDouglas Gilbert } else 200538d5c833SDouglas Gilbert len = 4; 200638d5c833SDouglas Gilbert 200738d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 200838d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 200938d5c833SDouglas Gilbert } 201038d5c833SDouglas Gilbert 20111da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 20121da177e4SLinus Torvalds 20131da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target) 20141da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 20151da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 20161da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 20191da177e4SLinus Torvalds if (1 == pcontrol) 20201da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 20211da177e4SLinus Torvalds return sizeof(err_recov_pg); 20221da177e4SLinus Torvalds } 20231da177e4SLinus Torvalds 20241da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target) 20251da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 20261da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 20271da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 20281da177e4SLinus Torvalds 20291da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 20301da177e4SLinus Torvalds if (1 == pcontrol) 20311da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 20321da177e4SLinus Torvalds return sizeof(disconnect_pg); 20331da177e4SLinus Torvalds } 20341da177e4SLinus Torvalds 20351da177e4SLinus Torvalds static int resp_format_pg(unsigned char *p, int pcontrol, int target) 20361da177e4SLinus Torvalds { /* Format device page for mode_sense */ 20371da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 20381da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 20391da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 2042773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 2043773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 2044773642d9SDouglas Gilbert if (sdebug_removable) 20451da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 20461da177e4SLinus Torvalds if (1 == pcontrol) 20471da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 20481da177e4SLinus Torvalds return sizeof(format_pg); 20491da177e4SLinus Torvalds } 20501da177e4SLinus Torvalds 2051fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 2052fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 2053fd32119bSDouglas Gilbert 0, 0, 0, 0}; 2054fd32119bSDouglas Gilbert 20551da177e4SLinus Torvalds static int resp_caching_pg(unsigned char *p, int pcontrol, int target) 20561da177e4SLinus Torvalds { /* Caching page for mode_sense */ 2057cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 2058cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 2059cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 20601da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 20611da177e4SLinus Torvalds 2062773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 2063cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 20641da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 20651da177e4SLinus Torvalds if (1 == pcontrol) 2066cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 2067cbf67842SDouglas Gilbert else if (2 == pcontrol) 2068cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 20691da177e4SLinus Torvalds return sizeof(caching_pg); 20701da177e4SLinus Torvalds } 20711da177e4SLinus Torvalds 2072fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 2073fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 2074fd32119bSDouglas Gilbert 20751da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target) 20761da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 2077c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 2078c65b1445SDouglas Gilbert 0, 0, 0, 0}; 2079c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 20801da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 20811da177e4SLinus Torvalds 2082773642d9SDouglas Gilbert if (sdebug_dsense) 20831da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 2084c65b1445SDouglas Gilbert else 2085c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 2086c6a44287SMartin K. Petersen 2087773642d9SDouglas Gilbert if (sdebug_ato) 2088c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 2089c6a44287SMartin K. Petersen 20901da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 20911da177e4SLinus Torvalds if (1 == pcontrol) 2092c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 2093c65b1445SDouglas Gilbert else if (2 == pcontrol) 2094c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 20951da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 20961da177e4SLinus Torvalds } 20971da177e4SLinus Torvalds 2098c65b1445SDouglas Gilbert 20991da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target) 21001da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 2101c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 21021da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 2103c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 2104c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 2105c65b1445SDouglas Gilbert 21061da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 21071da177e4SLinus Torvalds if (1 == pcontrol) 2108c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 2109c65b1445SDouglas Gilbert else if (2 == pcontrol) 2110c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 21111da177e4SLinus Torvalds return sizeof(iec_m_pg); 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds 2114c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target) 2115c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2116c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2117c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2118c65b1445SDouglas Gilbert 2119c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2120c65b1445SDouglas Gilbert if (1 == pcontrol) 2121c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2122c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2123c65b1445SDouglas Gilbert } 2124c65b1445SDouglas Gilbert 2125c65b1445SDouglas Gilbert 2126c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target, 2127c65b1445SDouglas Gilbert int target_dev_id) 2128c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2129c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2130c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2131773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2132773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2133c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2134c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2135c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2136c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2137773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2138773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2139c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2140c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2141c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2142c65b1445SDouglas Gilbert }; 2143c65b1445SDouglas Gilbert int port_a, port_b; 2144c65b1445SDouglas Gilbert 21451b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 21461b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 21471b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 21481b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2149c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2150c65b1445SDouglas Gilbert port_b = port_a + 1; 2151c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2152773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2153773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2154c65b1445SDouglas Gilbert if (1 == pcontrol) 2155c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2156c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2157c65b1445SDouglas Gilbert } 2158c65b1445SDouglas Gilbert 2159c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol) 2160c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2161c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2162c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2163c65b1445SDouglas Gilbert }; 2164c65b1445SDouglas Gilbert 2165c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2166c65b1445SDouglas Gilbert if (1 == pcontrol) 2167c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2168c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2169c65b1445SDouglas Gilbert } 2170c65b1445SDouglas Gilbert 21711da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 21721da177e4SLinus Torvalds 2173fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2174fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 21751da177e4SLinus Torvalds { 217623183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 21771da177e4SLinus Torvalds unsigned char dev_spec; 2178760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2179c2248fc9SDouglas Gilbert int target = scp->device->id; 21801da177e4SLinus Torvalds unsigned char *ap; 21811da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 218201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2183760f3b03SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, bad_pcode; 21841da177e4SLinus Torvalds 2185760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 21861da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 21871da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 21881da177e4SLinus Torvalds subpcode = cmd[3]; 21891da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2190760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2191760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 2192760f3b03SDouglas Gilbert if (is_disk && !dbd) 219323183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 219423183910SDouglas Gilbert else 219523183910SDouglas Gilbert bd_len = 0; 2196773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 21971da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 21981da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2199cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 22001da177e4SLinus Torvalds return check_condition_result; 22011da177e4SLinus Torvalds } 2202c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2203c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2204b01f6f83SDouglas Gilbert /* for disks set DPOFUA bit and clear write protect (WP) bit */ 22059447b6ceSMartin K. Petersen if (is_disk) { 2206b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 22079447b6ceSMartin K. Petersen if (sdebug_wp) 22089447b6ceSMartin K. Petersen dev_spec |= 0x80; 22099447b6ceSMartin K. Petersen } else 221023183910SDouglas Gilbert dev_spec = 0x0; 22111da177e4SLinus Torvalds if (msense_6) { 22121da177e4SLinus Torvalds arr[2] = dev_spec; 221323183910SDouglas Gilbert arr[3] = bd_len; 22141da177e4SLinus Torvalds offset = 4; 22151da177e4SLinus Torvalds } else { 22161da177e4SLinus Torvalds arr[3] = dev_spec; 221723183910SDouglas Gilbert if (16 == bd_len) 221823183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 221923183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 22201da177e4SLinus Torvalds offset = 8; 22211da177e4SLinus Torvalds } 22221da177e4SLinus Torvalds ap = arr + offset; 222328898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 222428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 222528898873SFUJITA Tomonori 222623183910SDouglas Gilbert if (8 == bd_len) { 2227773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2228773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2229773642d9SDouglas Gilbert else 2230773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2231773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 223223183910SDouglas Gilbert offset += bd_len; 223323183910SDouglas Gilbert ap = arr + offset; 223423183910SDouglas Gilbert } else if (16 == bd_len) { 2235773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2236773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 223723183910SDouglas Gilbert offset += bd_len; 223823183910SDouglas Gilbert ap = arr + offset; 223923183910SDouglas Gilbert } 22401da177e4SLinus Torvalds 2241c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2242c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 224322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 22441da177e4SLinus Torvalds return check_condition_result; 22451da177e4SLinus Torvalds } 2246760f3b03SDouglas Gilbert bad_pcode = false; 2247760f3b03SDouglas Gilbert 22481da177e4SLinus Torvalds switch (pcode) { 22491da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 22501da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 22511da177e4SLinus Torvalds offset += len; 22521da177e4SLinus Torvalds break; 22531da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 22541da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 22551da177e4SLinus Torvalds offset += len; 22561da177e4SLinus Torvalds break; 22571da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2258760f3b03SDouglas Gilbert if (is_disk) { 22591da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 22601da177e4SLinus Torvalds offset += len; 2261760f3b03SDouglas Gilbert } else 2262760f3b03SDouglas Gilbert bad_pcode = true; 22631da177e4SLinus Torvalds break; 22641da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2265760f3b03SDouglas Gilbert if (is_disk) { 22661da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 22671da177e4SLinus Torvalds offset += len; 2268760f3b03SDouglas Gilbert } else 2269760f3b03SDouglas Gilbert bad_pcode = true; 22701da177e4SLinus Torvalds break; 22711da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 22721da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 22731da177e4SLinus Torvalds offset += len; 22741da177e4SLinus Torvalds break; 2275c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2276c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 227722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2278c65b1445SDouglas Gilbert return check_condition_result; 2279c65b1445SDouglas Gilbert } 2280c65b1445SDouglas Gilbert len = 0; 2281c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2282c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2283c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2284c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2285c65b1445SDouglas Gilbert target_dev_id); 2286c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2287c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2288c65b1445SDouglas Gilbert offset += len; 2289c65b1445SDouglas Gilbert break; 22901da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 22911da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 22921da177e4SLinus Torvalds offset += len; 22931da177e4SLinus Torvalds break; 22941da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2295c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 22961da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 22971da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2298760f3b03SDouglas Gilbert if (is_disk) { 2299760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2300760f3b03SDouglas Gilbert target); 2301760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2302760f3b03SDouglas Gilbert target); 2303760f3b03SDouglas Gilbert } 23041da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2305c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2306c65b1445SDouglas Gilbert if (0xff == subpcode) { 2307c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2308c65b1445SDouglas Gilbert target, target_dev_id); 2309c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2310c65b1445SDouglas Gilbert } 23111da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2312760f3b03SDouglas Gilbert offset += len; 2313c65b1445SDouglas Gilbert } else { 231422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2315c65b1445SDouglas Gilbert return check_condition_result; 2316c65b1445SDouglas Gilbert } 23171da177e4SLinus Torvalds break; 23181da177e4SLinus Torvalds default: 2319760f3b03SDouglas Gilbert bad_pcode = true; 2320760f3b03SDouglas Gilbert break; 2321760f3b03SDouglas Gilbert } 2322760f3b03SDouglas Gilbert if (bad_pcode) { 232322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 23241da177e4SLinus Torvalds return check_condition_result; 23251da177e4SLinus Torvalds } 23261da177e4SLinus Torvalds if (msense_6) 23271da177e4SLinus Torvalds arr[0] = offset - 1; 2328773642d9SDouglas Gilbert else 2329773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 233087c715dcSDouglas Gilbert return fill_from_dev_buffer(scp, arr, min_t(int, alloc_len, offset)); 23311da177e4SLinus Torvalds } 23321da177e4SLinus Torvalds 2333c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2334c65b1445SDouglas Gilbert 2335fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2336fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2337c65b1445SDouglas Gilbert { 2338c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2339c2248fc9SDouglas Gilbert int param_len, res, mpage; 2340c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 234101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2342c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2343c65b1445SDouglas Gilbert 2344c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2345c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2346c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2347773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2348c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 234922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2350c65b1445SDouglas Gilbert return check_condition_result; 2351c65b1445SDouglas Gilbert } 2352c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2353c65b1445SDouglas Gilbert if (-1 == res) 2354773642d9SDouglas Gilbert return DID_ERROR << 16; 2355773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2356cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2357cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2358cbf67842SDouglas Gilbert __func__, param_len, res); 2359773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2360773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 236123183910SDouglas Gilbert if (md_len > 2) { 236222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2363c65b1445SDouglas Gilbert return check_condition_result; 2364c65b1445SDouglas Gilbert } 2365c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2366c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2367c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2368c65b1445SDouglas Gilbert if (ps) { 236922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2370c65b1445SDouglas Gilbert return check_condition_result; 2371c65b1445SDouglas Gilbert } 2372c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2373773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2374c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2375c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2376cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2377c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2378c65b1445SDouglas Gilbert return check_condition_result; 2379c65b1445SDouglas Gilbert } 2380c65b1445SDouglas Gilbert switch (mpage) { 2381cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2382cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2383cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2384cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2385cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2386cbf67842SDouglas Gilbert } 2387cbf67842SDouglas Gilbert break; 2388c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2389c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2390c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2391c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 23929447b6ceSMartin K. Petersen if (ctrl_m_pg[4] & 0x8) 23939447b6ceSMartin K. Petersen sdebug_wp = true; 23949447b6ceSMartin K. Petersen else 23959447b6ceSMartin K. Petersen sdebug_wp = false; 2396773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2397cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2398c65b1445SDouglas Gilbert } 2399c65b1445SDouglas Gilbert break; 2400c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2401c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2402c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2403c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2404cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2405c65b1445SDouglas Gilbert } 2406c65b1445SDouglas Gilbert break; 2407c65b1445SDouglas Gilbert default: 2408c65b1445SDouglas Gilbert break; 2409c65b1445SDouglas Gilbert } 241022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2411c65b1445SDouglas Gilbert return check_condition_result; 2412cbf67842SDouglas Gilbert set_mode_changed_ua: 2413cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2414cbf67842SDouglas Gilbert return 0; 2415c65b1445SDouglas Gilbert } 2416c65b1445SDouglas Gilbert 2417c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char *arr) 2418c65b1445SDouglas Gilbert { 2419c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2420c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2421c65b1445SDouglas Gilbert }; 2422c65b1445SDouglas Gilbert 2423c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2424c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2425c65b1445SDouglas Gilbert } 2426c65b1445SDouglas Gilbert 2427c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char *arr) 2428c65b1445SDouglas Gilbert { 2429c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2430c65b1445SDouglas Gilbert }; 2431c65b1445SDouglas Gilbert 2432c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2433c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2434c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2435c65b1445SDouglas Gilbert arr[5] = 0xff; 2436c65b1445SDouglas Gilbert } 2437c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2438c65b1445SDouglas Gilbert } 2439c65b1445SDouglas Gilbert 2440c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2441c65b1445SDouglas Gilbert 2442c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *scp, 2443c65b1445SDouglas Gilbert struct sdebug_dev_info *devip) 2444c65b1445SDouglas Gilbert { 2445ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2446c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 244701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2448c65b1445SDouglas Gilbert 2449c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2450c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2451c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2452c65b1445SDouglas Gilbert if (ppc || sp) { 245322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2454c65b1445SDouglas Gilbert return check_condition_result; 2455c65b1445SDouglas Gilbert } 2456c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 245723183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2458773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2459c65b1445SDouglas Gilbert arr[0] = pcode; 246023183910SDouglas Gilbert if (0 == subpcode) { 2461c65b1445SDouglas Gilbert switch (pcode) { 2462c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2463c65b1445SDouglas Gilbert n = 4; 2464c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2465c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2466c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2467c65b1445SDouglas Gilbert arr[3] = n - 4; 2468c65b1445SDouglas Gilbert break; 2469c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2470c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2471c65b1445SDouglas Gilbert break; 2472c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2473c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2474c65b1445SDouglas Gilbert break; 2475c65b1445SDouglas Gilbert default: 247622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2477c65b1445SDouglas Gilbert return check_condition_result; 2478c65b1445SDouglas Gilbert } 247923183910SDouglas Gilbert } else if (0xff == subpcode) { 248023183910SDouglas Gilbert arr[0] |= 0x40; 248123183910SDouglas Gilbert arr[1] = subpcode; 248223183910SDouglas Gilbert switch (pcode) { 248323183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 248423183910SDouglas Gilbert n = 4; 248523183910SDouglas Gilbert arr[n++] = 0x0; 248623183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 248723183910SDouglas Gilbert arr[n++] = 0x0; 248823183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 248923183910SDouglas Gilbert arr[n++] = 0xd; 249023183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 249123183910SDouglas Gilbert arr[n++] = 0x2f; 249223183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 249323183910SDouglas Gilbert arr[3] = n - 4; 249423183910SDouglas Gilbert break; 249523183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 249623183910SDouglas Gilbert n = 4; 249723183910SDouglas Gilbert arr[n++] = 0xd; 249823183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 249923183910SDouglas Gilbert arr[3] = n - 4; 250023183910SDouglas Gilbert break; 250123183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 250223183910SDouglas Gilbert n = 4; 250323183910SDouglas Gilbert arr[n++] = 0x2f; 250423183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 250523183910SDouglas Gilbert arr[3] = n - 4; 250623183910SDouglas Gilbert break; 250723183910SDouglas Gilbert default: 250822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 250923183910SDouglas Gilbert return check_condition_result; 251023183910SDouglas Gilbert } 251123183910SDouglas Gilbert } else { 251222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 251323183910SDouglas Gilbert return check_condition_result; 251423183910SDouglas Gilbert } 251587c715dcSDouglas Gilbert len = min_t(int, get_unaligned_be16(arr + 2) + 4, alloc_len); 2516c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 251787c715dcSDouglas Gilbert min_t(int, len, SDEBUG_MAX_INQ_ARR_SZ)); 2518c65b1445SDouglas Gilbert } 2519c65b1445SDouglas Gilbert 25209447b6ceSMartin K. Petersen static inline int check_device_access_params(struct scsi_cmnd *scp, 25219447b6ceSMartin K. Petersen unsigned long long lba, unsigned int num, bool write) 25221da177e4SLinus Torvalds { 2523c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 252422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 25251da177e4SLinus Torvalds return check_condition_result; 25261da177e4SLinus Torvalds } 2527c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2528c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 252922017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2530cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2531c65b1445SDouglas Gilbert return check_condition_result; 2532c65b1445SDouglas Gilbert } 25339447b6ceSMartin K. Petersen if (write && unlikely(sdebug_wp)) { 25349447b6ceSMartin K. Petersen mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2); 25359447b6ceSMartin K. Petersen return check_condition_result; 25369447b6ceSMartin K. Petersen } 253719789100SFUJITA Tomonori return 0; 253819789100SFUJITA Tomonori } 253919789100SFUJITA Tomonori 254087c715dcSDouglas Gilbert static inline struct sdeb_store_info *devip2sip(struct sdebug_dev_info *devip) 254187c715dcSDouglas Gilbert { 254287c715dcSDouglas Gilbert return sdebug_fake_rw ? 254387c715dcSDouglas Gilbert NULL : xa_load(per_store_ap, devip->sdbg_host->si_idx); 254487c715dcSDouglas Gilbert } 254587c715dcSDouglas Gilbert 2546a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 254787c715dcSDouglas Gilbert static int do_device_access(struct sdeb_store_info *sip, struct scsi_cmnd *scp, 254887c715dcSDouglas Gilbert u32 sg_skip, u64 lba, u32 num, bool do_write) 254919789100SFUJITA Tomonori { 255019789100SFUJITA Tomonori int ret; 2551c2248fc9SDouglas Gilbert u64 block, rest = 0; 2552a4517511SAkinobu Mita enum dma_data_direction dir; 255387c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 255487c715dcSDouglas Gilbert u8 *fsp; 255519789100SFUJITA Tomonori 2556c2248fc9SDouglas Gilbert if (do_write) { 2557a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 25584f2c8bf6SDouglas Gilbert write_since_sync = true; 2559a4517511SAkinobu Mita } else { 2560a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2561a4517511SAkinobu Mita } 2562a4517511SAkinobu Mita 256387c715dcSDouglas Gilbert if (!sdb->length || !sip) 2564a4517511SAkinobu Mita return 0; 256587c715dcSDouglas Gilbert if (scp->sc_data_direction != dir) 2566a4517511SAkinobu Mita return -1; 256787c715dcSDouglas Gilbert fsp = sip->storep; 256819789100SFUJITA Tomonori 256919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 257019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 257119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 257219789100SFUJITA Tomonori 2573386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 257487c715dcSDouglas Gilbert fsp + (block * sdebug_sector_size), 25750a7e69c7SDouglas Gilbert (num - rest) * sdebug_sector_size, sg_skip, do_write); 2576773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2577a4517511SAkinobu Mita return ret; 2578a4517511SAkinobu Mita 2579a4517511SAkinobu Mita if (rest) { 2580386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 258187c715dcSDouglas Gilbert fsp, rest * sdebug_sector_size, 25820a7e69c7SDouglas Gilbert sg_skip + ((num - rest) * sdebug_sector_size), 25830a7e69c7SDouglas Gilbert do_write); 2584a4517511SAkinobu Mita } 258519789100SFUJITA Tomonori 258619789100SFUJITA Tomonori return ret; 258719789100SFUJITA Tomonori } 258819789100SFUJITA Tomonori 258987c715dcSDouglas Gilbert /* Returns number of bytes copied or -1 if error. */ 259087c715dcSDouglas Gilbert static int do_dout_fetch(struct scsi_cmnd *scp, u32 num, u8 *doutp) 259187c715dcSDouglas Gilbert { 259287c715dcSDouglas Gilbert struct scsi_data_buffer *sdb = &scp->sdb; 259387c715dcSDouglas Gilbert 259487c715dcSDouglas Gilbert if (!sdb->length) 259587c715dcSDouglas Gilbert return 0; 259687c715dcSDouglas Gilbert if (scp->sc_data_direction != DMA_TO_DEVICE) 259787c715dcSDouglas Gilbert return -1; 259887c715dcSDouglas Gilbert return sg_copy_buffer(sdb->table.sgl, sdb->table.nents, doutp, 259987c715dcSDouglas Gilbert num * sdebug_sector_size, 0, true); 260087c715dcSDouglas Gilbert } 260187c715dcSDouglas Gilbert 260287c715dcSDouglas Gilbert /* If sip->storep+lba compares equal to arr(num), then copy top half of 260387c715dcSDouglas Gilbert * arr into sip->storep+lba and return true. If comparison fails then 260438d5c833SDouglas Gilbert * return false. */ 260587c715dcSDouglas Gilbert static bool comp_write_worker(struct sdeb_store_info *sip, u64 lba, u32 num, 2606c3e2fe92SDouglas Gilbert const u8 *arr, bool compare_only) 260738d5c833SDouglas Gilbert { 260838d5c833SDouglas Gilbert bool res; 260938d5c833SDouglas Gilbert u64 block, rest = 0; 261038d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2611773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 261287c715dcSDouglas Gilbert u8 *fsp = sip->storep; 261338d5c833SDouglas Gilbert 261438d5c833SDouglas Gilbert block = do_div(lba, store_blks); 261538d5c833SDouglas Gilbert if (block + num > store_blks) 261638d5c833SDouglas Gilbert rest = block + num - store_blks; 261738d5c833SDouglas Gilbert 261887c715dcSDouglas Gilbert res = !memcmp(fsp + (block * lb_size), arr, (num - rest) * lb_size); 261938d5c833SDouglas Gilbert if (!res) 262038d5c833SDouglas Gilbert return res; 262138d5c833SDouglas Gilbert if (rest) 262287c715dcSDouglas Gilbert res = memcmp(fsp, arr + ((num - rest) * lb_size), 262338d5c833SDouglas Gilbert rest * lb_size); 262438d5c833SDouglas Gilbert if (!res) 262538d5c833SDouglas Gilbert return res; 2626c3e2fe92SDouglas Gilbert if (compare_only) 2627c3e2fe92SDouglas Gilbert return true; 262838d5c833SDouglas Gilbert arr += num * lb_size; 262987c715dcSDouglas Gilbert memcpy(fsp + (block * lb_size), arr, (num - rest) * lb_size); 263038d5c833SDouglas Gilbert if (rest) 263187c715dcSDouglas Gilbert memcpy(fsp, arr + ((num - rest) * lb_size), rest * lb_size); 263238d5c833SDouglas Gilbert return res; 263338d5c833SDouglas Gilbert } 263438d5c833SDouglas Gilbert 263551d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2636beb40ea4SAkinobu Mita { 263751d648afSAkinobu Mita __be16 csum; 2638beb40ea4SAkinobu Mita 2639773642d9SDouglas Gilbert if (sdebug_guard) 264051d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 264151d648afSAkinobu Mita else 2642beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 264351d648afSAkinobu Mita 2644beb40ea4SAkinobu Mita return csum; 2645beb40ea4SAkinobu Mita } 2646beb40ea4SAkinobu Mita 26476ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 2648beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2649beb40ea4SAkinobu Mita { 2650773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2651beb40ea4SAkinobu Mita 2652beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2653c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2654beb40ea4SAkinobu Mita (unsigned long)sector, 2655beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2656beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2657beb40ea4SAkinobu Mita return 0x01; 2658beb40ea4SAkinobu Mita } 26598475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 2660beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2661c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2662c1287970STomas Winkler (unsigned long)sector); 2663beb40ea4SAkinobu Mita return 0x03; 2664beb40ea4SAkinobu Mita } 26658475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2666beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2667c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2668c1287970STomas Winkler (unsigned long)sector); 2669beb40ea4SAkinobu Mita return 0x03; 2670beb40ea4SAkinobu Mita } 2671beb40ea4SAkinobu Mita return 0; 2672beb40ea4SAkinobu Mita } 2673beb40ea4SAkinobu Mita 267487c715dcSDouglas Gilbert static void dif_copy_prot(struct scsi_cmnd *scp, sector_t sector, 267565f72f2aSAkinobu Mita unsigned int sectors, bool read) 2676c6a44287SMartin K. Petersen { 2677be4e11beSAkinobu Mita size_t resid; 2678c6a44287SMartin K. Petersen void *paddr; 267987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 268087c715dcSDouglas Gilbert scp->device->hostdata); 268187c715dcSDouglas Gilbert struct t10_pi_tuple *dif_storep = sip->dif_storep; 268214faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2683be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2684c6a44287SMartin K. Petersen 2685e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2686e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2687c6a44287SMartin K. Petersen 268887c715dcSDouglas Gilbert sg_miter_start(&miter, scsi_prot_sglist(scp), 268987c715dcSDouglas Gilbert scsi_prot_sg_count(scp), SG_MITER_ATOMIC | 2690be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2691be4e11beSAkinobu Mita 2692be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 269387c715dcSDouglas Gilbert size_t len = min_t(size_t, miter.length, resid); 269487c715dcSDouglas Gilbert void *start = dif_store(sip, sector); 2695be4e11beSAkinobu Mita size_t rest = 0; 269614faa944SAkinobu Mita 269714faa944SAkinobu Mita if (dif_store_end < start + len) 269814faa944SAkinobu Mita rest = start + len - dif_store_end; 2699c6a44287SMartin K. Petersen 2700be4e11beSAkinobu Mita paddr = miter.addr; 270114faa944SAkinobu Mita 270265f72f2aSAkinobu Mita if (read) 270365f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 270465f72f2aSAkinobu Mita else 270565f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 270665f72f2aSAkinobu Mita 270765f72f2aSAkinobu Mita if (rest) { 270865f72f2aSAkinobu Mita if (read) 270914faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 271065f72f2aSAkinobu Mita else 271165f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 271265f72f2aSAkinobu Mita } 2713c6a44287SMartin K. Petersen 2714e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2715c6a44287SMartin K. Petersen resid -= len; 2716c6a44287SMartin K. Petersen } 2717be4e11beSAkinobu Mita sg_miter_stop(&miter); 2718bb8c063cSAkinobu Mita } 2719c6a44287SMartin K. Petersen 272087c715dcSDouglas Gilbert static int prot_verify_read(struct scsi_cmnd *scp, sector_t start_sec, 2721bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2722bb8c063cSAkinobu Mita { 2723bb8c063cSAkinobu Mita unsigned int i; 2724bb8c063cSAkinobu Mita sector_t sector; 272587c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 272687c715dcSDouglas Gilbert scp->device->hostdata); 272787c715dcSDouglas Gilbert struct t10_pi_tuple *sdt; 2728bb8c063cSAkinobu Mita 2729c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2730bb8c063cSAkinobu Mita int ret; 2731bb8c063cSAkinobu Mita 2732bb8c063cSAkinobu Mita sector = start_sec + i; 273387c715dcSDouglas Gilbert sdt = dif_store(sip, sector); 2734bb8c063cSAkinobu Mita 273551d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2736bb8c063cSAkinobu Mita continue; 2737bb8c063cSAkinobu Mita 273887c715dcSDouglas Gilbert ret = dif_verify(sdt, lba2fake_store(sip, sector), sector, 273987c715dcSDouglas Gilbert ei_lba); 2740bb8c063cSAkinobu Mita if (ret) { 2741bb8c063cSAkinobu Mita dif_errors++; 2742bb8c063cSAkinobu Mita return ret; 2743bb8c063cSAkinobu Mita } 2744bb8c063cSAkinobu Mita } 2745bb8c063cSAkinobu Mita 274687c715dcSDouglas Gilbert dif_copy_prot(scp, start_sec, sectors, true); 2747c6a44287SMartin K. Petersen dix_reads++; 2748c6a44287SMartin K. Petersen 2749c6a44287SMartin K. Petersen return 0; 2750c6a44287SMartin K. Petersen } 2751c6a44287SMartin K. Petersen 2752fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 275319789100SFUJITA Tomonori { 275487c715dcSDouglas Gilbert bool check_prot; 2755c2248fc9SDouglas Gilbert u32 num; 2756c2248fc9SDouglas Gilbert u32 ei_lba; 275719789100SFUJITA Tomonori int ret; 275887c715dcSDouglas Gilbert u64 lba; 275987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 276087c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 276187c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 276287c715dcSDouglas Gilbert struct sdebug_queued_cmd *sqcp; 276319789100SFUJITA Tomonori 2764c2248fc9SDouglas Gilbert switch (cmd[0]) { 2765c2248fc9SDouglas Gilbert case READ_16: 2766c2248fc9SDouglas Gilbert ei_lba = 0; 2767c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2768c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2769c2248fc9SDouglas Gilbert check_prot = true; 2770c2248fc9SDouglas Gilbert break; 2771c2248fc9SDouglas Gilbert case READ_10: 2772c2248fc9SDouglas Gilbert ei_lba = 0; 2773c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2774c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2775c2248fc9SDouglas Gilbert check_prot = true; 2776c2248fc9SDouglas Gilbert break; 2777c2248fc9SDouglas Gilbert case READ_6: 2778c2248fc9SDouglas Gilbert ei_lba = 0; 2779c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2780c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2781c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2782c2248fc9SDouglas Gilbert check_prot = true; 2783c2248fc9SDouglas Gilbert break; 2784c2248fc9SDouglas Gilbert case READ_12: 2785c2248fc9SDouglas Gilbert ei_lba = 0; 2786c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2787c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2788c2248fc9SDouglas Gilbert check_prot = true; 2789c2248fc9SDouglas Gilbert break; 2790c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2791c2248fc9SDouglas Gilbert ei_lba = 0; 2792c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2793c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2794c2248fc9SDouglas Gilbert check_prot = false; 2795c2248fc9SDouglas Gilbert break; 2796c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2797c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2798c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2799c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2800c2248fc9SDouglas Gilbert check_prot = false; 2801c2248fc9SDouglas Gilbert break; 2802c2248fc9SDouglas Gilbert } 2803f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 28048475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2805c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2806c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2807c2248fc9SDouglas Gilbert return check_condition_result; 2808c2248fc9SDouglas Gilbert } 28098475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 28108475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 2811c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2812c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2813c2248fc9SDouglas Gilbert "to DIF device\n"); 2814c2248fc9SDouglas Gilbert } 2815f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2816c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 2817c2248fc9SDouglas Gilbert 2818c4837394SDouglas Gilbert if (sqcp) { 2819c4837394SDouglas Gilbert if (sqcp->inj_short) 2820c2248fc9SDouglas Gilbert num /= 2; 2821c2248fc9SDouglas Gilbert } 2822c4837394SDouglas Gilbert } else 2823c4837394SDouglas Gilbert sqcp = NULL; 2824c2248fc9SDouglas Gilbert 28259447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 28269447b6ceSMartin K. Petersen if (ret) 28279447b6ceSMartin K. Petersen return ret; 2828f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 2829d9da891aSLaurence Oberman (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) && 2830d9da891aSLaurence Oberman ((lba + num) > sdebug_medium_error_start))) { 2831c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2832c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2833c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2834c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2835c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 283632f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 283732f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2838c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2839c65b1445SDouglas Gilbert } 2840c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 28411da177e4SLinus Torvalds return check_condition_result; 28421da177e4SLinus Torvalds } 2843c6a44287SMartin K. Petersen 284467da413fSDouglas Gilbert read_lock(macc_lckp); 28456c78cc06SAkinobu Mita 2846c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2847f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2848c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2849c6a44287SMartin K. Petersen 2850c6a44287SMartin K. Petersen if (prot_ret) { 285167da413fSDouglas Gilbert read_unlock(macc_lckp); 2852c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2853c6a44287SMartin K. Petersen return illegal_condition_result; 2854c6a44287SMartin K. Petersen } 2855c6a44287SMartin K. Petersen } 2856c6a44287SMartin K. Petersen 285787c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, false); 285867da413fSDouglas Gilbert read_unlock(macc_lckp); 2859f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2860a4517511SAkinobu Mita return DID_ERROR << 16; 2861a4517511SAkinobu Mita 286242d387beSBart Van Assche scsi_set_resid(scp, scsi_bufflen(scp) - ret); 2863a4517511SAkinobu Mita 2864c4837394SDouglas Gilbert if (unlikely(sqcp)) { 2865c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2866c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2867c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2868c2248fc9SDouglas Gilbert return check_condition_result; 2869c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 2870c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2871c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2872c2248fc9SDouglas Gilbert return check_condition_result; 2873c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2874c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2875c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2876c2248fc9SDouglas Gilbert return illegal_condition_result; 2877c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2878c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2879c2248fc9SDouglas Gilbert return illegal_condition_result; 2880c2248fc9SDouglas Gilbert } 2881c2248fc9SDouglas Gilbert } 2882a4517511SAkinobu Mita return 0; 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds 288558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2886c6a44287SMartin K. Petersen { 2887cbf67842SDouglas Gilbert int i, j, n; 2888c6a44287SMartin K. Petersen 2889cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2890c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2891cbf67842SDouglas Gilbert char b[128]; 2892c6a44287SMartin K. Petersen 2893cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2894c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2895c6a44287SMartin K. Petersen 2896cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2897cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2898cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2899cbf67842SDouglas Gilbert else 2900cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2901cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2902cbf67842SDouglas Gilbert } 2903cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2904c6a44287SMartin K. Petersen } 2905c6a44287SMartin K. Petersen } 2906c6a44287SMartin K. Petersen 2907c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2908395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2909c6a44287SMartin K. Petersen { 2910be4e11beSAkinobu Mita int ret; 29116ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 2912be4e11beSAkinobu Mita void *daddr; 291365f72f2aSAkinobu Mita sector_t sector = start_sec; 2914c6a44287SMartin K. Petersen int ppage_offset; 2915be4e11beSAkinobu Mita int dpage_offset; 2916be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2917be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2918c6a44287SMartin K. Petersen 2919c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2920c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2921c6a44287SMartin K. Petersen 2922be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2923be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2924be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2925be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2926be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2927c6a44287SMartin K. Petersen 2928be4e11beSAkinobu Mita /* For each protection page */ 2929be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2930be4e11beSAkinobu Mita dpage_offset = 0; 2931be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2932be4e11beSAkinobu Mita ret = 0x01; 2933be4e11beSAkinobu Mita goto out; 2934c6a44287SMartin K. Petersen } 2935c6a44287SMartin K. Petersen 2936be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 29376ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 2938be4e11beSAkinobu Mita /* If we're at the end of the current 2939be4e11beSAkinobu Mita * data page advance to the next one 2940be4e11beSAkinobu Mita */ 2941be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2942be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2943be4e11beSAkinobu Mita ret = 0x01; 2944be4e11beSAkinobu Mita goto out; 2945be4e11beSAkinobu Mita } 2946be4e11beSAkinobu Mita dpage_offset = 0; 2947be4e11beSAkinobu Mita } 2948c6a44287SMartin K. Petersen 2949be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2950be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2951be4e11beSAkinobu Mita 2952be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2953beb40ea4SAkinobu Mita if (ret) { 2954773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2955395cef03SMartin K. Petersen goto out; 2956395cef03SMartin K. Petersen } 2957395cef03SMartin K. Petersen 2958c6a44287SMartin K. Petersen sector++; 2959395cef03SMartin K. Petersen ei_lba++; 2960773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2961c6a44287SMartin K. Petersen } 2962be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2963be4e11beSAkinobu Mita sg_miter_stop(&diter); 2964c6a44287SMartin K. Petersen } 2965be4e11beSAkinobu Mita sg_miter_stop(&piter); 2966c6a44287SMartin K. Petersen 296765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2968c6a44287SMartin K. Petersen dix_writes++; 2969c6a44287SMartin K. Petersen 2970c6a44287SMartin K. Petersen return 0; 2971c6a44287SMartin K. Petersen 2972c6a44287SMartin K. Petersen out: 2973c6a44287SMartin K. Petersen dif_errors++; 2974be4e11beSAkinobu Mita sg_miter_stop(&diter); 2975be4e11beSAkinobu Mita sg_miter_stop(&piter); 2976c6a44287SMartin K. Petersen return ret; 2977c6a44287SMartin K. Petersen } 2978c6a44287SMartin K. Petersen 2979b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2980b90ebc3dSAkinobu Mita { 2981773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2982773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2983773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2984b90ebc3dSAkinobu Mita return lba; 2985b90ebc3dSAkinobu Mita } 2986b90ebc3dSAkinobu Mita 2987b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2988b90ebc3dSAkinobu Mita { 2989773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2990a027b5b9SAkinobu Mita 2991773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2992773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2993a027b5b9SAkinobu Mita return lba; 2994a027b5b9SAkinobu Mita } 2995a027b5b9SAkinobu Mita 299687c715dcSDouglas Gilbert static unsigned int map_state(struct sdeb_store_info *sip, sector_t lba, 299787c715dcSDouglas Gilbert unsigned int *num) 299844d92694SMartin K. Petersen { 2999b90ebc3dSAkinobu Mita sector_t end; 3000b90ebc3dSAkinobu Mita unsigned int mapped; 3001b90ebc3dSAkinobu Mita unsigned long index; 3002b90ebc3dSAkinobu Mita unsigned long next; 300344d92694SMartin K. Petersen 3004b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 300587c715dcSDouglas Gilbert mapped = test_bit(index, sip->map_storep); 300644d92694SMartin K. Petersen 300744d92694SMartin K. Petersen if (mapped) 300887c715dcSDouglas Gilbert next = find_next_zero_bit(sip->map_storep, map_size, index); 300944d92694SMartin K. Petersen else 301087c715dcSDouglas Gilbert next = find_next_bit(sip->map_storep, map_size, index); 301144d92694SMartin K. Petersen 3012b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 301344d92694SMartin K. Petersen *num = end - lba; 301444d92694SMartin K. Petersen return mapped; 301544d92694SMartin K. Petersen } 301644d92694SMartin K. Petersen 301787c715dcSDouglas Gilbert static void map_region(struct sdeb_store_info *sip, sector_t lba, 301887c715dcSDouglas Gilbert unsigned int len) 301944d92694SMartin K. Petersen { 302044d92694SMartin K. Petersen sector_t end = lba + len; 302144d92694SMartin K. Petersen 302244d92694SMartin K. Petersen while (lba < end) { 3023b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 302444d92694SMartin K. Petersen 3025b90ebc3dSAkinobu Mita if (index < map_size) 302687c715dcSDouglas Gilbert set_bit(index, sip->map_storep); 302744d92694SMartin K. Petersen 3028b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 302944d92694SMartin K. Petersen } 303044d92694SMartin K. Petersen } 303144d92694SMartin K. Petersen 303287c715dcSDouglas Gilbert static void unmap_region(struct sdeb_store_info *sip, sector_t lba, 303387c715dcSDouglas Gilbert unsigned int len) 303444d92694SMartin K. Petersen { 303544d92694SMartin K. Petersen sector_t end = lba + len; 303687c715dcSDouglas Gilbert u8 *fsp = sip->storep; 303744d92694SMartin K. Petersen 303844d92694SMartin K. Petersen while (lba < end) { 3039b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 304044d92694SMartin K. Petersen 3041b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 3042773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 3043b90ebc3dSAkinobu Mita index < map_size) { 304487c715dcSDouglas Gilbert clear_bit(index, sip->map_storep); 3045760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 304687c715dcSDouglas Gilbert memset(fsp + lba * sdebug_sector_size, 3047760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 3048773642d9SDouglas Gilbert sdebug_sector_size * 3049773642d9SDouglas Gilbert sdebug_unmap_granularity); 3050be1dd78dSEric Sandeen } 305187c715dcSDouglas Gilbert if (sip->dif_storep) { 305287c715dcSDouglas Gilbert memset(sip->dif_storep + lba, 0xff, 305387c715dcSDouglas Gilbert sizeof(*sip->dif_storep) * 3054773642d9SDouglas Gilbert sdebug_unmap_granularity); 3055e9926b43SAkinobu Mita } 3056b90ebc3dSAkinobu Mita } 3057b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 305844d92694SMartin K. Petersen } 305944d92694SMartin K. Petersen } 306044d92694SMartin K. Petersen 3061fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 30621da177e4SLinus Torvalds { 306387c715dcSDouglas Gilbert bool check_prot; 3064c2248fc9SDouglas Gilbert u32 num; 3065c2248fc9SDouglas Gilbert u32 ei_lba; 306619789100SFUJITA Tomonori int ret; 306787c715dcSDouglas Gilbert u64 lba; 306887c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 306987c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 307087c715dcSDouglas Gilbert u8 *cmd = scp->cmnd; 30711da177e4SLinus Torvalds 3072c2248fc9SDouglas Gilbert switch (cmd[0]) { 3073c2248fc9SDouglas Gilbert case WRITE_16: 3074c2248fc9SDouglas Gilbert ei_lba = 0; 3075c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3076c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3077c2248fc9SDouglas Gilbert check_prot = true; 3078c2248fc9SDouglas Gilbert break; 3079c2248fc9SDouglas Gilbert case WRITE_10: 3080c2248fc9SDouglas Gilbert ei_lba = 0; 3081c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3082c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3083c2248fc9SDouglas Gilbert check_prot = true; 3084c2248fc9SDouglas Gilbert break; 3085c2248fc9SDouglas Gilbert case WRITE_6: 3086c2248fc9SDouglas Gilbert ei_lba = 0; 3087c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 3088c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 3089c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 3090c2248fc9SDouglas Gilbert check_prot = true; 3091c2248fc9SDouglas Gilbert break; 3092c2248fc9SDouglas Gilbert case WRITE_12: 3093c2248fc9SDouglas Gilbert ei_lba = 0; 3094c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3095c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 3096c2248fc9SDouglas Gilbert check_prot = true; 3097c2248fc9SDouglas Gilbert break; 3098c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 3099c2248fc9SDouglas Gilbert ei_lba = 0; 3100c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3101c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3102c2248fc9SDouglas Gilbert check_prot = false; 3103c2248fc9SDouglas Gilbert break; 3104c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 3105c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 3106c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 3107c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 3108c2248fc9SDouglas Gilbert check_prot = false; 3109c2248fc9SDouglas Gilbert break; 3110c2248fc9SDouglas Gilbert } 3111f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 31128475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3113c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 3114c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 3115c2248fc9SDouglas Gilbert return check_condition_result; 3116c2248fc9SDouglas Gilbert } 31178475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31188475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3119c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 3120c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 3121c2248fc9SDouglas Gilbert "to DIF device\n"); 3122c2248fc9SDouglas Gilbert } 31239447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 31249447b6ceSMartin K. Petersen if (ret) 31259447b6ceSMartin K. Petersen return ret; 312667da413fSDouglas Gilbert write_lock(macc_lckp); 31276c78cc06SAkinobu Mita 3128c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 3129f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3130c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 3131c6a44287SMartin K. Petersen 3132c6a44287SMartin K. Petersen if (prot_ret) { 313367da413fSDouglas Gilbert write_unlock(macc_lckp); 3134c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 3135c6a44287SMartin K. Petersen return illegal_condition_result; 3136c6a44287SMartin K. Petersen } 3137c6a44287SMartin K. Petersen } 3138c6a44287SMartin K. Petersen 313987c715dcSDouglas Gilbert ret = do_device_access(sip, scp, 0, lba, num, true); 3140f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 314187c715dcSDouglas Gilbert map_region(sip, lba, num); 314267da413fSDouglas Gilbert write_unlock(macc_lckp); 3143f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3144773642d9SDouglas Gilbert return DID_ERROR << 16; 3145c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3146c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3147c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3148cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3149773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 315044d92694SMartin K. Petersen 3151f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3152c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3153c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3154c2248fc9SDouglas Gilbert 3155c4837394SDouglas Gilbert if (sqcp) { 3156c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3157c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3158c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3159c2248fc9SDouglas Gilbert return check_condition_result; 3160c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3161c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3162c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3163c2248fc9SDouglas Gilbert return illegal_condition_result; 3164c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3165c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3166c2248fc9SDouglas Gilbert return illegal_condition_result; 3167c2248fc9SDouglas Gilbert } 3168c2248fc9SDouglas Gilbert } 3169c4837394SDouglas Gilbert } 31701da177e4SLinus Torvalds return 0; 31711da177e4SLinus Torvalds } 31721da177e4SLinus Torvalds 3173481b5e5cSDouglas Gilbert /* 3174481b5e5cSDouglas Gilbert * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32). 3175481b5e5cSDouglas Gilbert * No READ GATHERED yet (requires bidi or long cdb holding gather list). 3176481b5e5cSDouglas Gilbert */ 3177481b5e5cSDouglas Gilbert static int resp_write_scat(struct scsi_cmnd *scp, 3178481b5e5cSDouglas Gilbert struct sdebug_dev_info *devip) 3179481b5e5cSDouglas Gilbert { 3180481b5e5cSDouglas Gilbert u8 *cmd = scp->cmnd; 3181481b5e5cSDouglas Gilbert u8 *lrdp = NULL; 3182481b5e5cSDouglas Gilbert u8 *up; 318387c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 318487c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 3185481b5e5cSDouglas Gilbert u8 wrprotect; 3186481b5e5cSDouglas Gilbert u16 lbdof, num_lrd, k; 3187481b5e5cSDouglas Gilbert u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb; 3188481b5e5cSDouglas Gilbert u32 lb_size = sdebug_sector_size; 3189481b5e5cSDouglas Gilbert u32 ei_lba; 3190481b5e5cSDouglas Gilbert u64 lba; 3191481b5e5cSDouglas Gilbert int ret, res; 3192481b5e5cSDouglas Gilbert bool is_16; 3193481b5e5cSDouglas Gilbert static const u32 lrd_size = 32; /* + parameter list header size */ 3194481b5e5cSDouglas Gilbert 3195481b5e5cSDouglas Gilbert if (cmd[0] == VARIABLE_LENGTH_CMD) { 3196481b5e5cSDouglas Gilbert is_16 = false; 3197481b5e5cSDouglas Gilbert wrprotect = (cmd[10] >> 5) & 0x7; 3198481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 12); 3199481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 16); 3200481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 28); 3201481b5e5cSDouglas Gilbert } else { /* that leaves WRITE SCATTERED(16) */ 3202481b5e5cSDouglas Gilbert is_16 = true; 3203481b5e5cSDouglas Gilbert wrprotect = (cmd[2] >> 5) & 0x7; 3204481b5e5cSDouglas Gilbert lbdof = get_unaligned_be16(cmd + 4); 3205481b5e5cSDouglas Gilbert num_lrd = get_unaligned_be16(cmd + 8); 3206481b5e5cSDouglas Gilbert bt_len = get_unaligned_be32(cmd + 10); 3207481b5e5cSDouglas Gilbert if (unlikely(have_dif_prot)) { 3208481b5e5cSDouglas Gilbert if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 3209481b5e5cSDouglas Gilbert wrprotect) { 3210481b5e5cSDouglas Gilbert mk_sense_invalid_opcode(scp); 3211481b5e5cSDouglas Gilbert return illegal_condition_result; 3212481b5e5cSDouglas Gilbert } 3213481b5e5cSDouglas Gilbert if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 3214481b5e5cSDouglas Gilbert sdebug_dif == T10_PI_TYPE3_PROTECTION) && 3215481b5e5cSDouglas Gilbert wrprotect == 0) 3216481b5e5cSDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 3217481b5e5cSDouglas Gilbert "Unprotected WR to DIF device\n"); 3218481b5e5cSDouglas Gilbert } 3219481b5e5cSDouglas Gilbert } 3220481b5e5cSDouglas Gilbert if ((num_lrd == 0) || (bt_len == 0)) 3221481b5e5cSDouglas Gilbert return 0; /* T10 says these do-nothings are not errors */ 3222481b5e5cSDouglas Gilbert if (lbdof == 0) { 3223481b5e5cSDouglas Gilbert if (sdebug_verbose) 3224481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3225481b5e5cSDouglas Gilbert "%s: %s: LB Data Offset field bad\n", 3226481b5e5cSDouglas Gilbert my_name, __func__); 3227481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3228481b5e5cSDouglas Gilbert return illegal_condition_result; 3229481b5e5cSDouglas Gilbert } 3230481b5e5cSDouglas Gilbert lbdof_blen = lbdof * lb_size; 3231481b5e5cSDouglas Gilbert if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) { 3232481b5e5cSDouglas Gilbert if (sdebug_verbose) 3233481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3234481b5e5cSDouglas Gilbert "%s: %s: LBA range descriptors don't fit\n", 3235481b5e5cSDouglas Gilbert my_name, __func__); 3236481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 3237481b5e5cSDouglas Gilbert return illegal_condition_result; 3238481b5e5cSDouglas Gilbert } 3239481b5e5cSDouglas Gilbert lrdp = kzalloc(lbdof_blen, GFP_ATOMIC); 3240481b5e5cSDouglas Gilbert if (lrdp == NULL) 3241481b5e5cSDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3242481b5e5cSDouglas Gilbert if (sdebug_verbose) 3243481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3244481b5e5cSDouglas Gilbert "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n", 3245481b5e5cSDouglas Gilbert my_name, __func__, lbdof_blen); 3246481b5e5cSDouglas Gilbert res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen); 3247481b5e5cSDouglas Gilbert if (res == -1) { 3248481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3249481b5e5cSDouglas Gilbert goto err_out; 3250481b5e5cSDouglas Gilbert } 3251481b5e5cSDouglas Gilbert 325267da413fSDouglas Gilbert write_lock(macc_lckp); 3253481b5e5cSDouglas Gilbert sg_off = lbdof_blen; 3254481b5e5cSDouglas Gilbert /* Spec says Buffer xfer Length field in number of LBs in dout */ 3255481b5e5cSDouglas Gilbert cum_lb = 0; 3256481b5e5cSDouglas Gilbert for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) { 3257481b5e5cSDouglas Gilbert lba = get_unaligned_be64(up + 0); 3258481b5e5cSDouglas Gilbert num = get_unaligned_be32(up + 8); 3259481b5e5cSDouglas Gilbert if (sdebug_verbose) 3260481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3261481b5e5cSDouglas Gilbert "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n", 3262481b5e5cSDouglas Gilbert my_name, __func__, k, lba, num, sg_off); 3263481b5e5cSDouglas Gilbert if (num == 0) 3264481b5e5cSDouglas Gilbert continue; 32659447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 3266481b5e5cSDouglas Gilbert if (ret) 3267481b5e5cSDouglas Gilbert goto err_out_unlock; 3268481b5e5cSDouglas Gilbert num_by = num * lb_size; 3269481b5e5cSDouglas Gilbert ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12); 3270481b5e5cSDouglas Gilbert 3271481b5e5cSDouglas Gilbert if ((cum_lb + num) > bt_len) { 3272481b5e5cSDouglas Gilbert if (sdebug_verbose) 3273481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3274481b5e5cSDouglas Gilbert "%s: %s: sum of blocks > data provided\n", 3275481b5e5cSDouglas Gilbert my_name, __func__); 3276481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC, 3277481b5e5cSDouglas Gilbert 0); 3278481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3279481b5e5cSDouglas Gilbert goto err_out_unlock; 3280481b5e5cSDouglas Gilbert } 3281481b5e5cSDouglas Gilbert 3282481b5e5cSDouglas Gilbert /* DIX + T10 DIF */ 3283481b5e5cSDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 3284481b5e5cSDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, 3285481b5e5cSDouglas Gilbert ei_lba); 3286481b5e5cSDouglas Gilbert 3287481b5e5cSDouglas Gilbert if (prot_ret) { 3288481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 3289481b5e5cSDouglas Gilbert prot_ret); 3290481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3291481b5e5cSDouglas Gilbert goto err_out_unlock; 3292481b5e5cSDouglas Gilbert } 3293481b5e5cSDouglas Gilbert } 3294481b5e5cSDouglas Gilbert 329587c715dcSDouglas Gilbert ret = do_device_access(sip, scp, sg_off, lba, num, true); 3296481b5e5cSDouglas Gilbert if (unlikely(scsi_debug_lbp())) 329787c715dcSDouglas Gilbert map_region(sip, lba, num); 3298481b5e5cSDouglas Gilbert if (unlikely(-1 == ret)) { 3299481b5e5cSDouglas Gilbert ret = DID_ERROR << 16; 3300481b5e5cSDouglas Gilbert goto err_out_unlock; 3301481b5e5cSDouglas Gilbert } else if (unlikely(sdebug_verbose && (ret < num_by))) 3302481b5e5cSDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3303481b5e5cSDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3304481b5e5cSDouglas Gilbert my_name, num_by, ret); 3305481b5e5cSDouglas Gilbert 3306481b5e5cSDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3307481b5e5cSDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3308481b5e5cSDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3309481b5e5cSDouglas Gilbert 3310481b5e5cSDouglas Gilbert if (sqcp) { 3311481b5e5cSDouglas Gilbert if (sqcp->inj_recovered) { 3312481b5e5cSDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3313481b5e5cSDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3314481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3315481b5e5cSDouglas Gilbert goto err_out_unlock; 3316481b5e5cSDouglas Gilbert } else if (sqcp->inj_dif) { 3317481b5e5cSDouglas Gilbert /* Logical block guard check failed */ 3318481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 3319481b5e5cSDouglas Gilbert 0x10, 1); 3320481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3321481b5e5cSDouglas Gilbert goto err_out_unlock; 3322481b5e5cSDouglas Gilbert } else if (sqcp->inj_dix) { 3323481b5e5cSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 3324481b5e5cSDouglas Gilbert 0x10, 1); 3325481b5e5cSDouglas Gilbert ret = illegal_condition_result; 3326481b5e5cSDouglas Gilbert goto err_out_unlock; 3327481b5e5cSDouglas Gilbert } 3328481b5e5cSDouglas Gilbert } 3329481b5e5cSDouglas Gilbert } 3330481b5e5cSDouglas Gilbert sg_off += num_by; 3331481b5e5cSDouglas Gilbert cum_lb += num; 3332481b5e5cSDouglas Gilbert } 3333481b5e5cSDouglas Gilbert ret = 0; 3334481b5e5cSDouglas Gilbert err_out_unlock: 333567da413fSDouglas Gilbert write_unlock(macc_lckp); 3336481b5e5cSDouglas Gilbert err_out: 3337481b5e5cSDouglas Gilbert kfree(lrdp); 3338481b5e5cSDouglas Gilbert return ret; 3339481b5e5cSDouglas Gilbert } 3340481b5e5cSDouglas Gilbert 3341fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3342fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 334344d92694SMartin K. Petersen { 334444d92694SMartin K. Petersen unsigned long long i; 334540d07b52SDouglas Gilbert u64 block, lbaa; 334687c715dcSDouglas Gilbert u32 lb_size = sdebug_sector_size; 334787c715dcSDouglas Gilbert int ret; 334887c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip((struct sdebug_dev_info *) 334987c715dcSDouglas Gilbert scp->device->hostdata); 335087c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 335140d07b52SDouglas Gilbert u8 *fs1p; 335287c715dcSDouglas Gilbert u8 *fsp; 335344d92694SMartin K. Petersen 33549447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 335544d92694SMartin K. Petersen if (ret) 335644d92694SMartin K. Petersen return ret; 335744d92694SMartin K. Petersen 335867da413fSDouglas Gilbert write_lock(macc_lckp); 335944d92694SMartin K. Petersen 33609ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 336187c715dcSDouglas Gilbert unmap_region(sip, lba, num); 336244d92694SMartin K. Petersen goto out; 336344d92694SMartin K. Petersen } 336440d07b52SDouglas Gilbert lbaa = lba; 336540d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 3366c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 336787c715dcSDouglas Gilbert fsp = sip->storep; 336887c715dcSDouglas Gilbert fs1p = fsp + (block * lb_size); 3369c2248fc9SDouglas Gilbert if (ndob) { 337040d07b52SDouglas Gilbert memset(fs1p, 0, lb_size); 3371c2248fc9SDouglas Gilbert ret = 0; 3372c2248fc9SDouglas Gilbert } else 337340d07b52SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fs1p, lb_size); 337444d92694SMartin K. Petersen 337544d92694SMartin K. Petersen if (-1 == ret) { 337667da413fSDouglas Gilbert write_unlock(&sip->macc_lck); 3377773642d9SDouglas Gilbert return DID_ERROR << 16; 337840d07b52SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < lb_size)) 3379c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3380e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 338140d07b52SDouglas Gilbert my_name, "write same", lb_size, ret); 338244d92694SMartin K. Petersen 338344d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 338440d07b52SDouglas Gilbert for (i = 1 ; i < num ; i++) { 338540d07b52SDouglas Gilbert lbaa = lba + i; 338640d07b52SDouglas Gilbert block = do_div(lbaa, sdebug_store_sectors); 338787c715dcSDouglas Gilbert memmove(fsp + (block * lb_size), fs1p, lb_size); 338840d07b52SDouglas Gilbert } 33899ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 339087c715dcSDouglas Gilbert map_region(sip, lba, num); 339144d92694SMartin K. Petersen out: 339267da413fSDouglas Gilbert write_unlock(macc_lckp); 339344d92694SMartin K. Petersen 339444d92694SMartin K. Petersen return 0; 339544d92694SMartin K. Petersen } 339644d92694SMartin K. Petersen 3397fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3398fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3399c2248fc9SDouglas Gilbert { 3400c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3401c2248fc9SDouglas Gilbert u32 lba; 3402c2248fc9SDouglas Gilbert u16 num; 3403c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3404c2248fc9SDouglas Gilbert bool unmap = false; 3405c2248fc9SDouglas Gilbert 3406c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3407773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3408c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3409c2248fc9SDouglas Gilbert return check_condition_result; 3410c2248fc9SDouglas Gilbert } else 3411c2248fc9SDouglas Gilbert unmap = true; 3412c2248fc9SDouglas Gilbert } 3413c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3414c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3415773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3416c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3417c2248fc9SDouglas Gilbert return check_condition_result; 3418c2248fc9SDouglas Gilbert } 3419c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3420c2248fc9SDouglas Gilbert } 3421c2248fc9SDouglas Gilbert 3422fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3423fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3424c2248fc9SDouglas Gilbert { 3425c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3426c2248fc9SDouglas Gilbert u64 lba; 3427c2248fc9SDouglas Gilbert u32 num; 3428c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3429c2248fc9SDouglas Gilbert bool unmap = false; 3430c2248fc9SDouglas Gilbert bool ndob = false; 3431c2248fc9SDouglas Gilbert 3432c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3433773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3434c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3435c2248fc9SDouglas Gilbert return check_condition_result; 3436c2248fc9SDouglas Gilbert } else 3437c2248fc9SDouglas Gilbert unmap = true; 3438c2248fc9SDouglas Gilbert } 3439c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3440c2248fc9SDouglas Gilbert ndob = true; 3441c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3442c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3443773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3444c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3445c2248fc9SDouglas Gilbert return check_condition_result; 3446c2248fc9SDouglas Gilbert } 3447c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3448c2248fc9SDouglas Gilbert } 3449c2248fc9SDouglas Gilbert 3450acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3451acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3452acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3453fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3454fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3455acafd0b9SEwan D. Milne { 3456acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3457acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3458acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3459acafd0b9SEwan D. Milne u8 mode; 3460acafd0b9SEwan D. Milne 3461acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3462acafd0b9SEwan D. Milne switch (mode) { 3463acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3464acafd0b9SEwan D. Milne /* set UAs on this device only */ 3465acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3466acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3467acafd0b9SEwan D. Milne break; 3468acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3469acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3470acafd0b9SEwan D. Milne break; 3471acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3472acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3473acafd0b9SEwan D. Milne list_for_each_entry(dp, 3474acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3475acafd0b9SEwan D. Milne dev_list) 3476acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3477acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3478acafd0b9SEwan D. Milne if (devip != dp) 3479acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3480acafd0b9SEwan D. Milne dp->uas_bm); 3481acafd0b9SEwan D. Milne } 3482acafd0b9SEwan D. Milne break; 3483acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3484acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3485acafd0b9SEwan D. Milne list_for_each_entry(dp, 3486acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3487acafd0b9SEwan D. Milne dev_list) 3488acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3489acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3490acafd0b9SEwan D. Milne dp->uas_bm); 3491acafd0b9SEwan D. Milne break; 3492acafd0b9SEwan D. Milne default: 3493acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3494acafd0b9SEwan D. Milne break; 3495acafd0b9SEwan D. Milne } 3496acafd0b9SEwan D. Milne return 0; 3497acafd0b9SEwan D. Milne } 3498acafd0b9SEwan D. Milne 3499fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3500fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 350138d5c833SDouglas Gilbert { 350238d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 350338d5c833SDouglas Gilbert u8 *arr; 350487c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 350587c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 350638d5c833SDouglas Gilbert u64 lba; 350738d5c833SDouglas Gilbert u32 dnum; 3508773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 350938d5c833SDouglas Gilbert u8 num; 351038d5c833SDouglas Gilbert int ret; 3511d467d31fSDouglas Gilbert int retval = 0; 351238d5c833SDouglas Gilbert 3513d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 351438d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 351538d5c833SDouglas Gilbert if (0 == num) 351638d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 35178475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 351838d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 351938d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 352038d5c833SDouglas Gilbert return check_condition_result; 352138d5c833SDouglas Gilbert } 35228475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 35238475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 352438d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 352538d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 352638d5c833SDouglas Gilbert "to DIF device\n"); 35279447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, false); 35289447b6ceSMartin K. Petersen if (ret) 35299447b6ceSMartin K. Petersen return ret; 3530d467d31fSDouglas Gilbert dnum = 2 * num; 35316396bb22SKees Cook arr = kcalloc(lb_size, dnum, GFP_ATOMIC); 3532d467d31fSDouglas Gilbert if (NULL == arr) { 3533d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3534d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3535d467d31fSDouglas Gilbert return check_condition_result; 3536d467d31fSDouglas Gilbert } 353738d5c833SDouglas Gilbert 353867da413fSDouglas Gilbert write_lock(macc_lckp); 353938d5c833SDouglas Gilbert 354087c715dcSDouglas Gilbert ret = do_dout_fetch(scp, dnum, arr); 354138d5c833SDouglas Gilbert if (ret == -1) { 3542d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3543d467d31fSDouglas Gilbert goto cleanup; 3544773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 354538d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 354638d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 354738d5c833SDouglas Gilbert dnum * lb_size, ret); 3548c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, num, arr, false)) { 354938d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3550d467d31fSDouglas Gilbert retval = check_condition_result; 3551d467d31fSDouglas Gilbert goto cleanup; 355238d5c833SDouglas Gilbert } 355338d5c833SDouglas Gilbert if (scsi_debug_lbp()) 355487c715dcSDouglas Gilbert map_region(sip, lba, num); 3555d467d31fSDouglas Gilbert cleanup: 355667da413fSDouglas Gilbert write_unlock(macc_lckp); 3557d467d31fSDouglas Gilbert kfree(arr); 3558d467d31fSDouglas Gilbert return retval; 355938d5c833SDouglas Gilbert } 356038d5c833SDouglas Gilbert 356144d92694SMartin K. Petersen struct unmap_block_desc { 356244d92694SMartin K. Petersen __be64 lba; 356344d92694SMartin K. Petersen __be32 blocks; 356444d92694SMartin K. Petersen __be32 __reserved; 356544d92694SMartin K. Petersen }; 356644d92694SMartin K. Petersen 3567fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 356844d92694SMartin K. Petersen { 356944d92694SMartin K. Petersen unsigned char *buf; 357044d92694SMartin K. Petersen struct unmap_block_desc *desc; 357187c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 357287c715dcSDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 357344d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 357444d92694SMartin K. Petersen int ret; 357544d92694SMartin K. Petersen 3576c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3577c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3578c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3579c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 358044d92694SMartin K. Petersen 358144d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3582773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3583c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 358444d92694SMartin K. Petersen return check_condition_result; 3585c2248fc9SDouglas Gilbert } 358644d92694SMartin K. Petersen 3587b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3588c2248fc9SDouglas Gilbert if (!buf) { 3589c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3590c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3591c2248fc9SDouglas Gilbert return check_condition_result; 3592c2248fc9SDouglas Gilbert } 3593c2248fc9SDouglas Gilbert 3594c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 359544d92694SMartin K. Petersen 359644d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 359744d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 359844d92694SMartin K. Petersen 359944d92694SMartin K. Petersen desc = (void *)&buf[8]; 360044d92694SMartin K. Petersen 360167da413fSDouglas Gilbert write_lock(macc_lckp); 36026c78cc06SAkinobu Mita 360344d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 360444d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 360544d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 360644d92694SMartin K. Petersen 36079447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, num, true); 360844d92694SMartin K. Petersen if (ret) 360944d92694SMartin K. Petersen goto out; 361044d92694SMartin K. Petersen 361187c715dcSDouglas Gilbert unmap_region(sip, lba, num); 361244d92694SMartin K. Petersen } 361344d92694SMartin K. Petersen 361444d92694SMartin K. Petersen ret = 0; 361544d92694SMartin K. Petersen 361644d92694SMartin K. Petersen out: 361767da413fSDouglas Gilbert write_unlock(macc_lckp); 361844d92694SMartin K. Petersen kfree(buf); 361944d92694SMartin K. Petersen 362044d92694SMartin K. Petersen return ret; 362144d92694SMartin K. Petersen } 362244d92694SMartin K. Petersen 362344d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 362444d92694SMartin K. Petersen 3625fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3626fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 362744d92694SMartin K. Petersen { 3628c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 362987c715dcSDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 3630c2248fc9SDouglas Gilbert u64 lba; 3631c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 363244d92694SMartin K. Petersen int ret; 363387c715dcSDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 363444d92694SMartin K. Petersen 3635c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3636c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 363744d92694SMartin K. Petersen 363844d92694SMartin K. Petersen if (alloc_len < 24) 363944d92694SMartin K. Petersen return 0; 364044d92694SMartin K. Petersen 36419447b6ceSMartin K. Petersen ret = check_device_access_params(scp, lba, 1, false); 364244d92694SMartin K. Petersen if (ret) 364344d92694SMartin K. Petersen return ret; 364444d92694SMartin K. Petersen 3645c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 364687c715dcSDouglas Gilbert mapped = map_state(sip, lba, &num); 3647c2248fc9SDouglas Gilbert else { 3648c2248fc9SDouglas Gilbert mapped = 1; 3649c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3650c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3651c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3652c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3653c2248fc9SDouglas Gilbert else 3654c2248fc9SDouglas Gilbert num = 0xffffffff; 3655c2248fc9SDouglas Gilbert } 365644d92694SMartin K. Petersen 365744d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3658c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3659c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3660c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3661c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 366244d92694SMartin K. Petersen 3663c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 366444d92694SMartin K. Petersen } 366544d92694SMartin K. Petersen 366680c49563SDouglas Gilbert static int resp_sync_cache(struct scsi_cmnd *scp, 366780c49563SDouglas Gilbert struct sdebug_dev_info *devip) 366880c49563SDouglas Gilbert { 36694f2c8bf6SDouglas Gilbert int res = 0; 367080c49563SDouglas Gilbert u64 lba; 367180c49563SDouglas Gilbert u32 num_blocks; 367280c49563SDouglas Gilbert u8 *cmd = scp->cmnd; 367380c49563SDouglas Gilbert 367480c49563SDouglas Gilbert if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */ 367580c49563SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 367680c49563SDouglas Gilbert num_blocks = get_unaligned_be16(cmd + 7); 367780c49563SDouglas Gilbert } else { /* SYNCHRONIZE_CACHE(16) */ 367880c49563SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 367980c49563SDouglas Gilbert num_blocks = get_unaligned_be32(cmd + 10); 368080c49563SDouglas Gilbert } 368180c49563SDouglas Gilbert if (lba + num_blocks > sdebug_capacity) { 368280c49563SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 368380c49563SDouglas Gilbert return check_condition_result; 368480c49563SDouglas Gilbert } 36854f2c8bf6SDouglas Gilbert if (!write_since_sync || cmd[1] & 0x2) 36864f2c8bf6SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 36874f2c8bf6SDouglas Gilbert else /* delay if write_since_sync and IMMED clear */ 36884f2c8bf6SDouglas Gilbert write_since_sync = false; 36894f2c8bf6SDouglas Gilbert return res; 369080c49563SDouglas Gilbert } 369180c49563SDouglas Gilbert 3692ed9f3e25SDouglas Gilbert /* 3693ed9f3e25SDouglas Gilbert * Assuming the LBA+num_blocks is not out-of-range, this function will return 3694ed9f3e25SDouglas Gilbert * CONDITION MET if the specified blocks will/have fitted in the cache, and 3695ed9f3e25SDouglas Gilbert * a GOOD status otherwise. Model a disk with a big cache and yield 3696ed9f3e25SDouglas Gilbert * CONDITION MET. Actually tries to bring range in main memory into the 3697ed9f3e25SDouglas Gilbert * cache associated with the CPU(s). 3698ed9f3e25SDouglas Gilbert */ 3699ed9f3e25SDouglas Gilbert static int resp_pre_fetch(struct scsi_cmnd *scp, 3700ed9f3e25SDouglas Gilbert struct sdebug_dev_info *devip) 3701ed9f3e25SDouglas Gilbert { 3702ed9f3e25SDouglas Gilbert int res = 0; 3703ed9f3e25SDouglas Gilbert u64 lba; 3704ed9f3e25SDouglas Gilbert u64 block, rest = 0; 3705ed9f3e25SDouglas Gilbert u32 nblks; 3706ed9f3e25SDouglas Gilbert u8 *cmd = scp->cmnd; 3707ed9f3e25SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 3708ed9f3e25SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 3709ed9f3e25SDouglas Gilbert u8 *fsp = sip ? sip->storep : NULL; 3710ed9f3e25SDouglas Gilbert 3711ed9f3e25SDouglas Gilbert if (cmd[0] == PRE_FETCH) { /* 10 byte cdb */ 3712ed9f3e25SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3713ed9f3e25SDouglas Gilbert nblks = get_unaligned_be16(cmd + 7); 3714ed9f3e25SDouglas Gilbert } else { /* PRE-FETCH(16) */ 3715ed9f3e25SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3716ed9f3e25SDouglas Gilbert nblks = get_unaligned_be32(cmd + 10); 3717ed9f3e25SDouglas Gilbert } 3718ed9f3e25SDouglas Gilbert if (lba + nblks > sdebug_capacity) { 3719ed9f3e25SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 3720ed9f3e25SDouglas Gilbert return check_condition_result; 3721ed9f3e25SDouglas Gilbert } 3722ed9f3e25SDouglas Gilbert if (!fsp) 3723ed9f3e25SDouglas Gilbert goto fini; 3724ed9f3e25SDouglas Gilbert /* PRE-FETCH spec says nothing about LBP or PI so skip them */ 3725ed9f3e25SDouglas Gilbert block = do_div(lba, sdebug_store_sectors); 3726ed9f3e25SDouglas Gilbert if (block + nblks > sdebug_store_sectors) 3727ed9f3e25SDouglas Gilbert rest = block + nblks - sdebug_store_sectors; 3728ed9f3e25SDouglas Gilbert 3729ed9f3e25SDouglas Gilbert /* Try to bring the PRE-FETCH range into CPU's cache */ 3730ed9f3e25SDouglas Gilbert read_lock(macc_lckp); 3731ed9f3e25SDouglas Gilbert prefetch_range(fsp + (sdebug_sector_size * block), 3732ed9f3e25SDouglas Gilbert (nblks - rest) * sdebug_sector_size); 3733ed9f3e25SDouglas Gilbert if (rest) 3734ed9f3e25SDouglas Gilbert prefetch_range(fsp, rest * sdebug_sector_size); 3735ed9f3e25SDouglas Gilbert read_unlock(macc_lckp); 3736ed9f3e25SDouglas Gilbert fini: 3737ed9f3e25SDouglas Gilbert if (cmd[1] & 0x2) 3738ed9f3e25SDouglas Gilbert res = SDEG_RES_IMMED_MASK; 3739ed9f3e25SDouglas Gilbert return res | condition_met_result; 3740ed9f3e25SDouglas Gilbert } 3741ed9f3e25SDouglas Gilbert 3742fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 3743fb0cc8d1SDouglas Gilbert 37448d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 37458d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 37468d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 37478d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 37488d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 37498d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 37508d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 37518d039e22SDouglas Gilbert */ 37521da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 37531da177e4SLinus Torvalds struct sdebug_dev_info *devip) 37541da177e4SLinus Torvalds { 375501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 37568d039e22SDouglas Gilbert unsigned int alloc_len; 37578d039e22SDouglas Gilbert unsigned char select_report; 37588d039e22SDouglas Gilbert u64 lun; 37598d039e22SDouglas Gilbert struct scsi_lun *lun_p; 3760fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 37618d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 37628d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 37638d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 37648d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 3765fb0cc8d1SDouglas Gilbert int k, j, n, res; 3766fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 3767fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 37681da177e4SLinus Torvalds 376919c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 37708d039e22SDouglas Gilbert 37718d039e22SDouglas Gilbert select_report = cmd[2]; 37728d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 37738d039e22SDouglas Gilbert 37748d039e22SDouglas Gilbert if (alloc_len < 4) { 37758d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 37768d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 37771da177e4SLinus Torvalds return check_condition_result; 37781da177e4SLinus Torvalds } 37798d039e22SDouglas Gilbert 37808d039e22SDouglas Gilbert switch (select_report) { 37818d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 3782773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 37838d039e22SDouglas Gilbert wlun_cnt = 0; 37848d039e22SDouglas Gilbert break; 37858d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 3786c65b1445SDouglas Gilbert lun_cnt = 0; 37878d039e22SDouglas Gilbert wlun_cnt = 1; 37888d039e22SDouglas Gilbert break; 37898d039e22SDouglas Gilbert case 2: /* all LUNs */ 37908d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 37918d039e22SDouglas Gilbert wlun_cnt = 1; 37928d039e22SDouglas Gilbert break; 37938d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 37948d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 37958d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 37968d039e22SDouglas Gilbert default: 37978d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 37988d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 37998d039e22SDouglas Gilbert return check_condition_result; 38008d039e22SDouglas Gilbert } 38018d039e22SDouglas Gilbert 38028d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 3803c65b1445SDouglas Gilbert --lun_cnt; 38048d039e22SDouglas Gilbert 38058d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 3806fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 3807fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 38088d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 38098d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 38108d039e22SDouglas Gilbert 3811fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 38128d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 3813fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 3814fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 3815fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 3816fb0cc8d1SDouglas Gilbert if (k == 0) { 3817fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 3818fb0cc8d1SDouglas Gilbert ++lun_p; 3819fb0cc8d1SDouglas Gilbert j = 1; 3820fb0cc8d1SDouglas Gilbert } 3821fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 3822fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 3823fb0cc8d1SDouglas Gilbert break; 3824fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 3825fb0cc8d1SDouglas Gilbert } 3826fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 3827fb0cc8d1SDouglas Gilbert break; 3828fb0cc8d1SDouglas Gilbert n = j * sz_lun; 3829fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 3830fb0cc8d1SDouglas Gilbert if (res) 3831fb0cc8d1SDouglas Gilbert return res; 3832fb0cc8d1SDouglas Gilbert off_rsp += n; 3833fb0cc8d1SDouglas Gilbert } 3834fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 3835fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 3836fb0cc8d1SDouglas Gilbert ++j; 3837fb0cc8d1SDouglas Gilbert } 3838fb0cc8d1SDouglas Gilbert if (j > 0) 3839fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 38408d039e22SDouglas Gilbert return res; 38411da177e4SLinus Torvalds } 38421da177e4SLinus Torvalds 3843c3e2fe92SDouglas Gilbert static int resp_verify(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 3844c3e2fe92SDouglas Gilbert { 3845c3e2fe92SDouglas Gilbert bool is_bytchk3 = false; 3846c3e2fe92SDouglas Gilbert u8 bytchk; 3847c3e2fe92SDouglas Gilbert int ret, j; 3848c3e2fe92SDouglas Gilbert u32 vnum, a_num, off; 3849c3e2fe92SDouglas Gilbert const u32 lb_size = sdebug_sector_size; 3850c3e2fe92SDouglas Gilbert u64 lba; 3851c3e2fe92SDouglas Gilbert u8 *arr; 3852c3e2fe92SDouglas Gilbert u8 *cmd = scp->cmnd; 3853c3e2fe92SDouglas Gilbert struct sdeb_store_info *sip = devip2sip(devip); 3854c3e2fe92SDouglas Gilbert rwlock_t *macc_lckp = sip ? &sip->macc_lck : &sdeb_fake_rw_lck; 3855c3e2fe92SDouglas Gilbert 3856c3e2fe92SDouglas Gilbert bytchk = (cmd[1] >> 1) & 0x3; 3857c3e2fe92SDouglas Gilbert if (bytchk == 0) { 3858c3e2fe92SDouglas Gilbert return 0; /* always claim internal verify okay */ 3859c3e2fe92SDouglas Gilbert } else if (bytchk == 2) { 3860c3e2fe92SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 3861c3e2fe92SDouglas Gilbert return check_condition_result; 3862c3e2fe92SDouglas Gilbert } else if (bytchk == 3) { 3863c3e2fe92SDouglas Gilbert is_bytchk3 = true; /* 1 block sent, compared repeatedly */ 3864c3e2fe92SDouglas Gilbert } 3865c3e2fe92SDouglas Gilbert switch (cmd[0]) { 3866c3e2fe92SDouglas Gilbert case VERIFY_16: 3867c3e2fe92SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3868c3e2fe92SDouglas Gilbert vnum = get_unaligned_be32(cmd + 10); 3869c3e2fe92SDouglas Gilbert break; 3870c3e2fe92SDouglas Gilbert case VERIFY: /* is VERIFY(10) */ 3871c3e2fe92SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3872c3e2fe92SDouglas Gilbert vnum = get_unaligned_be16(cmd + 7); 3873c3e2fe92SDouglas Gilbert break; 3874c3e2fe92SDouglas Gilbert default: 3875c3e2fe92SDouglas Gilbert mk_sense_invalid_opcode(scp); 3876c3e2fe92SDouglas Gilbert return check_condition_result; 3877c3e2fe92SDouglas Gilbert } 3878c3e2fe92SDouglas Gilbert a_num = is_bytchk3 ? 1 : vnum; 3879c3e2fe92SDouglas Gilbert /* Treat following check like one for read (i.e. no write) access */ 3880c3e2fe92SDouglas Gilbert ret = check_device_access_params(scp, lba, a_num, false); 3881c3e2fe92SDouglas Gilbert if (ret) 3882c3e2fe92SDouglas Gilbert return ret; 3883c3e2fe92SDouglas Gilbert 3884c3e2fe92SDouglas Gilbert arr = kcalloc(lb_size, vnum, GFP_ATOMIC); 3885c3e2fe92SDouglas Gilbert if (!arr) { 3886c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3887c3e2fe92SDouglas Gilbert INSUFF_RES_ASCQ); 3888c3e2fe92SDouglas Gilbert return check_condition_result; 3889c3e2fe92SDouglas Gilbert } 3890c3e2fe92SDouglas Gilbert /* Not changing store, so only need read access */ 389167da413fSDouglas Gilbert read_lock(macc_lckp); 3892c3e2fe92SDouglas Gilbert 3893c3e2fe92SDouglas Gilbert ret = do_dout_fetch(scp, a_num, arr); 3894c3e2fe92SDouglas Gilbert if (ret == -1) { 3895c3e2fe92SDouglas Gilbert ret = DID_ERROR << 16; 3896c3e2fe92SDouglas Gilbert goto cleanup; 3897c3e2fe92SDouglas Gilbert } else if (sdebug_verbose && (ret < (a_num * lb_size))) { 3898c3e2fe92SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3899c3e2fe92SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 3900c3e2fe92SDouglas Gilbert my_name, __func__, a_num * lb_size, ret); 3901c3e2fe92SDouglas Gilbert } 3902c3e2fe92SDouglas Gilbert if (is_bytchk3) { 3903c3e2fe92SDouglas Gilbert for (j = 1, off = lb_size; j < vnum; ++j, off += lb_size) 3904c3e2fe92SDouglas Gilbert memcpy(arr + off, arr, lb_size); 3905c3e2fe92SDouglas Gilbert } 3906c3e2fe92SDouglas Gilbert ret = 0; 3907c3e2fe92SDouglas Gilbert if (!comp_write_worker(sip, lba, vnum, arr, true)) { 3908c3e2fe92SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3909c3e2fe92SDouglas Gilbert ret = check_condition_result; 3910c3e2fe92SDouglas Gilbert goto cleanup; 3911c3e2fe92SDouglas Gilbert } 3912c3e2fe92SDouglas Gilbert cleanup: 391367da413fSDouglas Gilbert read_unlock(macc_lckp); 3914c3e2fe92SDouglas Gilbert kfree(arr); 3915c3e2fe92SDouglas Gilbert return ret; 3916c3e2fe92SDouglas Gilbert } 3917c3e2fe92SDouglas Gilbert 3918c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 3919c4837394SDouglas Gilbert { 3920c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 3921c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 3922c4837394SDouglas Gilbert 3923458df78bSBart Van Assche pr_debug("tag=%#x, hwq=%d\n", tag, hwq); 3924458df78bSBart Van Assche if (WARN_ON_ONCE(hwq >= submit_queues)) 3925458df78bSBart Van Assche hwq = 0; 3926458df78bSBart Van Assche return sdebug_q_arr + hwq; 3927c4837394SDouglas Gilbert } 3928c4837394SDouglas Gilbert 3929c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 3930fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 39311da177e4SLinus Torvalds { 39327382f9d8SDouglas Gilbert bool aborted = sd_dp->aborted; 3933c4837394SDouglas Gilbert int qc_idx; 3934cbf67842SDouglas Gilbert int retiring = 0; 39351da177e4SLinus Torvalds unsigned long iflags; 3936c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3937cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3938cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3939cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 39401da177e4SLinus Torvalds 394110bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 39427382f9d8SDouglas Gilbert if (unlikely(aborted)) 39437382f9d8SDouglas Gilbert sd_dp->aborted = false; 3944c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 3945c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 3946c4837394SDouglas Gilbert if (sdebug_statistics) { 3947cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3948c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 3949c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 3950c4837394SDouglas Gilbert } 3951c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 3952c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 39531da177e4SLinus Torvalds return; 39541da177e4SLinus Torvalds } 3955c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3956c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 3957cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3958b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 3959c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3960c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 3961c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 39621da177e4SLinus Torvalds return; 39631da177e4SLinus Torvalds } 3964cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3965f46eb0e9SDouglas Gilbert if (likely(devip)) 3966cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3967cbf67842SDouglas Gilbert else 3968c1287970STomas Winkler pr_err("devip=NULL\n"); 3969f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3970cbf67842SDouglas Gilbert retiring = 1; 3971cbf67842SDouglas Gilbert 3972cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3973c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 3974c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3975c1287970STomas Winkler pr_err("Unexpected completion\n"); 3976cbf67842SDouglas Gilbert return; 39771da177e4SLinus Torvalds } 39781da177e4SLinus Torvalds 3979cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3980cbf67842SDouglas Gilbert int k, retval; 3981cbf67842SDouglas Gilbert 3982cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3983c4837394SDouglas Gilbert if (qc_idx >= retval) { 3984c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3985c1287970STomas Winkler pr_err("index %d too large\n", retval); 3986cbf67842SDouglas Gilbert return; 3987cbf67842SDouglas Gilbert } 3988c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 3989773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3990cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3991cbf67842SDouglas Gilbert else 3992cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3993cbf67842SDouglas Gilbert } 3994c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 39957382f9d8SDouglas Gilbert if (unlikely(aborted)) { 39967382f9d8SDouglas Gilbert if (sdebug_verbose) 39977382f9d8SDouglas Gilbert pr_info("bypassing scsi_done() due to aborted cmd\n"); 39987382f9d8SDouglas Gilbert return; 39997382f9d8SDouglas Gilbert } 4000cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 4001cbf67842SDouglas Gilbert } 4002cbf67842SDouglas Gilbert 4003cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 4004fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 4005cbf67842SDouglas Gilbert { 4006a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 4007a10bc12aSDouglas Gilbert hrt); 4008a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4009cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 4010cbf67842SDouglas Gilbert } 40111da177e4SLinus Torvalds 4012a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 4013fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 4014a10bc12aSDouglas Gilbert { 4015a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 4016a10bc12aSDouglas Gilbert ew.work); 4017a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 4018a10bc12aSDouglas Gilbert } 4019a10bc12aSDouglas Gilbert 402009ba24c1SDouglas Gilbert static bool got_shared_uuid; 4021bf476433SChristoph Hellwig static uuid_t shared_uuid; 402209ba24c1SDouglas Gilbert 4023fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 4024fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 40255cb2fc06SFUJITA Tomonori { 40265cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 40275cb2fc06SFUJITA Tomonori 40285cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 40295cb2fc06SFUJITA Tomonori if (devip) { 403009ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 4031bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 403209ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 403309ba24c1SDouglas Gilbert if (got_shared_uuid) 403409ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 403509ba24c1SDouglas Gilbert else { 4036bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 403709ba24c1SDouglas Gilbert got_shared_uuid = true; 403809ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 403909ba24c1SDouglas Gilbert } 404009ba24c1SDouglas Gilbert } 40415cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 40425cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 40435cb2fc06SFUJITA Tomonori } 40445cb2fc06SFUJITA Tomonori return devip; 40455cb2fc06SFUJITA Tomonori } 40465cb2fc06SFUJITA Tomonori 4047f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 40481da177e4SLinus Torvalds { 40491da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 40501da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 4051f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 40521da177e4SLinus Torvalds 4053d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 40541da177e4SLinus Torvalds if (!sdbg_host) { 4055c1287970STomas Winkler pr_err("Host info NULL\n"); 40561da177e4SLinus Torvalds return NULL; 40571da177e4SLinus Torvalds } 40581da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 40591da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 40601da177e4SLinus Torvalds (devip->target == sdev->id) && 40611da177e4SLinus Torvalds (devip->lun == sdev->lun)) 40621da177e4SLinus Torvalds return devip; 40631da177e4SLinus Torvalds else { 40641da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 40651da177e4SLinus Torvalds open_devip = devip; 40661da177e4SLinus Torvalds } 40671da177e4SLinus Torvalds } 40685cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 40695cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 40705cb2fc06SFUJITA Tomonori if (!open_devip) { 4071c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 40721da177e4SLinus Torvalds return NULL; 40731da177e4SLinus Torvalds } 40741da177e4SLinus Torvalds } 4075a75869d1SFUJITA Tomonori 40761da177e4SLinus Torvalds open_devip->channel = sdev->channel; 40771da177e4SLinus Torvalds open_devip->target = sdev->id; 40781da177e4SLinus Torvalds open_devip->lun = sdev->lun; 40791da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 4080cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 4081cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 4082c2248fc9SDouglas Gilbert open_devip->used = true; 40831da177e4SLinus Torvalds return open_devip; 40841da177e4SLinus Torvalds } 40851da177e4SLinus Torvalds 40868dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 40871da177e4SLinus Torvalds { 4088773642d9SDouglas Gilbert if (sdebug_verbose) 4089c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 40908dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 40918dea0d02SFUJITA Tomonori return 0; 40928dea0d02SFUJITA Tomonori } 40931da177e4SLinus Torvalds 40948dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 40958dea0d02SFUJITA Tomonori { 4096f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 4097f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 4098a34c4e98SFUJITA Tomonori 4099773642d9SDouglas Gilbert if (sdebug_verbose) 4100c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 41018dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 4102b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 4103b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 4104b01f6f83SDouglas Gilbert if (devip == NULL) { 4105f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 4106b01f6f83SDouglas Gilbert if (devip == NULL) 41078dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 4108f46eb0e9SDouglas Gilbert } 4109c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 4110773642d9SDouglas Gilbert if (sdebug_no_uld) 411178d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 41129b760fd8SDouglas Gilbert config_cdb_len(sdp); 41138dea0d02SFUJITA Tomonori return 0; 41148dea0d02SFUJITA Tomonori } 41158dea0d02SFUJITA Tomonori 41168dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 41178dea0d02SFUJITA Tomonori { 41188dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 41198dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 41208dea0d02SFUJITA Tomonori 4121773642d9SDouglas Gilbert if (sdebug_verbose) 4122c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 41238dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 41248dea0d02SFUJITA Tomonori if (devip) { 412525985edcSLucas De Marchi /* make this slot available for re-use */ 4126c2248fc9SDouglas Gilbert devip->used = false; 41278dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 41288dea0d02SFUJITA Tomonori } 41298dea0d02SFUJITA Tomonori } 41308dea0d02SFUJITA Tomonori 413110bde980SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp, 413210bde980SDouglas Gilbert enum sdeb_defer_type defer_t) 4133c4837394SDouglas Gilbert { 4134c4837394SDouglas Gilbert if (!sd_dp) 4135c4837394SDouglas Gilbert return; 413610bde980SDouglas Gilbert if (defer_t == SDEB_DEFER_HRT) 4137c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 413810bde980SDouglas Gilbert else if (defer_t == SDEB_DEFER_WQ) 4139c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 4140c4837394SDouglas Gilbert } 4141c4837394SDouglas Gilbert 4142a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 4143a10bc12aSDouglas Gilbert returns false */ 4144a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 41458dea0d02SFUJITA Tomonori { 41468dea0d02SFUJITA Tomonori unsigned long iflags; 4147c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 414810bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 4149c4837394SDouglas Gilbert struct sdebug_queue *sqp; 41508dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 4151cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4152a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 41538dea0d02SFUJITA Tomonori 4154c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4155c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4156773642d9SDouglas Gilbert qmax = sdebug_max_queue; 4157cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 4158cbf67842SDouglas Gilbert if (r_qmax > qmax) 4159cbf67842SDouglas Gilbert qmax = r_qmax; 4160cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 4161c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 4162c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 4163a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 4164a10bc12aSDouglas Gilbert continue; 4165c4837394SDouglas Gilbert /* found */ 4166db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 4167db525fceSDouglas Gilbert cmnd->device->hostdata; 4168db525fceSDouglas Gilbert if (devip) 4169db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 4170db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 4171a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 417210bde980SDouglas Gilbert if (sd_dp) { 417310bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 417410bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 417510bde980SDouglas Gilbert } else 417610bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 4177c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 417810bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 4179c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 4180a10bc12aSDouglas Gilbert return true; 41818dea0d02SFUJITA Tomonori } 4182cbf67842SDouglas Gilbert } 4183c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4184c4837394SDouglas Gilbert } 4185a10bc12aSDouglas Gilbert return false; 41868dea0d02SFUJITA Tomonori } 41878dea0d02SFUJITA Tomonori 4188a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 41898dea0d02SFUJITA Tomonori static void stop_all_queued(void) 41908dea0d02SFUJITA Tomonori { 41918dea0d02SFUJITA Tomonori unsigned long iflags; 4192c4837394SDouglas Gilbert int j, k; 419310bde980SDouglas Gilbert enum sdeb_defer_type l_defer_t; 4194c4837394SDouglas Gilbert struct sdebug_queue *sqp; 41958dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 4196cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4197a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 41988dea0d02SFUJITA Tomonori 4199c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4200c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4201c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 4202c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 4203c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 4204c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 4205a10bc12aSDouglas Gilbert continue; 4206db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 4207db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 4208db525fceSDouglas Gilbert if (devip) 4209db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 4210db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 4211a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 421210bde980SDouglas Gilbert if (sd_dp) { 421310bde980SDouglas Gilbert l_defer_t = sd_dp->defer_t; 421410bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_NONE; 421510bde980SDouglas Gilbert } else 421610bde980SDouglas Gilbert l_defer_t = SDEB_DEFER_NONE; 4217c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 421810bde980SDouglas Gilbert stop_qc_helper(sd_dp, l_defer_t); 4219c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 4220c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 42218dea0d02SFUJITA Tomonori } 42228dea0d02SFUJITA Tomonori } 4223c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4224c4837394SDouglas Gilbert } 4225cbf67842SDouglas Gilbert } 4226cbf67842SDouglas Gilbert 4227cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 4228cbf67842SDouglas Gilbert static void free_all_queued(void) 4229cbf67842SDouglas Gilbert { 4230c4837394SDouglas Gilbert int j, k; 4231c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4232cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4233cbf67842SDouglas Gilbert 4234c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4235c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 4236c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 4237a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 4238a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 4239cbf67842SDouglas Gilbert } 42401da177e4SLinus Torvalds } 4241c4837394SDouglas Gilbert } 42421da177e4SLinus Torvalds 42431da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 42441da177e4SLinus Torvalds { 4245a10bc12aSDouglas Gilbert bool ok; 4246a10bc12aSDouglas Gilbert 42471da177e4SLinus Torvalds ++num_aborts; 4248cbf67842SDouglas Gilbert if (SCpnt) { 4249a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 4250a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 4251a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 4252a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 4253a10bc12aSDouglas Gilbert ok ? "" : " not"); 4254cbf67842SDouglas Gilbert } 42551da177e4SLinus Torvalds return SUCCESS; 42561da177e4SLinus Torvalds } 42571da177e4SLinus Torvalds 42581da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt) 42591da177e4SLinus Torvalds { 42601da177e4SLinus Torvalds ++num_dev_resets; 4261cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 4262cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 4263f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 4264f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 4265cbf67842SDouglas Gilbert 4266773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 4267cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 42681da177e4SLinus Torvalds if (devip) 4269cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 42701da177e4SLinus Torvalds } 42711da177e4SLinus Torvalds return SUCCESS; 42721da177e4SLinus Torvalds } 42731da177e4SLinus Torvalds 4274cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 4275cbf67842SDouglas Gilbert { 4276cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 4277cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4278cbf67842SDouglas Gilbert struct scsi_device *sdp; 4279cbf67842SDouglas Gilbert struct Scsi_Host *hp; 4280cbf67842SDouglas Gilbert int k = 0; 4281cbf67842SDouglas Gilbert 4282cbf67842SDouglas Gilbert ++num_target_resets; 4283cbf67842SDouglas Gilbert if (!SCpnt) 4284cbf67842SDouglas Gilbert goto lie; 4285cbf67842SDouglas Gilbert sdp = SCpnt->device; 4286cbf67842SDouglas Gilbert if (!sdp) 4287cbf67842SDouglas Gilbert goto lie; 4288773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 4289cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 4290cbf67842SDouglas Gilbert hp = sdp->host; 4291cbf67842SDouglas Gilbert if (!hp) 4292cbf67842SDouglas Gilbert goto lie; 4293cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 4294cbf67842SDouglas Gilbert if (sdbg_host) { 4295cbf67842SDouglas Gilbert list_for_each_entry(devip, 4296cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 4297cbf67842SDouglas Gilbert dev_list) 4298cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 4299cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4300cbf67842SDouglas Gilbert ++k; 4301cbf67842SDouglas Gilbert } 4302cbf67842SDouglas Gilbert } 4303773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 4304cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4305cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 4306cbf67842SDouglas Gilbert lie: 4307cbf67842SDouglas Gilbert return SUCCESS; 4308cbf67842SDouglas Gilbert } 4309cbf67842SDouglas Gilbert 43101da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt) 43111da177e4SLinus Torvalds { 43121da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 4313cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 43141da177e4SLinus Torvalds struct scsi_device *sdp; 43151da177e4SLinus Torvalds struct Scsi_Host *hp; 4316cbf67842SDouglas Gilbert int k = 0; 43171da177e4SLinus Torvalds 43181da177e4SLinus Torvalds ++num_bus_resets; 4319cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 4320cbf67842SDouglas Gilbert goto lie; 4321cbf67842SDouglas Gilbert sdp = SCpnt->device; 4322773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 4323cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 4324cbf67842SDouglas Gilbert hp = sdp->host; 4325cbf67842SDouglas Gilbert if (hp) { 4326d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 43271da177e4SLinus Torvalds if (sdbg_host) { 4328cbf67842SDouglas Gilbert list_for_each_entry(devip, 43291da177e4SLinus Torvalds &sdbg_host->dev_info_list, 4330cbf67842SDouglas Gilbert dev_list) { 4331cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4332cbf67842SDouglas Gilbert ++k; 43331da177e4SLinus Torvalds } 43341da177e4SLinus Torvalds } 4335cbf67842SDouglas Gilbert } 4336773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 4337cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4338cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 4339cbf67842SDouglas Gilbert lie: 43401da177e4SLinus Torvalds return SUCCESS; 43411da177e4SLinus Torvalds } 43421da177e4SLinus Torvalds 43431da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt) 43441da177e4SLinus Torvalds { 43451da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 4346cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4347cbf67842SDouglas Gilbert int k = 0; 43481da177e4SLinus Torvalds 43491da177e4SLinus Torvalds ++num_host_resets; 4350773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 4351cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 43521da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 43531da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 4354cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 4355cbf67842SDouglas Gilbert dev_list) { 4356cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 4357cbf67842SDouglas Gilbert ++k; 4358cbf67842SDouglas Gilbert } 43591da177e4SLinus Torvalds } 43601da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 43611da177e4SLinus Torvalds stop_all_queued(); 4362773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 4363cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 4364cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 43651da177e4SLinus Torvalds return SUCCESS; 43661da177e4SLinus Torvalds } 43671da177e4SLinus Torvalds 436887c715dcSDouglas Gilbert static void sdebug_build_parts(unsigned char *ramp, unsigned long store_size) 43691da177e4SLinus Torvalds { 43701442f76dSChristoph Hellwig struct msdos_partition *pp; 43711da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 43721da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 43731da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 43741da177e4SLinus Torvalds 43751da177e4SLinus Torvalds /* assume partition table already zeroed */ 4376773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 43771da177e4SLinus Torvalds return; 4378773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 4379773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 4380c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 43811da177e4SLinus Torvalds } 4382c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 43831da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 4384773642d9SDouglas Gilbert / sdebug_num_parts; 43851da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 43861da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 4387773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 43881da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 43891da177e4SLinus Torvalds * heads_by_sects; 4390773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 4391773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 43921da177e4SLinus Torvalds 43931da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 43941da177e4SLinus Torvalds ramp[511] = 0xAA; 43951442f76dSChristoph Hellwig pp = (struct msdos_partition *)(ramp + 0x1be); 43961da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 43971da177e4SLinus Torvalds start_sec = starts[k]; 43981da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 43991da177e4SLinus Torvalds pp->boot_ind = 0; 44001da177e4SLinus Torvalds 44011da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 44021da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 44031da177e4SLinus Torvalds / sdebug_sectors_per; 44041da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 44051da177e4SLinus Torvalds 44061da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 44071da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 44081da177e4SLinus Torvalds / sdebug_sectors_per; 44091da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 44101da177e4SLinus Torvalds 4411150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 4412150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 44131da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 44141da177e4SLinus Torvalds } 44151da177e4SLinus Torvalds } 44161da177e4SLinus Torvalds 4417c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 4418c4837394SDouglas Gilbert { 4419c4837394SDouglas Gilbert int j; 4420c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4421c4837394SDouglas Gilbert 4422c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 4423c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 4424c4837394SDouglas Gilbert } 4425c4837394SDouglas Gilbert 4426c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 4427c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 4428c4837394SDouglas Gilbert */ 4429c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 4430c4837394SDouglas Gilbert { 4431c4837394SDouglas Gilbert int count, modulo; 4432c4837394SDouglas Gilbert 4433c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 4434c4837394SDouglas Gilbert if (modulo < 2) 4435c4837394SDouglas Gilbert return; 4436c4837394SDouglas Gilbert block_unblock_all_queues(true); 4437c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 4438c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 4439c4837394SDouglas Gilbert block_unblock_all_queues(false); 4440c4837394SDouglas Gilbert } 4441c4837394SDouglas Gilbert 4442c4837394SDouglas Gilbert static void clear_queue_stats(void) 4443c4837394SDouglas Gilbert { 4444c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4445c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 4446c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 4447c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4448c4837394SDouglas Gilbert } 4449c4837394SDouglas Gilbert 4450c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 4451c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 4452c4837394SDouglas Gilbert { 4453f9ba7af8SMartin Wilck if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) { 4454f9ba7af8SMartin Wilck if (sdebug_every_nth > 0) 4455f9ba7af8SMartin Wilck sqcp->inj_recovered = sqcp->inj_transport 4456f9ba7af8SMartin Wilck = sqcp->inj_dif 44577382f9d8SDouglas Gilbert = sqcp->inj_dix = sqcp->inj_short 44587382f9d8SDouglas Gilbert = sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0; 4459c4837394SDouglas Gilbert return; 4460f9ba7af8SMartin Wilck } 4461c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 4462c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 4463c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 4464c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 4465c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 44667ee6d1b4SBart Van Assche sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts); 44677382f9d8SDouglas Gilbert sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts); 4468c4837394SDouglas Gilbert } 4469c4837394SDouglas Gilbert 4470a2aede97SDouglas Gilbert #define INCLUSIVE_TIMING_MAX_NS 1000000 /* 1 millisecond */ 4471a2aede97SDouglas Gilbert 4472c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 4473c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 4474c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 4475c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 4476c4837394SDouglas Gilbert */ 4477fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 4478f66b8517SMartin Wilck int scsi_result, 4479f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, 4480f66b8517SMartin Wilck struct sdebug_dev_info *), 4481f66b8517SMartin Wilck int delta_jiff, int ndelay) 44821da177e4SLinus Torvalds { 4483a2aede97SDouglas Gilbert bool new_sd_dp; 4484cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 4485a2aede97SDouglas Gilbert unsigned long iflags; 4486a2aede97SDouglas Gilbert u64 ns_from_boot = 0; 4487c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4488c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4489299b6c07STomas Winkler struct scsi_device *sdp; 4490a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 44911da177e4SLinus Torvalds 4492b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 4493b01f6f83SDouglas Gilbert if (scsi_result == 0) 4494f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 4495f46eb0e9SDouglas Gilbert goto respond_in_thread; 44961da177e4SLinus Torvalds } 4497299b6c07STomas Winkler sdp = cmnd->device; 4498299b6c07STomas Winkler 4499cd62b7daSDouglas Gilbert if (delta_jiff == 0) 4500cd62b7daSDouglas Gilbert goto respond_in_thread; 45011da177e4SLinus Torvalds 4502c4837394SDouglas Gilbert sqp = get_queue(cmnd); 4503c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4504c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 4505c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4506c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4507c4837394SDouglas Gilbert } 4508cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 4509cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 4510cbf67842SDouglas Gilbert inject = 0; 4511f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 4512cd62b7daSDouglas Gilbert if (scsi_result) { 4513c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4514cd62b7daSDouglas Gilbert goto respond_in_thread; 4515cd62b7daSDouglas Gilbert } else 4516cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4517c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 4518773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 4519f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 4520cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 4521cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 4522773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 4523cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4524cbf67842SDouglas Gilbert inject = 1; 4525cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 45261da177e4SLinus Torvalds } 4527cbf67842SDouglas Gilbert } 4528cbf67842SDouglas Gilbert 4529c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 4530f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 4531c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4532cd62b7daSDouglas Gilbert if (scsi_result) 4533cd62b7daSDouglas Gilbert goto respond_in_thread; 4534773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 4535cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4536773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 4537cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4538cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 4539773642d9SDouglas Gilbert __func__, sdebug_max_queue, 4540cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 4541cbf67842SDouglas Gilbert "report: host busy")); 4542cd62b7daSDouglas Gilbert if (scsi_result) 4543cd62b7daSDouglas Gilbert goto respond_in_thread; 4544cd62b7daSDouglas Gilbert else 4545cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 45461da177e4SLinus Torvalds } 4547c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 4548cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4549c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 45501da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4551c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 4552a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 4553c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4554c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 4555c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 455610bde980SDouglas Gilbert if (sd_dp == NULL) { 455710bde980SDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 455810bde980SDouglas Gilbert if (sd_dp == NULL) 455910bde980SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4560a2aede97SDouglas Gilbert new_sd_dp = true; 4561a2aede97SDouglas Gilbert } else { 4562a2aede97SDouglas Gilbert new_sd_dp = false; 456310bde980SDouglas Gilbert } 4564f66b8517SMartin Wilck 4565a2aede97SDouglas Gilbert if (ndelay > 0 && ndelay < INCLUSIVE_TIMING_MAX_NS) 4566a2aede97SDouglas Gilbert ns_from_boot = ktime_get_boottime_ns(); 4567a2aede97SDouglas Gilbert 4568a2aede97SDouglas Gilbert /* one of the resp_*() response functions is called here */ 4569f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 4570f66b8517SMartin Wilck if (cmnd->result & SDEG_RES_IMMED_MASK) { 4571f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 4572f66b8517SMartin Wilck delta_jiff = ndelay = 0; 4573f66b8517SMartin Wilck } 4574f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 4575f66b8517SMartin Wilck cmnd->result = scsi_result; 4576f66b8517SMartin Wilck 4577f66b8517SMartin Wilck if (unlikely(sdebug_verbose && cmnd->result)) 4578f66b8517SMartin Wilck sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 4579f66b8517SMartin Wilck __func__, cmnd->result); 4580f66b8517SMartin Wilck 458110bde980SDouglas Gilbert if (delta_jiff > 0 || ndelay > 0) { 4582b333a819SDouglas Gilbert ktime_t kt; 4583cbf67842SDouglas Gilbert 4584b333a819SDouglas Gilbert if (delta_jiff > 0) { 45850c4bc91dSDouglas Gilbert u64 ns = jiffies_to_nsecs(delta_jiff); 45860c4bc91dSDouglas Gilbert 45870c4bc91dSDouglas Gilbert if (sdebug_random && ns < U32_MAX) { 45880c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 45890c4bc91dSDouglas Gilbert } else if (sdebug_random) { 45900c4bc91dSDouglas Gilbert ns >>= 12; /* scale to 4 usec precision */ 45910c4bc91dSDouglas Gilbert if (ns < U32_MAX) /* over 4 hours max */ 45920c4bc91dSDouglas Gilbert ns = prandom_u32_max((u32)ns); 45930c4bc91dSDouglas Gilbert ns <<= 12; 45940c4bc91dSDouglas Gilbert } 45950c4bc91dSDouglas Gilbert kt = ns_to_ktime(ns); 45960c4bc91dSDouglas Gilbert } else { /* ndelay has a 4.2 second max */ 45970c4bc91dSDouglas Gilbert kt = sdebug_random ? prandom_u32_max((u32)ndelay) : 45980c4bc91dSDouglas Gilbert (u32)ndelay; 4599a2aede97SDouglas Gilbert if (ndelay < INCLUSIVE_TIMING_MAX_NS) { 4600a2aede97SDouglas Gilbert u64 d = ktime_get_boottime_ns() - ns_from_boot; 4601a2aede97SDouglas Gilbert 4602a2aede97SDouglas Gilbert if (kt <= d) { /* elapsed duration >= kt */ 4603a2aede97SDouglas Gilbert sqcp->a_cmnd = NULL; 4604a2aede97SDouglas Gilbert atomic_dec(&devip->num_in_q); 4605a2aede97SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 4606a2aede97SDouglas Gilbert if (new_sd_dp) 4607a2aede97SDouglas Gilbert kfree(sd_dp); 4608a2aede97SDouglas Gilbert /* call scsi_done() from this thread */ 4609a2aede97SDouglas Gilbert cmnd->scsi_done(cmnd); 4610a2aede97SDouglas Gilbert return 0; 4611a2aede97SDouglas Gilbert } 4612a2aede97SDouglas Gilbert /* otherwise reduce kt by elapsed time */ 4613a2aede97SDouglas Gilbert kt -= d; 4614a2aede97SDouglas Gilbert } 46150c4bc91dSDouglas Gilbert } 461610bde980SDouglas Gilbert if (!sd_dp->init_hrt) { 461710bde980SDouglas Gilbert sd_dp->init_hrt = true; 4618a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4619a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 4620c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 4621a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 4622c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4623c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4624cbf67842SDouglas Gilbert } 4625c4837394SDouglas Gilbert if (sdebug_statistics) 4626c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 462710bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_HRT; 4628a2aede97SDouglas Gilbert /* schedule the invocation of scsi_done() for a later time */ 4629c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 4630c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 463110bde980SDouglas Gilbert if (!sd_dp->init_wq) { 463210bde980SDouglas Gilbert sd_dp->init_wq = true; 4633a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4634c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4635c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4636a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 4637cbf67842SDouglas Gilbert } 4638c4837394SDouglas Gilbert if (sdebug_statistics) 4639c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 464010bde980SDouglas Gilbert sd_dp->defer_t = SDEB_DEFER_WQ; 46417382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) 46427382f9d8SDouglas Gilbert sd_dp->aborted = true; 4643a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 46447382f9d8SDouglas Gilbert if (unlikely(sqcp->inj_cmd_abort)) { 46457382f9d8SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "abort request tag %d\n", 46467382f9d8SDouglas Gilbert cmnd->request->tag); 46477382f9d8SDouglas Gilbert blk_abort_request(cmnd->request); 46487382f9d8SDouglas Gilbert } 4649cbf67842SDouglas Gilbert } 4650f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 4651f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 4652cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4653cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4654cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4655cbf67842SDouglas Gilbert "status: TASK SET FULL"); 46561da177e4SLinus Torvalds return 0; 4657cd62b7daSDouglas Gilbert 4658cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4659f66b8517SMartin Wilck cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0; 4660f66b8517SMartin Wilck cmnd->result &= ~SDEG_RES_IMMED_MASK; 4661f66b8517SMartin Wilck if (cmnd->result == 0 && scsi_result != 0) 4662cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4663cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4664cd62b7daSDouglas Gilbert return 0; 46651da177e4SLinus Torvalds } 4666cbf67842SDouglas Gilbert 466723183910SDouglas Gilbert /* Note: The following macros create attribute files in the 466823183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 466923183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 467023183910SDouglas Gilbert as it can when the corresponding attribute in the 467123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 467223183910SDouglas Gilbert */ 4673773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 4674773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 46759b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 4676773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 4677c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 4678773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 4679773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 4680773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 4681773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 4682773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 4683773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 4684773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 4685773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 4686e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 4687e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO | S_IWUSR); 4688e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 4689e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO | S_IWUSR); 46905d807076SDouglas Gilbert module_param_string(inq_vendor, sdebug_inq_vendor_id, 46915d807076SDouglas Gilbert sizeof(sdebug_inq_vendor_id), S_IRUGO | S_IWUSR); 46925d807076SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 4693773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 4694773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 4695773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 4696773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 4697773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 4698773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 46995d807076SDouglas Gilbert module_param_named(medium_error_count, sdebug_medium_error_count, int, 47005d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 47015d807076SDouglas Gilbert module_param_named(medium_error_start, sdebug_medium_error_start, int, 47025d807076SDouglas Gilbert S_IRUGO | S_IWUSR); 4703773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 4704773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 4705773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 4706773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 4707773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 4708773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 47095d807076SDouglas Gilbert module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 4710773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 471187c715dcSDouglas Gilbert module_param_named(per_host_store, sdebug_per_host_store, bool, 471287c715dcSDouglas Gilbert S_IRUGO | S_IWUSR); 4713773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 4714773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 47150c4bc91dSDouglas Gilbert module_param_named(random, sdebug_random, bool, S_IRUGO | S_IWUSR); 4716773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 4717773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 4718773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 4719c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 4720773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 4721c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 4722773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 4723773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 4724773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 4725773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 472609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 47275d807076SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 4728773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 472923183910SDouglas Gilbert S_IRUGO | S_IWUSR); 47309447b6ceSMartin K. Petersen module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR); 4731773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 47325b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 47331da177e4SLinus Torvalds 47341da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 47351da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 47361da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4737b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 47381da177e4SLinus Torvalds 47395d807076SDouglas Gilbert MODULE_PARM_DESC(add_host, "add n hosts, in sysfs if negative remove host(s) (def=1)"); 47405b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 47419b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 47420759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4743cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4744c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 47455b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 47465b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4747c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4748beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 474923183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 47505b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4751185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 4752e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 47539b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 47549b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 47555d807076SDouglas Gilbert MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 47565d807076SDouglas Gilbert MODULE_PARM_DESC(lbprz, 47575d807076SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 47585b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 47595b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 47605b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 47615b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4762c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4763cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4764d9da891aSLaurence Oberman MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error"); 47655d807076SDouglas Gilbert MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error"); 4766cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4767c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 476878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 47691da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4770c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 477132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 477286e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 47735d807076SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 47745d807076SDouglas Gilbert MODULE_PARM_DESC(per_host_store, "If set, next positive add_host will get new store (def=0)"); 47755d807076SDouglas Gilbert MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 47761da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 47770c4bc91dSDouglas Gilbert MODULE_PARM_DESC(random, "If set, uniformly randomize command duration between 0 and delay_in_ns"); 4778d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4779760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 4780ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4781c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 4782c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 4783c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 47845b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 47855b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 47866014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 47876014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 478809ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 478909ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 4790c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 47915b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 47929447b6ceSMartin K. Petersen MODULE_PARM_DESC(wp, "Write Protect (def=0)"); 47935b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 47941da177e4SLinus Torvalds 4795760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 4796760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 47971da177e4SLinus Torvalds 47981da177e4SLinus Torvalds static const char *scsi_debug_info(struct Scsi_Host *shp) 47991da177e4SLinus Torvalds { 4800c4837394SDouglas Gilbert int k; 4801c4837394SDouglas Gilbert 4802760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 4803760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 4804760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 4805c4837394SDouglas Gilbert return sdebug_info; 4806760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 4807760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 4808760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 4809760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 48101da177e4SLinus Torvalds return sdebug_info; 48111da177e4SLinus Torvalds } 48121da177e4SLinus Torvalds 4813cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4814fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 4815fd32119bSDouglas Gilbert int length) 48161da177e4SLinus Torvalds { 48171da177e4SLinus Torvalds char arr[16]; 4818c8ed555aSAl Viro int opts; 48191da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 48201da177e4SLinus Torvalds 48211da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 48221da177e4SLinus Torvalds return -EACCES; 48231da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 48241da177e4SLinus Torvalds arr[minLen] = '\0'; 4825c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 48261da177e4SLinus Torvalds return -EINVAL; 4827773642d9SDouglas Gilbert sdebug_opts = opts; 4828773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4829773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4830773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4831c4837394SDouglas Gilbert tweak_cmnd_count(); 48321da177e4SLinus Torvalds return length; 48331da177e4SLinus Torvalds } 4834c8ed555aSAl Viro 4835cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4836cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4837cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4838c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4839c8ed555aSAl Viro { 4840c4837394SDouglas Gilbert int f, j, l; 4841c4837394SDouglas Gilbert struct sdebug_queue *sqp; 484287c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 4843cbf67842SDouglas Gilbert 4844c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 4845c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 4846c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 4847c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 4848c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 4849c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 4850c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 4851c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 4852c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 4853c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 4854c4837394SDouglas Gilbert num_aborts); 4855c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 4856c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 4857c4837394SDouglas Gilbert num_host_resets); 4858c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 4859c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 4860458df78bSBart Van Assche seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000, 4861458df78bSBart Van Assche sdebug_statistics); 4862c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 4863c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 4864c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 4865c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 4866c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 4867cbf67842SDouglas Gilbert 4868c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 4869c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4870c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 4871c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 4872773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4873c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 4874c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 4875c4837394SDouglas Gilbert "first,last bits", f, l); 4876c4837394SDouglas Gilbert } 4877cbf67842SDouglas Gilbert } 487887c715dcSDouglas Gilbert 487987c715dcSDouglas Gilbert seq_printf(m, "this host_no=%d\n", host->host_no); 488087c715dcSDouglas Gilbert if (!xa_empty(per_store_ap)) { 488187c715dcSDouglas Gilbert bool niu; 488287c715dcSDouglas Gilbert int idx; 488387c715dcSDouglas Gilbert unsigned long l_idx; 488487c715dcSDouglas Gilbert struct sdeb_store_info *sip; 488587c715dcSDouglas Gilbert 488687c715dcSDouglas Gilbert seq_puts(m, "\nhost list:\n"); 488787c715dcSDouglas Gilbert j = 0; 488887c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 488987c715dcSDouglas Gilbert idx = sdhp->si_idx; 489087c715dcSDouglas Gilbert seq_printf(m, " %d: host_no=%d, si_idx=%d\n", j, 489187c715dcSDouglas Gilbert sdhp->shost->host_no, idx); 489287c715dcSDouglas Gilbert ++j; 489387c715dcSDouglas Gilbert } 489487c715dcSDouglas Gilbert seq_printf(m, "\nper_store array [most_recent_idx=%d]:\n", 489587c715dcSDouglas Gilbert sdeb_most_recent_idx); 489687c715dcSDouglas Gilbert j = 0; 489787c715dcSDouglas Gilbert xa_for_each(per_store_ap, l_idx, sip) { 489887c715dcSDouglas Gilbert niu = xa_get_mark(per_store_ap, l_idx, 489987c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 490087c715dcSDouglas Gilbert idx = (int)l_idx; 490187c715dcSDouglas Gilbert seq_printf(m, " %d: idx=%d%s\n", j, idx, 490287c715dcSDouglas Gilbert (niu ? " not_in_use" : "")); 490387c715dcSDouglas Gilbert ++j; 490487c715dcSDouglas Gilbert } 490587c715dcSDouglas Gilbert } 4906c8ed555aSAl Viro return 0; 49071da177e4SLinus Torvalds } 49081da177e4SLinus Torvalds 490982069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 49101da177e4SLinus Torvalds { 4911c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 49121da177e4SLinus Torvalds } 4913c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 4914c4837394SDouglas Gilbert * of delay is jiffies. 4915c4837394SDouglas Gilbert */ 491682069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 491782069379SAkinobu Mita size_t count) 49181da177e4SLinus Torvalds { 4919c2206098SDouglas Gilbert int jdelay, res; 49201da177e4SLinus Torvalds 4921b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 4922cbf67842SDouglas Gilbert res = count; 4923c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4924c4837394SDouglas Gilbert int j, k; 4925c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4926cbf67842SDouglas Gilbert 4927c4837394SDouglas Gilbert block_unblock_all_queues(true); 4928c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4929c4837394SDouglas Gilbert ++j, ++sqp) { 4930c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4931c4837394SDouglas Gilbert sdebug_max_queue); 4932c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4933c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4934c4837394SDouglas Gilbert break; 4935c4837394SDouglas Gilbert } 4936c4837394SDouglas Gilbert } 4937c4837394SDouglas Gilbert if (res > 0) { 4938c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4939773642d9SDouglas Gilbert sdebug_ndelay = 0; 49401da177e4SLinus Torvalds } 4941c4837394SDouglas Gilbert block_unblock_all_queues(false); 4942cbf67842SDouglas Gilbert } 4943cbf67842SDouglas Gilbert return res; 49441da177e4SLinus Torvalds } 49451da177e4SLinus Torvalds return -EINVAL; 49461da177e4SLinus Torvalds } 494782069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 49481da177e4SLinus Torvalds 4949cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4950cbf67842SDouglas Gilbert { 4951773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4952cbf67842SDouglas Gilbert } 4953cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4954c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4955cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4956cbf67842SDouglas Gilbert size_t count) 4957cbf67842SDouglas Gilbert { 4958c4837394SDouglas Gilbert int ndelay, res; 4959cbf67842SDouglas Gilbert 4960cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4961c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 4962cbf67842SDouglas Gilbert res = count; 4963773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4964c4837394SDouglas Gilbert int j, k; 4965c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4966c4837394SDouglas Gilbert 4967c4837394SDouglas Gilbert block_unblock_all_queues(true); 4968c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4969c4837394SDouglas Gilbert ++j, ++sqp) { 4970c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4971c4837394SDouglas Gilbert sdebug_max_queue); 4972c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4973c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4974c4837394SDouglas Gilbert break; 4975c4837394SDouglas Gilbert } 4976c4837394SDouglas Gilbert } 4977c4837394SDouglas Gilbert if (res > 0) { 4978773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4979c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4980c2206098SDouglas Gilbert : DEF_JDELAY; 4981cbf67842SDouglas Gilbert } 4982c4837394SDouglas Gilbert block_unblock_all_queues(false); 4983cbf67842SDouglas Gilbert } 4984cbf67842SDouglas Gilbert return res; 4985cbf67842SDouglas Gilbert } 4986cbf67842SDouglas Gilbert return -EINVAL; 4987cbf67842SDouglas Gilbert } 4988cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4989cbf67842SDouglas Gilbert 499082069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 49911da177e4SLinus Torvalds { 4992773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 49931da177e4SLinus Torvalds } 49941da177e4SLinus Torvalds 499582069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 499682069379SAkinobu Mita size_t count) 49971da177e4SLinus Torvalds { 49981da177e4SLinus Torvalds int opts; 49991da177e4SLinus Torvalds char work[20]; 50001da177e4SLinus Torvalds 50019a051019SDouglas Gilbert if (sscanf(buf, "%10s", work) == 1) { 50029a051019SDouglas Gilbert if (strncasecmp(work, "0x", 2) == 0) { 50039a051019SDouglas Gilbert if (kstrtoint(work + 2, 16, &opts) == 0) 50041da177e4SLinus Torvalds goto opts_done; 50051da177e4SLinus Torvalds } else { 50069a051019SDouglas Gilbert if (kstrtoint(work, 10, &opts) == 0) 50071da177e4SLinus Torvalds goto opts_done; 50081da177e4SLinus Torvalds } 50091da177e4SLinus Torvalds } 50101da177e4SLinus Torvalds return -EINVAL; 50111da177e4SLinus Torvalds opts_done: 5012773642d9SDouglas Gilbert sdebug_opts = opts; 5013773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 5014773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 5015c4837394SDouglas Gilbert tweak_cmnd_count(); 50161da177e4SLinus Torvalds return count; 50171da177e4SLinus Torvalds } 501882069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 50191da177e4SLinus Torvalds 502082069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 50211da177e4SLinus Torvalds { 5022773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 50231da177e4SLinus Torvalds } 502482069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 502582069379SAkinobu Mita size_t count) 50261da177e4SLinus Torvalds { 50271da177e4SLinus Torvalds int n; 50281da177e4SLinus Torvalds 50291da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5030773642d9SDouglas Gilbert sdebug_ptype = n; 50311da177e4SLinus Torvalds return count; 50321da177e4SLinus Torvalds } 50331da177e4SLinus Torvalds return -EINVAL; 50341da177e4SLinus Torvalds } 503582069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 50361da177e4SLinus Torvalds 503782069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 50381da177e4SLinus Torvalds { 5039773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 50401da177e4SLinus Torvalds } 504182069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 504282069379SAkinobu Mita size_t count) 50431da177e4SLinus Torvalds { 50441da177e4SLinus Torvalds int n; 50451da177e4SLinus Torvalds 50461da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5047773642d9SDouglas Gilbert sdebug_dsense = n; 50481da177e4SLinus Torvalds return count; 50491da177e4SLinus Torvalds } 50501da177e4SLinus Torvalds return -EINVAL; 50511da177e4SLinus Torvalds } 505282069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 50531da177e4SLinus Torvalds 505482069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 505523183910SDouglas Gilbert { 5056773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 505723183910SDouglas Gilbert } 505882069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 505982069379SAkinobu Mita size_t count) 506023183910SDouglas Gilbert { 506187c715dcSDouglas Gilbert int n, idx; 506223183910SDouglas Gilbert 506323183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 506487c715dcSDouglas Gilbert bool want_store = (n == 0); 506587c715dcSDouglas Gilbert struct sdebug_host_info *sdhp; 506687c715dcSDouglas Gilbert 5067cbf67842SDouglas Gilbert n = (n > 0); 5068773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 506987c715dcSDouglas Gilbert if (sdebug_fake_rw == n) 507087c715dcSDouglas Gilbert return count; /* not transitioning so do nothing */ 5071cbf67842SDouglas Gilbert 507287c715dcSDouglas Gilbert if (want_store) { /* 1 --> 0 transition, set up store */ 507387c715dcSDouglas Gilbert if (sdeb_first_idx < 0) { 507487c715dcSDouglas Gilbert idx = sdebug_add_store(); 507587c715dcSDouglas Gilbert if (idx < 0) 507687c715dcSDouglas Gilbert return idx; 507787c715dcSDouglas Gilbert } else { 507887c715dcSDouglas Gilbert idx = sdeb_first_idx; 507987c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, 508087c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 5081cbf67842SDouglas Gilbert } 508287c715dcSDouglas Gilbert /* make all hosts use same store */ 508387c715dcSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 508487c715dcSDouglas Gilbert host_list) { 508587c715dcSDouglas Gilbert if (sdhp->si_idx != idx) { 508687c715dcSDouglas Gilbert xa_set_mark(per_store_ap, sdhp->si_idx, 508787c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE); 508887c715dcSDouglas Gilbert sdhp->si_idx = idx; 508987c715dcSDouglas Gilbert } 509087c715dcSDouglas Gilbert } 509187c715dcSDouglas Gilbert sdeb_most_recent_idx = idx; 509287c715dcSDouglas Gilbert } else { /* 0 --> 1 transition is trigger for shrink */ 509387c715dcSDouglas Gilbert sdebug_erase_all_stores(true /* apart from first */); 5094cbf67842SDouglas Gilbert } 5095773642d9SDouglas Gilbert sdebug_fake_rw = n; 509623183910SDouglas Gilbert return count; 509723183910SDouglas Gilbert } 509823183910SDouglas Gilbert return -EINVAL; 509923183910SDouglas Gilbert } 510082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 510123183910SDouglas Gilbert 510282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 5103c65b1445SDouglas Gilbert { 5104773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 5105c65b1445SDouglas Gilbert } 510682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 510782069379SAkinobu Mita size_t count) 5108c65b1445SDouglas Gilbert { 5109c65b1445SDouglas Gilbert int n; 5110c65b1445SDouglas Gilbert 5111c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5112773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 5113c65b1445SDouglas Gilbert return count; 5114c65b1445SDouglas Gilbert } 5115c65b1445SDouglas Gilbert return -EINVAL; 5116c65b1445SDouglas Gilbert } 511782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 5118c65b1445SDouglas Gilbert 511982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 51201da177e4SLinus Torvalds { 5121773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 51221da177e4SLinus Torvalds } 512382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 512482069379SAkinobu Mita size_t count) 51251da177e4SLinus Torvalds { 51261da177e4SLinus Torvalds int n; 51271da177e4SLinus Torvalds 51281da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5129773642d9SDouglas Gilbert sdebug_num_tgts = n; 51301da177e4SLinus Torvalds sdebug_max_tgts_luns(); 51311da177e4SLinus Torvalds return count; 51321da177e4SLinus Torvalds } 51331da177e4SLinus Torvalds return -EINVAL; 51341da177e4SLinus Torvalds } 513582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 51361da177e4SLinus Torvalds 513782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 51381da177e4SLinus Torvalds { 5139773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 51401da177e4SLinus Torvalds } 514182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 51421da177e4SLinus Torvalds 514387c715dcSDouglas Gilbert static ssize_t per_host_store_show(struct device_driver *ddp, char *buf) 514487c715dcSDouglas Gilbert { 514587c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_per_host_store); 514687c715dcSDouglas Gilbert } 514787c715dcSDouglas Gilbert 514887c715dcSDouglas Gilbert static ssize_t per_host_store_store(struct device_driver *ddp, const char *buf, 514987c715dcSDouglas Gilbert size_t count) 515087c715dcSDouglas Gilbert { 515187c715dcSDouglas Gilbert bool v; 515287c715dcSDouglas Gilbert 515387c715dcSDouglas Gilbert if (kstrtobool(buf, &v)) 515487c715dcSDouglas Gilbert return -EINVAL; 515587c715dcSDouglas Gilbert 515687c715dcSDouglas Gilbert sdebug_per_host_store = v; 515787c715dcSDouglas Gilbert return count; 515887c715dcSDouglas Gilbert } 515987c715dcSDouglas Gilbert static DRIVER_ATTR_RW(per_host_store); 516087c715dcSDouglas Gilbert 516182069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 51621da177e4SLinus Torvalds { 5163773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 51641da177e4SLinus Torvalds } 516582069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 51661da177e4SLinus Torvalds 516782069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 51681da177e4SLinus Torvalds { 5169773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 51701da177e4SLinus Torvalds } 517182069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 517282069379SAkinobu Mita size_t count) 51731da177e4SLinus Torvalds { 51741da177e4SLinus Torvalds int nth; 51751da177e4SLinus Torvalds 51761da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 5177773642d9SDouglas Gilbert sdebug_every_nth = nth; 5178c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 5179c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 5180c4837394SDouglas Gilbert sdebug_statistics = true; 5181c4837394SDouglas Gilbert } 5182c4837394SDouglas Gilbert tweak_cmnd_count(); 51831da177e4SLinus Torvalds return count; 51841da177e4SLinus Torvalds } 51851da177e4SLinus Torvalds return -EINVAL; 51861da177e4SLinus Torvalds } 518782069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 51881da177e4SLinus Torvalds 518982069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 51901da177e4SLinus Torvalds { 5191773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 51921da177e4SLinus Torvalds } 519382069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 519482069379SAkinobu Mita size_t count) 51951da177e4SLinus Torvalds { 51961da177e4SLinus Torvalds int n; 519719c8ead7SEwan D. Milne bool changed; 51981da177e4SLinus Torvalds 51991da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 52008d039e22SDouglas Gilbert if (n > 256) { 52018d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 52028d039e22SDouglas Gilbert return -EINVAL; 52038d039e22SDouglas Gilbert } 5204773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 5205773642d9SDouglas Gilbert sdebug_max_luns = n; 52061da177e4SLinus Torvalds sdebug_max_tgts_luns(); 5207773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 520819c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 520919c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 521019c8ead7SEwan D. Milne 521119c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 521219c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 521319c8ead7SEwan D. Milne host_list) { 521419c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 521519c8ead7SEwan D. Milne dev_list) { 521619c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 521719c8ead7SEwan D. Milne dp->uas_bm); 521819c8ead7SEwan D. Milne } 521919c8ead7SEwan D. Milne } 522019c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 522119c8ead7SEwan D. Milne } 52221da177e4SLinus Torvalds return count; 52231da177e4SLinus Torvalds } 52241da177e4SLinus Torvalds return -EINVAL; 52251da177e4SLinus Torvalds } 522682069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 52271da177e4SLinus Torvalds 522882069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 522978d4e5a0SDouglas Gilbert { 5230773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 523178d4e5a0SDouglas Gilbert } 5232cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 5233cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 523482069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 523582069379SAkinobu Mita size_t count) 523678d4e5a0SDouglas Gilbert { 5237c4837394SDouglas Gilbert int j, n, k, a; 5238c4837394SDouglas Gilbert struct sdebug_queue *sqp; 523978d4e5a0SDouglas Gilbert 524078d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 5241c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 5242c4837394SDouglas Gilbert block_unblock_all_queues(true); 5243c4837394SDouglas Gilbert k = 0; 5244c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 5245c4837394SDouglas Gilbert ++j, ++sqp) { 5246c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 5247c4837394SDouglas Gilbert if (a > k) 5248c4837394SDouglas Gilbert k = a; 5249c4837394SDouglas Gilbert } 5250773642d9SDouglas Gilbert sdebug_max_queue = n; 5251c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 5252cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 5253cbf67842SDouglas Gilbert else if (k >= n) 5254cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 5255cbf67842SDouglas Gilbert else 5256cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 5257c4837394SDouglas Gilbert block_unblock_all_queues(false); 525878d4e5a0SDouglas Gilbert return count; 525978d4e5a0SDouglas Gilbert } 526078d4e5a0SDouglas Gilbert return -EINVAL; 526178d4e5a0SDouglas Gilbert } 526282069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 526378d4e5a0SDouglas Gilbert 526482069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 526578d4e5a0SDouglas Gilbert { 5266773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 526778d4e5a0SDouglas Gilbert } 526882069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 526978d4e5a0SDouglas Gilbert 527082069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 52711da177e4SLinus Torvalds { 5272773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 52731da177e4SLinus Torvalds } 527482069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 52751da177e4SLinus Torvalds 527682069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 5277c65b1445SDouglas Gilbert { 5278773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 5279c65b1445SDouglas Gilbert } 528082069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 528182069379SAkinobu Mita size_t count) 5282c65b1445SDouglas Gilbert { 5283c65b1445SDouglas Gilbert int n; 52840d01c5dfSDouglas Gilbert bool changed; 5285c65b1445SDouglas Gilbert 5286c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5287773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 5288773642d9SDouglas Gilbert sdebug_virtual_gb = n; 528928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 52900d01c5dfSDouglas Gilbert if (changed) { 52910d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 52920d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 529328898873SFUJITA Tomonori 52944bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 52950d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 52960d01c5dfSDouglas Gilbert host_list) { 52970d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 52980d01c5dfSDouglas Gilbert dev_list) { 52990d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 53000d01c5dfSDouglas Gilbert dp->uas_bm); 53010d01c5dfSDouglas Gilbert } 53020d01c5dfSDouglas Gilbert } 53034bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 53040d01c5dfSDouglas Gilbert } 5305c65b1445SDouglas Gilbert return count; 5306c65b1445SDouglas Gilbert } 5307c65b1445SDouglas Gilbert return -EINVAL; 5308c65b1445SDouglas Gilbert } 530982069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 5310c65b1445SDouglas Gilbert 531182069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 53121da177e4SLinus Torvalds { 531387c715dcSDouglas Gilbert /* absolute number of hosts currently active is what is shown */ 531487c715dcSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_hosts); 53151da177e4SLinus Torvalds } 53161da177e4SLinus Torvalds 531782069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 531882069379SAkinobu Mita size_t count) 53191da177e4SLinus Torvalds { 532087c715dcSDouglas Gilbert bool found; 532187c715dcSDouglas Gilbert unsigned long idx; 532287c715dcSDouglas Gilbert struct sdeb_store_info *sip; 532387c715dcSDouglas Gilbert bool want_phs = (sdebug_fake_rw == 0) && sdebug_per_host_store; 53241da177e4SLinus Torvalds int delta_hosts; 53251da177e4SLinus Torvalds 5326f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 53271da177e4SLinus Torvalds return -EINVAL; 53281da177e4SLinus Torvalds if (delta_hosts > 0) { 53291da177e4SLinus Torvalds do { 533087c715dcSDouglas Gilbert found = false; 533187c715dcSDouglas Gilbert if (want_phs) { 533287c715dcSDouglas Gilbert xa_for_each_marked(per_store_ap, idx, sip, 533387c715dcSDouglas Gilbert SDEB_XA_NOT_IN_USE) { 533487c715dcSDouglas Gilbert sdeb_most_recent_idx = (int)idx; 533587c715dcSDouglas Gilbert found = true; 533687c715dcSDouglas Gilbert break; 533787c715dcSDouglas Gilbert } 533887c715dcSDouglas Gilbert if (found) /* re-use case */ 533987c715dcSDouglas Gilbert sdebug_add_host_helper((int)idx); 534087c715dcSDouglas Gilbert else 534187c715dcSDouglas Gilbert sdebug_do_add_host(true); 534287c715dcSDouglas Gilbert } else { 534387c715dcSDouglas Gilbert sdebug_do_add_host(false); 534487c715dcSDouglas Gilbert } 53451da177e4SLinus Torvalds } while (--delta_hosts); 53461da177e4SLinus Torvalds } else if (delta_hosts < 0) { 53471da177e4SLinus Torvalds do { 534887c715dcSDouglas Gilbert sdebug_do_remove_host(false); 53491da177e4SLinus Torvalds } while (++delta_hosts); 53501da177e4SLinus Torvalds } 53511da177e4SLinus Torvalds return count; 53521da177e4SLinus Torvalds } 535382069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 53541da177e4SLinus Torvalds 535582069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 535623183910SDouglas Gilbert { 5357773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 535823183910SDouglas Gilbert } 535982069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 536082069379SAkinobu Mita size_t count) 536123183910SDouglas Gilbert { 536223183910SDouglas Gilbert int n; 536323183910SDouglas Gilbert 536423183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5365773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 536623183910SDouglas Gilbert return count; 536723183910SDouglas Gilbert } 536823183910SDouglas Gilbert return -EINVAL; 536923183910SDouglas Gilbert } 537082069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 537123183910SDouglas Gilbert 5372c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 5373c4837394SDouglas Gilbert { 5374c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 5375c4837394SDouglas Gilbert } 5376c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 5377c4837394SDouglas Gilbert size_t count) 5378c4837394SDouglas Gilbert { 5379c4837394SDouglas Gilbert int n; 5380c4837394SDouglas Gilbert 5381c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 5382c4837394SDouglas Gilbert if (n > 0) 5383c4837394SDouglas Gilbert sdebug_statistics = true; 5384c4837394SDouglas Gilbert else { 5385c4837394SDouglas Gilbert clear_queue_stats(); 5386c4837394SDouglas Gilbert sdebug_statistics = false; 5387c4837394SDouglas Gilbert } 5388c4837394SDouglas Gilbert return count; 5389c4837394SDouglas Gilbert } 5390c4837394SDouglas Gilbert return -EINVAL; 5391c4837394SDouglas Gilbert } 5392c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 5393c4837394SDouglas Gilbert 539482069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 5395597136abSMartin K. Petersen { 5396773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 5397597136abSMartin K. Petersen } 539882069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 5399597136abSMartin K. Petersen 5400c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 5401c4837394SDouglas Gilbert { 5402c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 5403c4837394SDouglas Gilbert } 5404c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 5405c4837394SDouglas Gilbert 540682069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 5407c6a44287SMartin K. Petersen { 5408773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 5409c6a44287SMartin K. Petersen } 541082069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 5411c6a44287SMartin K. Petersen 541282069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 5413c6a44287SMartin K. Petersen { 5414773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 5415c6a44287SMartin K. Petersen } 541682069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 5417c6a44287SMartin K. Petersen 541882069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 5419c6a44287SMartin K. Petersen { 5420773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 5421c6a44287SMartin K. Petersen } 542282069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 5423c6a44287SMartin K. Petersen 542482069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 5425c6a44287SMartin K. Petersen { 5426773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 5427c6a44287SMartin K. Petersen } 542882069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 5429c6a44287SMartin K. Petersen 543082069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 543144d92694SMartin K. Petersen { 543287c715dcSDouglas Gilbert ssize_t count = 0; 543344d92694SMartin K. Petersen 54345b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 543544d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 543644d92694SMartin K. Petersen sdebug_store_sectors); 543744d92694SMartin K. Petersen 543887c715dcSDouglas Gilbert if (sdebug_fake_rw == 0 && !xa_empty(per_store_ap)) { 543987c715dcSDouglas Gilbert struct sdeb_store_info *sip = xa_load(per_store_ap, 0); 544087c715dcSDouglas Gilbert 544187c715dcSDouglas Gilbert if (sip) 5442c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 544387c715dcSDouglas Gilbert (int)map_size, sip->map_storep); 544487c715dcSDouglas Gilbert } 544544d92694SMartin K. Petersen buf[count++] = '\n'; 5446c7badc90STejun Heo buf[count] = '\0'; 544744d92694SMartin K. Petersen 544844d92694SMartin K. Petersen return count; 544944d92694SMartin K. Petersen } 545082069379SAkinobu Mita static DRIVER_ATTR_RO(map); 545144d92694SMartin K. Petersen 54520c4bc91dSDouglas Gilbert static ssize_t random_show(struct device_driver *ddp, char *buf) 54530c4bc91dSDouglas Gilbert { 54540c4bc91dSDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_random); 54550c4bc91dSDouglas Gilbert } 54560c4bc91dSDouglas Gilbert 54570c4bc91dSDouglas Gilbert static ssize_t random_store(struct device_driver *ddp, const char *buf, 54580c4bc91dSDouglas Gilbert size_t count) 54590c4bc91dSDouglas Gilbert { 54600c4bc91dSDouglas Gilbert bool v; 54610c4bc91dSDouglas Gilbert 54620c4bc91dSDouglas Gilbert if (kstrtobool(buf, &v)) 54630c4bc91dSDouglas Gilbert return -EINVAL; 54640c4bc91dSDouglas Gilbert 54650c4bc91dSDouglas Gilbert sdebug_random = v; 54660c4bc91dSDouglas Gilbert return count; 54670c4bc91dSDouglas Gilbert } 54680c4bc91dSDouglas Gilbert static DRIVER_ATTR_RW(random); 54690c4bc91dSDouglas Gilbert 547082069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 5471d986788bSMartin Pitt { 5472773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 5473d986788bSMartin Pitt } 547482069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 547582069379SAkinobu Mita size_t count) 5476d986788bSMartin Pitt { 5477d986788bSMartin Pitt int n; 5478d986788bSMartin Pitt 5479d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5480773642d9SDouglas Gilbert sdebug_removable = (n > 0); 5481d986788bSMartin Pitt return count; 5482d986788bSMartin Pitt } 5483d986788bSMartin Pitt return -EINVAL; 5484d986788bSMartin Pitt } 548582069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 5486d986788bSMartin Pitt 5487cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 5488cbf67842SDouglas Gilbert { 5489773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 5490cbf67842SDouglas Gilbert } 5491185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 5492cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 5493cbf67842SDouglas Gilbert size_t count) 5494cbf67842SDouglas Gilbert { 5495185dd232SDouglas Gilbert int n; 5496cbf67842SDouglas Gilbert 5497cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5498185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 5499185dd232SDouglas Gilbert return count; 5500cbf67842SDouglas Gilbert } 5501cbf67842SDouglas Gilbert return -EINVAL; 5502cbf67842SDouglas Gilbert } 5503cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 5504cbf67842SDouglas Gilbert 5505c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 5506c2248fc9SDouglas Gilbert { 5507773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 5508c2248fc9SDouglas Gilbert } 5509c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 5510c2248fc9SDouglas Gilbert size_t count) 5511c2248fc9SDouglas Gilbert { 5512c2248fc9SDouglas Gilbert int n; 5513c2248fc9SDouglas Gilbert 5514c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 5515773642d9SDouglas Gilbert sdebug_strict = (n > 0); 5516c2248fc9SDouglas Gilbert return count; 5517c2248fc9SDouglas Gilbert } 5518c2248fc9SDouglas Gilbert return -EINVAL; 5519c2248fc9SDouglas Gilbert } 5520c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 5521c2248fc9SDouglas Gilbert 552209ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 552309ba24c1SDouglas Gilbert { 552409ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 552509ba24c1SDouglas Gilbert } 552609ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 552709ba24c1SDouglas Gilbert 55289b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 55299b760fd8SDouglas Gilbert { 55309b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 55319b760fd8SDouglas Gilbert } 55329b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 55339b760fd8SDouglas Gilbert size_t count) 55349b760fd8SDouglas Gilbert { 55359b760fd8SDouglas Gilbert int ret, n; 55369b760fd8SDouglas Gilbert 55379b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 55389b760fd8SDouglas Gilbert if (ret) 55399b760fd8SDouglas Gilbert return ret; 55409b760fd8SDouglas Gilbert sdebug_cdb_len = n; 55419b760fd8SDouglas Gilbert all_config_cdb_len(); 55429b760fd8SDouglas Gilbert return count; 55439b760fd8SDouglas Gilbert } 55449b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 55459b760fd8SDouglas Gilbert 5546cbf67842SDouglas Gilbert 554782069379SAkinobu Mita /* Note: The following array creates attribute files in the 554823183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 554923183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 555023183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 555187c715dcSDouglas Gilbert is changed. For example see: add_host_store() above. 555223183910SDouglas Gilbert */ 55536ecaff7fSRandy Dunlap 555482069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 555582069379SAkinobu Mita &driver_attr_delay.attr, 555682069379SAkinobu Mita &driver_attr_opts.attr, 555782069379SAkinobu Mita &driver_attr_ptype.attr, 555882069379SAkinobu Mita &driver_attr_dsense.attr, 555982069379SAkinobu Mita &driver_attr_fake_rw.attr, 556082069379SAkinobu Mita &driver_attr_no_lun_0.attr, 556182069379SAkinobu Mita &driver_attr_num_tgts.attr, 556282069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 556382069379SAkinobu Mita &driver_attr_num_parts.attr, 556482069379SAkinobu Mita &driver_attr_every_nth.attr, 556582069379SAkinobu Mita &driver_attr_max_luns.attr, 556682069379SAkinobu Mita &driver_attr_max_queue.attr, 556782069379SAkinobu Mita &driver_attr_no_uld.attr, 556882069379SAkinobu Mita &driver_attr_scsi_level.attr, 556982069379SAkinobu Mita &driver_attr_virtual_gb.attr, 557082069379SAkinobu Mita &driver_attr_add_host.attr, 557187c715dcSDouglas Gilbert &driver_attr_per_host_store.attr, 557282069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 557382069379SAkinobu Mita &driver_attr_sector_size.attr, 5574c4837394SDouglas Gilbert &driver_attr_statistics.attr, 5575c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 557682069379SAkinobu Mita &driver_attr_dix.attr, 557782069379SAkinobu Mita &driver_attr_dif.attr, 557882069379SAkinobu Mita &driver_attr_guard.attr, 557982069379SAkinobu Mita &driver_attr_ato.attr, 558082069379SAkinobu Mita &driver_attr_map.attr, 55810c4bc91dSDouglas Gilbert &driver_attr_random.attr, 558282069379SAkinobu Mita &driver_attr_removable.attr, 5583cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 5584cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 5585c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 558609ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 55879b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 558882069379SAkinobu Mita NULL, 558982069379SAkinobu Mita }; 559082069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 55911da177e4SLinus Torvalds 559211ddcecaSAkinobu Mita static struct device *pseudo_primary; 55938dea0d02SFUJITA Tomonori 55941da177e4SLinus Torvalds static int __init scsi_debug_init(void) 55951da177e4SLinus Torvalds { 559687c715dcSDouglas Gilbert bool want_store = (sdebug_fake_rw == 0); 55975f2578e5SFUJITA Tomonori unsigned long sz; 559887c715dcSDouglas Gilbert int k, ret, hosts_to_add; 559987c715dcSDouglas Gilbert int idx = -1; 56001da177e4SLinus Torvalds 560187c715dcSDouglas Gilbert ramdisk_lck_a[0] = &atomic_rw; 560287c715dcSDouglas Gilbert ramdisk_lck_a[1] = &atomic_rw2; 5603cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 5604cbf67842SDouglas Gilbert 5605773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 5606c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 5607773642d9SDouglas Gilbert sdebug_ndelay = 0; 5608773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 5609c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 5610cbf67842SDouglas Gilbert 5611773642d9SDouglas Gilbert switch (sdebug_sector_size) { 5612597136abSMartin K. Petersen case 512: 5613597136abSMartin K. Petersen case 1024: 5614597136abSMartin K. Petersen case 2048: 5615597136abSMartin K. Petersen case 4096: 5616597136abSMartin K. Petersen break; 5617597136abSMartin K. Petersen default: 5618773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 5619597136abSMartin K. Petersen return -EINVAL; 5620597136abSMartin K. Petersen } 5621597136abSMartin K. Petersen 5622773642d9SDouglas Gilbert switch (sdebug_dif) { 56238475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 5624f46eb0e9SDouglas Gilbert break; 56258475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 56268475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 56278475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 5628f46eb0e9SDouglas Gilbert have_dif_prot = true; 5629c6a44287SMartin K. Petersen break; 5630c6a44287SMartin K. Petersen 5631c6a44287SMartin K. Petersen default: 5632c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 5633c6a44287SMartin K. Petersen return -EINVAL; 5634c6a44287SMartin K. Petersen } 5635c6a44287SMartin K. Petersen 5636aa5334c4SMaurizio Lombardi if (sdebug_num_tgts < 0) { 5637aa5334c4SMaurizio Lombardi pr_err("num_tgts must be >= 0\n"); 5638aa5334c4SMaurizio Lombardi return -EINVAL; 5639aa5334c4SMaurizio Lombardi } 5640aa5334c4SMaurizio Lombardi 5641773642d9SDouglas Gilbert if (sdebug_guard > 1) { 5642c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 5643c6a44287SMartin K. Petersen return -EINVAL; 5644c6a44287SMartin K. Petersen } 5645c6a44287SMartin K. Petersen 5646773642d9SDouglas Gilbert if (sdebug_ato > 1) { 5647c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 5648c6a44287SMartin K. Petersen return -EINVAL; 5649c6a44287SMartin K. Petersen } 5650c6a44287SMartin K. Petersen 5651773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 5652773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 5653ea61fca5SMartin K. Petersen return -EINVAL; 5654ea61fca5SMartin K. Petersen } 56558d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 56568d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 56578d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 56588d039e22SDouglas Gilbert } 5659ea61fca5SMartin K. Petersen 5660773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 5661773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 5662ea61fca5SMartin K. Petersen return -EINVAL; 5663ea61fca5SMartin K. Petersen } 5664ea61fca5SMartin K. Petersen 5665c4837394SDouglas Gilbert if (submit_queues < 1) { 5666c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 5667c4837394SDouglas Gilbert return -EINVAL; 5668c4837394SDouglas Gilbert } 5669c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 5670c4837394SDouglas Gilbert GFP_KERNEL); 5671c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 5672c4837394SDouglas Gilbert return -ENOMEM; 5673c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 5674c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 5675c4837394SDouglas Gilbert 5676773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 5677773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 5678773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 5679773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 568028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 56811da177e4SLinus Torvalds 56821da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 56831da177e4SLinus Torvalds sdebug_heads = 8; 56841da177e4SLinus Torvalds sdebug_sectors_per = 32; 5685773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 56861da177e4SLinus Torvalds sdebug_heads = 64; 5687773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 5688fa785f0aSAndy Shevchenko sdebug_heads = 32; 56891da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 56901da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 56911da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 56921da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 56931da177e4SLinus Torvalds sdebug_heads = 255; 56941da177e4SLinus Torvalds sdebug_sectors_per = 63; 56951da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 56961da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 56971da177e4SLinus Torvalds } 56985b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 5699773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 5700773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 57016014759cSMartin K. Petersen 5702773642d9SDouglas Gilbert sdebug_unmap_max_desc = 5703773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 57046014759cSMartin K. Petersen 5705773642d9SDouglas Gilbert sdebug_unmap_granularity = 5706773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 57076014759cSMartin K. Petersen 5708773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 5709773642d9SDouglas Gilbert sdebug_unmap_granularity <= 5710773642d9SDouglas Gilbert sdebug_unmap_alignment) { 5711c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 5712c4837394SDouglas Gilbert ret = -EINVAL; 571387c715dcSDouglas Gilbert goto free_q_arr; 571444d92694SMartin K. Petersen } 571544d92694SMartin K. Petersen } 571687c715dcSDouglas Gilbert xa_init_flags(per_store_ap, XA_FLAGS_ALLOC | XA_FLAGS_LOCK_IRQ); 571787c715dcSDouglas Gilbert if (want_store) { 571887c715dcSDouglas Gilbert idx = sdebug_add_store(); 571987c715dcSDouglas Gilbert if (idx < 0) { 572087c715dcSDouglas Gilbert ret = idx; 572187c715dcSDouglas Gilbert goto free_q_arr; 572287c715dcSDouglas Gilbert } 572344d92694SMartin K. Petersen } 572444d92694SMartin K. Petersen 57259b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 57269b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 5727c1287970STomas Winkler pr_warn("root_device_register() error\n"); 57289b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 57296ecaff7fSRandy Dunlap goto free_vm; 57306ecaff7fSRandy Dunlap } 57316ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 57326ecaff7fSRandy Dunlap if (ret < 0) { 5733c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 57346ecaff7fSRandy Dunlap goto dev_unreg; 57356ecaff7fSRandy Dunlap } 57366ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 57376ecaff7fSRandy Dunlap if (ret < 0) { 5738c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 57396ecaff7fSRandy Dunlap goto bus_unreg; 57406ecaff7fSRandy Dunlap } 57411da177e4SLinus Torvalds 574287c715dcSDouglas Gilbert hosts_to_add = sdebug_add_host; 5743773642d9SDouglas Gilbert sdebug_add_host = 0; 57441da177e4SLinus Torvalds 574587c715dcSDouglas Gilbert for (k = 0; k < hosts_to_add; k++) { 574687c715dcSDouglas Gilbert if (want_store && k == 0) { 574787c715dcSDouglas Gilbert ret = sdebug_add_host_helper(idx); 574887c715dcSDouglas Gilbert if (ret < 0) { 574987c715dcSDouglas Gilbert pr_err("add_host_helper k=%d, error=%d\n", 575087c715dcSDouglas Gilbert k, -ret); 575187c715dcSDouglas Gilbert break; 575287c715dcSDouglas Gilbert } 575387c715dcSDouglas Gilbert } else { 575487c715dcSDouglas Gilbert ret = sdebug_do_add_host(want_store && 575587c715dcSDouglas Gilbert sdebug_per_host_store); 575687c715dcSDouglas Gilbert if (ret < 0) { 575787c715dcSDouglas Gilbert pr_err("add_host k=%d error=%d\n", k, -ret); 57581da177e4SLinus Torvalds break; 57591da177e4SLinus Torvalds } 57601da177e4SLinus Torvalds } 576187c715dcSDouglas Gilbert } 5762773642d9SDouglas Gilbert if (sdebug_verbose) 576387c715dcSDouglas Gilbert pr_info("built %d host(s)\n", sdebug_num_hosts); 5764c1287970STomas Winkler 57651da177e4SLinus Torvalds return 0; 57666ecaff7fSRandy Dunlap 57676ecaff7fSRandy Dunlap bus_unreg: 57686ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 57696ecaff7fSRandy Dunlap dev_unreg: 57709b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 57716ecaff7fSRandy Dunlap free_vm: 577287c715dcSDouglas Gilbert sdebug_erase_store(idx, NULL); 5773c4837394SDouglas Gilbert free_q_arr: 5774c4837394SDouglas Gilbert kfree(sdebug_q_arr); 57756ecaff7fSRandy Dunlap return ret; 57761da177e4SLinus Torvalds } 57771da177e4SLinus Torvalds 57781da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 57791da177e4SLinus Torvalds { 578087c715dcSDouglas Gilbert int k = sdebug_num_hosts; 57811da177e4SLinus Torvalds 57821da177e4SLinus Torvalds stop_all_queued(); 57831da177e4SLinus Torvalds for (; k; k--) 578487c715dcSDouglas Gilbert sdebug_do_remove_host(true); 578552ab9768SLuis Henriques free_all_queued(); 57861da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 57871da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 57889b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 57891da177e4SLinus Torvalds 579087c715dcSDouglas Gilbert sdebug_erase_all_stores(false); 579187c715dcSDouglas Gilbert xa_destroy(per_store_ap); 57921da177e4SLinus Torvalds } 57931da177e4SLinus Torvalds 57941da177e4SLinus Torvalds device_initcall(scsi_debug_init); 57951da177e4SLinus Torvalds module_exit(scsi_debug_exit); 57961da177e4SLinus Torvalds 57971da177e4SLinus Torvalds static void sdebug_release_adapter(struct device *dev) 57981da177e4SLinus Torvalds { 57991da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 58001da177e4SLinus Torvalds 58011da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 58021da177e4SLinus Torvalds kfree(sdbg_host); 58031da177e4SLinus Torvalds } 58041da177e4SLinus Torvalds 580587c715dcSDouglas Gilbert /* idx must be valid, if sip is NULL then it will be obtained using idx */ 580687c715dcSDouglas Gilbert static void sdebug_erase_store(int idx, struct sdeb_store_info *sip) 58071da177e4SLinus Torvalds { 580887c715dcSDouglas Gilbert if (idx < 0) 580987c715dcSDouglas Gilbert return; 581087c715dcSDouglas Gilbert if (!sip) { 581187c715dcSDouglas Gilbert if (xa_empty(per_store_ap)) 581287c715dcSDouglas Gilbert return; 581387c715dcSDouglas Gilbert sip = xa_load(per_store_ap, idx); 581487c715dcSDouglas Gilbert if (!sip) 581587c715dcSDouglas Gilbert return; 581687c715dcSDouglas Gilbert } 581787c715dcSDouglas Gilbert vfree(sip->map_storep); 581887c715dcSDouglas Gilbert vfree(sip->dif_storep); 581987c715dcSDouglas Gilbert vfree(sip->storep); 582087c715dcSDouglas Gilbert xa_erase(per_store_ap, idx); 582187c715dcSDouglas Gilbert kfree(sip); 582287c715dcSDouglas Gilbert } 582387c715dcSDouglas Gilbert 582487c715dcSDouglas Gilbert /* Assume apart_from_first==false only in shutdown case. */ 582587c715dcSDouglas Gilbert static void sdebug_erase_all_stores(bool apart_from_first) 582687c715dcSDouglas Gilbert { 582787c715dcSDouglas Gilbert unsigned long idx; 582887c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 582987c715dcSDouglas Gilbert 583087c715dcSDouglas Gilbert xa_for_each(per_store_ap, idx, sip) { 583187c715dcSDouglas Gilbert if (apart_from_first) 583287c715dcSDouglas Gilbert apart_from_first = false; 583387c715dcSDouglas Gilbert else 583487c715dcSDouglas Gilbert sdebug_erase_store(idx, sip); 583587c715dcSDouglas Gilbert } 583687c715dcSDouglas Gilbert if (apart_from_first) 583787c715dcSDouglas Gilbert sdeb_most_recent_idx = sdeb_first_idx; 583887c715dcSDouglas Gilbert } 583987c715dcSDouglas Gilbert 584087c715dcSDouglas Gilbert /* 584187c715dcSDouglas Gilbert * Returns store xarray new element index (idx) if >=0 else negated errno. 584287c715dcSDouglas Gilbert * Limit the number of stores to 65536. 584387c715dcSDouglas Gilbert */ 584487c715dcSDouglas Gilbert static int sdebug_add_store(void) 584587c715dcSDouglas Gilbert { 584687c715dcSDouglas Gilbert int res; 584787c715dcSDouglas Gilbert u32 n_idx; 584887c715dcSDouglas Gilbert unsigned long iflags; 584987c715dcSDouglas Gilbert unsigned long sz = (unsigned long)sdebug_dev_size_mb * 1048576; 585087c715dcSDouglas Gilbert struct sdeb_store_info *sip = NULL; 585187c715dcSDouglas Gilbert struct xa_limit xal = { .max = 1 << 16, .min = 0 }; 585287c715dcSDouglas Gilbert 585387c715dcSDouglas Gilbert sip = kzalloc(sizeof(*sip), GFP_KERNEL); 585487c715dcSDouglas Gilbert if (!sip) 585587c715dcSDouglas Gilbert return -ENOMEM; 585687c715dcSDouglas Gilbert 585787c715dcSDouglas Gilbert xa_lock_irqsave(per_store_ap, iflags); 585887c715dcSDouglas Gilbert res = __xa_alloc(per_store_ap, &n_idx, sip, xal, GFP_ATOMIC); 585987c715dcSDouglas Gilbert if (unlikely(res < 0)) { 586087c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 586187c715dcSDouglas Gilbert kfree(sip); 586287c715dcSDouglas Gilbert pr_warn("%s: xa_alloc() errno=%d\n", __func__, -res); 586387c715dcSDouglas Gilbert return res; 586487c715dcSDouglas Gilbert } 586587c715dcSDouglas Gilbert sdeb_most_recent_idx = n_idx; 586687c715dcSDouglas Gilbert if (sdeb_first_idx < 0) 586787c715dcSDouglas Gilbert sdeb_first_idx = n_idx; 586887c715dcSDouglas Gilbert xa_unlock_irqrestore(per_store_ap, iflags); 586987c715dcSDouglas Gilbert 587087c715dcSDouglas Gilbert res = -ENOMEM; 587187c715dcSDouglas Gilbert sip->storep = vzalloc(sz); 587287c715dcSDouglas Gilbert if (!sip->storep) { 587387c715dcSDouglas Gilbert pr_err("user data oom\n"); 587487c715dcSDouglas Gilbert goto err; 587587c715dcSDouglas Gilbert } 587687c715dcSDouglas Gilbert if (sdebug_num_parts > 0) 587787c715dcSDouglas Gilbert sdebug_build_parts(sip->storep, sz); 587887c715dcSDouglas Gilbert 587987c715dcSDouglas Gilbert /* DIF/DIX: what T10 calls Protection Information (PI) */ 588087c715dcSDouglas Gilbert if (sdebug_dix) { 588187c715dcSDouglas Gilbert int dif_size; 588287c715dcSDouglas Gilbert 588387c715dcSDouglas Gilbert dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 588487c715dcSDouglas Gilbert sip->dif_storep = vmalloc(dif_size); 588587c715dcSDouglas Gilbert 588687c715dcSDouglas Gilbert pr_info("dif_storep %u bytes @ %pK\n", dif_size, 588787c715dcSDouglas Gilbert sip->dif_storep); 588887c715dcSDouglas Gilbert 588987c715dcSDouglas Gilbert if (!sip->dif_storep) { 589087c715dcSDouglas Gilbert pr_err("DIX oom\n"); 589187c715dcSDouglas Gilbert goto err; 589287c715dcSDouglas Gilbert } 589387c715dcSDouglas Gilbert memset(sip->dif_storep, 0xff, dif_size); 589487c715dcSDouglas Gilbert } 589587c715dcSDouglas Gilbert /* Logical Block Provisioning */ 589687c715dcSDouglas Gilbert if (scsi_debug_lbp()) { 589787c715dcSDouglas Gilbert map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 589887c715dcSDouglas Gilbert sip->map_storep = vmalloc(array_size(sizeof(long), 589987c715dcSDouglas Gilbert BITS_TO_LONGS(map_size))); 590087c715dcSDouglas Gilbert 590187c715dcSDouglas Gilbert pr_info("%lu provisioning blocks\n", map_size); 590287c715dcSDouglas Gilbert 590387c715dcSDouglas Gilbert if (!sip->map_storep) { 590487c715dcSDouglas Gilbert pr_err("LBP map oom\n"); 590587c715dcSDouglas Gilbert goto err; 590687c715dcSDouglas Gilbert } 590787c715dcSDouglas Gilbert 590887c715dcSDouglas Gilbert bitmap_zero(sip->map_storep, map_size); 590987c715dcSDouglas Gilbert 591087c715dcSDouglas Gilbert /* Map first 1KB for partition table */ 591187c715dcSDouglas Gilbert if (sdebug_num_parts) 591287c715dcSDouglas Gilbert map_region(sip, 0, 2); 591387c715dcSDouglas Gilbert } 591487c715dcSDouglas Gilbert 591587c715dcSDouglas Gilbert rwlock_init(&sip->macc_lck); 591687c715dcSDouglas Gilbert return (int)n_idx; 591787c715dcSDouglas Gilbert err: 591887c715dcSDouglas Gilbert sdebug_erase_store((int)n_idx, sip); 591987c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -res); 592087c715dcSDouglas Gilbert return res; 592187c715dcSDouglas Gilbert } 592287c715dcSDouglas Gilbert 592387c715dcSDouglas Gilbert static int sdebug_add_host_helper(int per_host_idx) 592487c715dcSDouglas Gilbert { 592587c715dcSDouglas Gilbert int k, devs_per_host, idx; 592687c715dcSDouglas Gilbert int error = -ENOMEM; 59271da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 59288b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 59291da177e4SLinus Torvalds 593024669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL); 593187c715dcSDouglas Gilbert if (!sdbg_host) 59321da177e4SLinus Torvalds return -ENOMEM; 593387c715dcSDouglas Gilbert idx = (per_host_idx < 0) ? sdeb_first_idx : per_host_idx; 593487c715dcSDouglas Gilbert if (xa_get_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE)) 593587c715dcSDouglas Gilbert xa_clear_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 593687c715dcSDouglas Gilbert sdbg_host->si_idx = idx; 59371da177e4SLinus Torvalds 59381da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 59391da177e4SLinus Torvalds 5940773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 59411da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 59425cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 594387c715dcSDouglas Gilbert if (!sdbg_devinfo) 59441da177e4SLinus Torvalds goto clean; 59451da177e4SLinus Torvalds } 59461da177e4SLinus Torvalds 59471da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 59481da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 59491da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 59501da177e4SLinus Torvalds 59511da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 59529b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 59531da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 595487c715dcSDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_num_hosts); 59551da177e4SLinus Torvalds 59561da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 59571da177e4SLinus Torvalds if (error) 59581da177e4SLinus Torvalds goto clean; 59591da177e4SLinus Torvalds 596087c715dcSDouglas Gilbert ++sdebug_num_hosts; 596187c715dcSDouglas Gilbert return 0; 59621da177e4SLinus Torvalds 59631da177e4SLinus Torvalds clean: 59648b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 59658b40228fSFUJITA Tomonori dev_list) { 59661da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 59671da177e4SLinus Torvalds kfree(sdbg_devinfo); 59681da177e4SLinus Torvalds } 59691da177e4SLinus Torvalds kfree(sdbg_host); 597087c715dcSDouglas Gilbert pr_warn("%s: failed, errno=%d\n", __func__, -error); 59711da177e4SLinus Torvalds return error; 59721da177e4SLinus Torvalds } 59731da177e4SLinus Torvalds 597487c715dcSDouglas Gilbert static int sdebug_do_add_host(bool mk_new_store) 59751da177e4SLinus Torvalds { 597687c715dcSDouglas Gilbert int ph_idx = sdeb_most_recent_idx; 597787c715dcSDouglas Gilbert 597887c715dcSDouglas Gilbert if (mk_new_store) { 597987c715dcSDouglas Gilbert ph_idx = sdebug_add_store(); 598087c715dcSDouglas Gilbert if (ph_idx < 0) 598187c715dcSDouglas Gilbert return ph_idx; 598287c715dcSDouglas Gilbert } 598387c715dcSDouglas Gilbert return sdebug_add_host_helper(ph_idx); 598487c715dcSDouglas Gilbert } 598587c715dcSDouglas Gilbert 598687c715dcSDouglas Gilbert static void sdebug_do_remove_host(bool the_end) 598787c715dcSDouglas Gilbert { 598887c715dcSDouglas Gilbert int idx = -1; 59891da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host = NULL; 599087c715dcSDouglas Gilbert struct sdebug_host_info *sdbg_host2; 59911da177e4SLinus Torvalds 59921da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 59931da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 59941da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 59951da177e4SLinus Torvalds struct sdebug_host_info, host_list); 599687c715dcSDouglas Gilbert idx = sdbg_host->si_idx; 59971da177e4SLinus Torvalds } 599887c715dcSDouglas Gilbert if (!the_end && idx >= 0) { 599987c715dcSDouglas Gilbert bool unique = true; 600087c715dcSDouglas Gilbert 600187c715dcSDouglas Gilbert list_for_each_entry(sdbg_host2, &sdebug_host_list, host_list) { 600287c715dcSDouglas Gilbert if (sdbg_host2 == sdbg_host) 600387c715dcSDouglas Gilbert continue; 600487c715dcSDouglas Gilbert if (idx == sdbg_host2->si_idx) { 600587c715dcSDouglas Gilbert unique = false; 600687c715dcSDouglas Gilbert break; 600787c715dcSDouglas Gilbert } 600887c715dcSDouglas Gilbert } 600987c715dcSDouglas Gilbert if (unique) { 601087c715dcSDouglas Gilbert xa_set_mark(per_store_ap, idx, SDEB_XA_NOT_IN_USE); 601187c715dcSDouglas Gilbert if (idx == sdeb_most_recent_idx) 601287c715dcSDouglas Gilbert --sdeb_most_recent_idx; 601387c715dcSDouglas Gilbert } 601487c715dcSDouglas Gilbert } 601587c715dcSDouglas Gilbert if (sdbg_host) 601687c715dcSDouglas Gilbert list_del(&sdbg_host->host_list); 60171da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 60181da177e4SLinus Torvalds 60191da177e4SLinus Torvalds if (!sdbg_host) 60201da177e4SLinus Torvalds return; 60211da177e4SLinus Torvalds 60221da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 602387c715dcSDouglas Gilbert --sdebug_num_hosts; 60241da177e4SLinus Torvalds } 60251da177e4SLinus Torvalds 6026fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 6027cbf67842SDouglas Gilbert { 6028cbf67842SDouglas Gilbert int num_in_q = 0; 6029cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 6030cbf67842SDouglas Gilbert 6031c4837394SDouglas Gilbert block_unblock_all_queues(true); 6032cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 6033cbf67842SDouglas Gilbert if (NULL == devip) { 6034c4837394SDouglas Gilbert block_unblock_all_queues(false); 6035cbf67842SDouglas Gilbert return -ENODEV; 6036cbf67842SDouglas Gilbert } 6037cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 6038c40ecc12SChristoph Hellwig 6039cbf67842SDouglas Gilbert if (qdepth < 1) 6040cbf67842SDouglas Gilbert qdepth = 1; 6041c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 6042c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 6043c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 6044db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 6045cbf67842SDouglas Gilbert 6046773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 6047c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 6048c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 6049cbf67842SDouglas Gilbert } 6050c4837394SDouglas Gilbert block_unblock_all_queues(false); 6051cbf67842SDouglas Gilbert return sdev->queue_depth; 6052cbf67842SDouglas Gilbert } 6053cbf67842SDouglas Gilbert 6054c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 6055817fd66bSDouglas Gilbert { 6056c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 6057773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 6058773642d9SDouglas Gilbert sdebug_every_nth = -1; 6059773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 6060c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 6061773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 6062817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 6063c4837394SDouglas Gilbert return true; /* time out reads and writes */ 6064817fd66bSDouglas Gilbert } 6065c4837394SDouglas Gilbert return false; 6066817fd66bSDouglas Gilbert } 6067817fd66bSDouglas Gilbert 60687ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp) 60697ee6d1b4SBart Van Assche { 60707ee6d1b4SBart Van Assche return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) && 60717ee6d1b4SBart Van Assche (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 60727ee6d1b4SBart Van Assche } 60737ee6d1b4SBart Van Assche 6074fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 6075fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 6076c2248fc9SDouglas Gilbert { 6077c2248fc9SDouglas Gilbert u8 sdeb_i; 6078c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 6079c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 6080c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 6081c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 608287c715dcSDouglas Gilbert 6083c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 6084c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 6085f66b8517SMartin Wilck int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL; 6086c2248fc9SDouglas Gilbert int k, na; 6087c2248fc9SDouglas Gilbert int errsts = 0; 6088c2248fc9SDouglas Gilbert u32 flags; 6089c2248fc9SDouglas Gilbert u16 sa; 6090c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 6091c2248fc9SDouglas Gilbert bool has_wlun_rl; 6092c2248fc9SDouglas Gilbert 6093c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 6094c4837394SDouglas Gilbert if (sdebug_statistics) 6095c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 6096f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 6097f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 6098c2248fc9SDouglas Gilbert char b[120]; 6099c2248fc9SDouglas Gilbert int n, len, sb; 6100c2248fc9SDouglas Gilbert 6101c2248fc9SDouglas Gilbert len = scp->cmd_len; 6102c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 6103c2248fc9SDouglas Gilbert if (len > 32) 6104c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 6105c2248fc9SDouglas Gilbert else { 6106c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 6107c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 6108c2248fc9SDouglas Gilbert (u32)cmd[k]); 6109c2248fc9SDouglas Gilbert } 6110458df78bSBart Van Assche sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name, 6111458df78bSBart Van Assche blk_mq_unique_tag(scp->request), b); 6112c2248fc9SDouglas Gilbert } 61137ee6d1b4SBart Van Assche if (fake_host_busy(scp)) 61147ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 611534d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 6116f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 6117f46eb0e9SDouglas Gilbert goto err_out; 6118c2248fc9SDouglas Gilbert 6119c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 6120c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 6121c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 6122f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 6123f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 6124c2248fc9SDouglas Gilbert if (NULL == devip) 6125f46eb0e9SDouglas Gilbert goto err_out; 6126c2248fc9SDouglas Gilbert } 6127c2248fc9SDouglas Gilbert na = oip->num_attached; 6128c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 6129c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 6130c2248fc9SDouglas Gilbert r_oip = oip; 6131c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 6132c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 6133c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 6134c2248fc9SDouglas Gilbert else 6135c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 6136c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 6137c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 6138c2248fc9SDouglas Gilbert break; 6139c2248fc9SDouglas Gilbert } 6140c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 6141c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 6142c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 6143c2248fc9SDouglas Gilbert break; 6144c2248fc9SDouglas Gilbert } 6145c2248fc9SDouglas Gilbert } 6146c2248fc9SDouglas Gilbert if (k > na) { 6147c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 6148c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 6149c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 6150c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 6151c2248fc9SDouglas Gilbert else 6152c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 6153c2248fc9SDouglas Gilbert goto check_cond; 6154c2248fc9SDouglas Gilbert } 6155c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 6156c2248fc9SDouglas Gilbert flags = oip->flags; 6157f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 6158c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 6159c2248fc9SDouglas Gilbert goto check_cond; 6160c2248fc9SDouglas Gilbert } 6161f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 6162773642d9SDouglas Gilbert if (sdebug_verbose) 6163773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 6164773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 6165c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 6166c2248fc9SDouglas Gilbert goto check_cond; 6167c2248fc9SDouglas Gilbert } 6168f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 6169c2248fc9SDouglas Gilbert u8 rem; 6170c2248fc9SDouglas Gilbert int j; 6171c2248fc9SDouglas Gilbert 6172c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 6173c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 6174c2248fc9SDouglas Gilbert if (rem) { 6175c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 6176c2248fc9SDouglas Gilbert if (0x80 & rem) 6177c2248fc9SDouglas Gilbert break; 6178c2248fc9SDouglas Gilbert } 6179c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 6180c2248fc9SDouglas Gilbert goto check_cond; 6181c2248fc9SDouglas Gilbert } 6182c2248fc9SDouglas Gilbert } 6183c2248fc9SDouglas Gilbert } 6184f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 6185b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 6186b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 6187f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 6188c2248fc9SDouglas Gilbert if (errsts) 6189c2248fc9SDouglas Gilbert goto check_cond; 6190c2248fc9SDouglas Gilbert } 6191c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 6192c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 6193773642d9SDouglas Gilbert if (sdebug_verbose) 6194c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 6195c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 6196c2248fc9SDouglas Gilbert "required"); 6197c2248fc9SDouglas Gilbert errsts = check_condition_result; 6198c2248fc9SDouglas Gilbert goto fini; 6199c2248fc9SDouglas Gilbert } 6200773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 6201c2248fc9SDouglas Gilbert goto fini; 6202f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 6203c4837394SDouglas Gilbert if (fake_timeout(scp)) 6204c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 6205c2248fc9SDouglas Gilbert } 6206f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 6207f66b8517SMartin Wilck pfp = oip->pfp; /* calls a resp_* function */ 6208f66b8517SMartin Wilck else 6209f66b8517SMartin Wilck pfp = r_pfp; /* if leaf function ptr NULL, try the root's */ 6210c2248fc9SDouglas Gilbert 6211c2248fc9SDouglas Gilbert fini: 621267da413fSDouglas Gilbert if (F_DELAY_OVERR & flags) /* cmds like INQUIRY respond asap */ 6213f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, 0, 0); 621475aa3209SDouglas Gilbert else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 || 621575aa3209SDouglas Gilbert sdebug_ndelay > 10000)) { 621680c49563SDouglas Gilbert /* 621775aa3209SDouglas Gilbert * Skip long delays if ndelay <= 10 microseconds. Otherwise 621875aa3209SDouglas Gilbert * for Start Stop Unit (SSU) want at least 1 second delay and 621975aa3209SDouglas Gilbert * if sdebug_jdelay>1 want a long delay of that many seconds. 622075aa3209SDouglas Gilbert * For Synchronize Cache want 1/20 of SSU's delay. 622180c49563SDouglas Gilbert */ 622280c49563SDouglas Gilbert int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay; 62234f2c8bf6SDouglas Gilbert int denom = (flags & F_SYNC_DELAY) ? 20 : 1; 622480c49563SDouglas Gilbert 62254f2c8bf6SDouglas Gilbert jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ); 6226f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, jdelay, 0); 622780c49563SDouglas Gilbert } else 6228f66b8517SMartin Wilck return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay, 622910bde980SDouglas Gilbert sdebug_ndelay); 6230c2248fc9SDouglas Gilbert check_cond: 6231f66b8517SMartin Wilck return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0); 6232f46eb0e9SDouglas Gilbert err_out: 6233f66b8517SMartin Wilck return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0); 6234c2248fc9SDouglas Gilbert } 6235c2248fc9SDouglas Gilbert 62369e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 6237c8ed555aSAl Viro .show_info = scsi_debug_show_info, 6238c8ed555aSAl Viro .write_info = scsi_debug_write_info, 62399e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 62409e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 62419e603ca0SFUJITA Tomonori .info = scsi_debug_info, 62429e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 62439e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 62449e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 62459e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 6246185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 6247cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 62489e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 62499e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 6250cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 6251cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 62529e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 6253c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 62549e603ca0SFUJITA Tomonori .this_id = 7, 625565e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 6256cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 62576bb5e6e7SAkinobu Mita .max_sectors = -1U, 625850c2e910SChristoph Hellwig .max_segment_size = -1U, 62599e603ca0SFUJITA Tomonori .module = THIS_MODULE, 6260c40ecc12SChristoph Hellwig .track_queue_depth = 1, 62619e603ca0SFUJITA Tomonori }; 62629e603ca0SFUJITA Tomonori 62631da177e4SLinus Torvalds static int sdebug_driver_probe(struct device *dev) 62641da177e4SLinus Torvalds { 62651da177e4SLinus Torvalds int error = 0; 62661da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 62671da177e4SLinus Torvalds struct Scsi_Host *hpnt; 6268f46eb0e9SDouglas Gilbert int hprot; 62691da177e4SLinus Torvalds 62701da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 62711da177e4SLinus Torvalds 6272773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 62732a3d4eb8SChristoph Hellwig if (!sdebug_clustering) 62744af14d11SChristoph Hellwig sdebug_driver_template.dma_boundary = PAGE_SIZE - 1; 62754af14d11SChristoph Hellwig 62761da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 62771da177e4SLinus Torvalds if (NULL == hpnt) { 6278c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 62791da177e4SLinus Torvalds error = -ENODEV; 62801da177e4SLinus Torvalds return error; 62811da177e4SLinus Torvalds } 6282c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 62839b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 6284c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 6285c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 6286c4837394SDouglas Gilbert } 6287c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 6288c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 6289c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 62901da177e4SLinus Torvalds 62911da177e4SLinus Torvalds sdbg_host->shost = hpnt; 62921da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 6293773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 6294773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 62951da177e4SLinus Torvalds else 6296773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 6297773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 6298f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 62991da177e4SLinus Torvalds 6300f46eb0e9SDouglas Gilbert hprot = 0; 6301c6a44287SMartin K. Petersen 6302773642d9SDouglas Gilbert switch (sdebug_dif) { 6303c6a44287SMartin K. Petersen 63048475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 6305f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 6306773642d9SDouglas Gilbert if (sdebug_dix) 6307f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 6308c6a44287SMartin K. Petersen break; 6309c6a44287SMartin K. Petersen 63108475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 6311f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 6312773642d9SDouglas Gilbert if (sdebug_dix) 6313f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 6314c6a44287SMartin K. Petersen break; 6315c6a44287SMartin K. Petersen 63168475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 6317f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 6318773642d9SDouglas Gilbert if (sdebug_dix) 6319f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 6320c6a44287SMartin K. Petersen break; 6321c6a44287SMartin K. Petersen 6322c6a44287SMartin K. Petersen default: 6323773642d9SDouglas Gilbert if (sdebug_dix) 6324f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 6325c6a44287SMartin K. Petersen break; 6326c6a44287SMartin K. Petersen } 6327c6a44287SMartin K. Petersen 6328f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 6329c6a44287SMartin K. Petersen 6330f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 6331c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 6332f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 6333f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 6334f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 6335f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 6336f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 6337f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 6338f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 6339c6a44287SMartin K. Petersen 6340773642d9SDouglas Gilbert if (sdebug_guard == 1) 6341c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 6342c6a44287SMartin K. Petersen else 6343c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 6344c6a44287SMartin K. Petersen 6345773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 6346773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 6347c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 6348c4837394SDouglas Gilbert sdebug_statistics = true; 63491da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 63501da177e4SLinus Torvalds if (error) { 6351c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 63521da177e4SLinus Torvalds error = -ENODEV; 63531da177e4SLinus Torvalds scsi_host_put(hpnt); 635487c715dcSDouglas Gilbert } else { 63551da177e4SLinus Torvalds scsi_scan_host(hpnt); 635687c715dcSDouglas Gilbert } 63571da177e4SLinus Torvalds 63581da177e4SLinus Torvalds return error; 63591da177e4SLinus Torvalds } 63601da177e4SLinus Torvalds 63611da177e4SLinus Torvalds static int sdebug_driver_remove(struct device *dev) 63621da177e4SLinus Torvalds { 63631da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 63648b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 63651da177e4SLinus Torvalds 63661da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 63671da177e4SLinus Torvalds 63681da177e4SLinus Torvalds if (!sdbg_host) { 6369c1287970STomas Winkler pr_err("Unable to locate host info\n"); 63701da177e4SLinus Torvalds return -ENODEV; 63711da177e4SLinus Torvalds } 63721da177e4SLinus Torvalds 63731da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 63741da177e4SLinus Torvalds 63758b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 63768b40228fSFUJITA Tomonori dev_list) { 63771da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 63781da177e4SLinus Torvalds kfree(sdbg_devinfo); 63791da177e4SLinus Torvalds } 63801da177e4SLinus Torvalds 63811da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 63821da177e4SLinus Torvalds return 0; 63831da177e4SLinus Torvalds } 63841da177e4SLinus Torvalds 63858dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 63868dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 63871da177e4SLinus Torvalds { 63888dea0d02SFUJITA Tomonori return 1; 63898dea0d02SFUJITA Tomonori } 63901da177e4SLinus Torvalds 63918dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 63928dea0d02SFUJITA Tomonori .name = "pseudo", 63938dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 63948dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 63958dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 639682069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 63978dea0d02SFUJITA Tomonori }; 6398