11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 9773642d9SDouglas Gilbert * Copyright (C) 2001 - 2016 Douglas Gilbert 101da177e4SLinus Torvalds * 11773642d9SDouglas Gilbert * This program is free software; you can redistribute it and/or modify 12773642d9SDouglas Gilbert * it under the terms of the GNU General Public License as published by 13773642d9SDouglas Gilbert * the Free Software Foundation; either version 2, or (at your option) 14773642d9SDouglas Gilbert * any later version. 151da177e4SLinus Torvalds * 1678d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 20c1287970STomas Winkler 21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 22c1287970STomas Winkler 231da177e4SLinus Torvalds #include <linux/module.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/kernel.h> 261da177e4SLinus Torvalds #include <linux/errno.h> 27b333a819SDouglas Gilbert #include <linux/jiffies.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/string.h> 311da177e4SLinus Torvalds #include <linux/genhd.h> 321da177e4SLinus Torvalds #include <linux/fs.h> 331da177e4SLinus Torvalds #include <linux/init.h> 341da177e4SLinus Torvalds #include <linux/proc_fs.h> 351da177e4SLinus Torvalds #include <linux/vmalloc.h> 361da177e4SLinus Torvalds #include <linux/moduleparam.h> 37852e034dSJens Axboe #include <linux/scatterlist.h> 381da177e4SLinus Torvalds #include <linux/blkdev.h> 39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 40cbf67842SDouglas Gilbert #include <linux/spinlock.h> 41cbf67842SDouglas Gilbert #include <linux/interrupt.h> 42cbf67842SDouglas Gilbert #include <linux/atomic.h> 43cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 4409ba24c1SDouglas Gilbert #include <linux/uuid.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 */ 63b01f6f83SDouglas Gilbert #define SDEBUG_VERSION "1.86" 64b01f6f83SDouglas Gilbert static const char *sdebug_version_date = "20160430"; 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 78cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 79cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8019c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8119c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8222017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8322017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 84cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 85cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 86cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8722017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 881da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 896f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 90c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 91c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9222017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 93acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 951da177e4SLinus Torvalds 966f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 976f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 986f3cbf55SDouglas Gilbert 991da177e4SLinus Torvalds /* Default values for driver parameters */ 1001da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1011da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1021da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1031da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1041da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1051da177e4SLinus Torvalds */ 1065b94e232SMartin K. Petersen #define DEF_ATO 1 107c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1081da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1095b94e232SMartin K. Petersen #define DEF_DIF 0 1105b94e232SMartin K. Petersen #define DEF_DIX 0 1115b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1121da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1135b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1145b94e232SMartin K. Petersen #define DEF_GUARD 0 115cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1165b94e232SMartin K. Petersen #define DEF_LBPU 0 1175b94e232SMartin K. Petersen #define DEF_LBPWS 0 1185b94e232SMartin K. Petersen #define DEF_LBPWS10 0 119be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1205b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 121cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1225b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1231da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1241da177e4SLinus Torvalds #define DEF_OPTS 0 12532c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1265b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 127b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 128d986788bSMartin Pitt #define DEF_REMOVABLE false 129760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1305b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1315b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1325b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1346014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1355b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1365b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1375b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 138c2248fc9SDouglas Gilbert #define DEF_STRICT 0 139c4837394SDouglas Gilbert #define DEF_STATISTICS false 140c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 14109ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 142c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1431da177e4SLinus Torvalds 144b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 145b01f6f83SDouglas Gilbert 146773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 147773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 148773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 149773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 150773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 151773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 152773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 153773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 154773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 155773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 156773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 157773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 158773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 159773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 160773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 161773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 162773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 163773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 164773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 165773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 166773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 167773642d9SDouglas Gilbert SDEBUG_OPT_SHORT_TRANSFER) 1681da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 169fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1701da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 171773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1726f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 173773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1741da177e4SLinus Torvalds * 1751da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 176fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1771da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 178773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1796f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 180773642d9SDouglas Gilbert * commands if _DEBUG_OPT_TRANSPORT_ERR is set. 181773642d9SDouglas Gilbert * This will continue on every subsequent command until some other action 182773642d9SDouglas Gilbert * occurs (e.g. the user * writing a new value (other than -1 or 1) to 183773642d9SDouglas Gilbert * every_nth via sysfs). 1841da177e4SLinus Torvalds */ 1851da177e4SLinus Torvalds 186cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 187cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 188cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 189cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 190cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 191cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 192cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1930d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 19419c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 195acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 196acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 197acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 198cbf67842SDouglas Gilbert 199773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2001da177e4SLinus Torvalds * sector on read commands: */ 2011da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 20232f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2031da177e4SLinus Torvalds 2041da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2051da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2061da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2071da177e4SLinus Torvalds 208c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 209c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 210c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 211c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 212c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 213c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 214c4837394SDouglas Gilbert */ 215c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 216c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 217cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 218cbf67842SDouglas Gilbert 219fd32119bSDouglas Gilbert #define F_D_IN 1 220fd32119bSDouglas Gilbert #define F_D_OUT 2 221fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 222fd32119bSDouglas Gilbert #define F_D_UNKN 8 223fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 224fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 225fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 226fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 227fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 228fd32119bSDouglas Gilbert #define F_INV_OP 0x200 229fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 230fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 231fd32119bSDouglas Gilbert 232fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 233fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 234fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 235fd32119bSDouglas Gilbert 236fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 237fd32119bSDouglas Gilbert 238b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 239fd32119bSDouglas Gilbert 240fd32119bSDouglas Gilbert 241fd32119bSDouglas Gilbert struct sdebug_dev_info { 242fd32119bSDouglas Gilbert struct list_head dev_list; 243fd32119bSDouglas Gilbert unsigned int channel; 244fd32119bSDouglas Gilbert unsigned int target; 245fd32119bSDouglas Gilbert u64 lun; 24609ba24c1SDouglas Gilbert uuid_be lu_name; 247fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 248fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 249fd32119bSDouglas Gilbert atomic_t num_in_q; 250c4837394SDouglas Gilbert atomic_t stopped; 251fd32119bSDouglas Gilbert bool used; 252fd32119bSDouglas Gilbert }; 253fd32119bSDouglas Gilbert 254fd32119bSDouglas Gilbert struct sdebug_host_info { 255fd32119bSDouglas Gilbert struct list_head host_list; 256fd32119bSDouglas Gilbert struct Scsi_Host *shost; 257fd32119bSDouglas Gilbert struct device dev; 258fd32119bSDouglas Gilbert struct list_head dev_info_list; 259fd32119bSDouglas Gilbert }; 260fd32119bSDouglas Gilbert 261fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 262fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 263fd32119bSDouglas Gilbert 264fd32119bSDouglas Gilbert struct sdebug_defer { 265fd32119bSDouglas Gilbert struct hrtimer hrt; 266fd32119bSDouglas Gilbert struct execute_work ew; 267c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 268c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 269c4837394SDouglas Gilbert int issuing_cpu; 270fd32119bSDouglas Gilbert }; 271fd32119bSDouglas Gilbert 272fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 273c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 274c4837394SDouglas Gilbert * instance indicates this slot is in use. 275c4837394SDouglas Gilbert */ 276fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 277fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 278c4837394SDouglas Gilbert unsigned int inj_recovered:1; 279c4837394SDouglas Gilbert unsigned int inj_transport:1; 280c4837394SDouglas Gilbert unsigned int inj_dif:1; 281c4837394SDouglas Gilbert unsigned int inj_dix:1; 282c4837394SDouglas Gilbert unsigned int inj_short:1; 283fd32119bSDouglas Gilbert }; 284fd32119bSDouglas Gilbert 285c4837394SDouglas Gilbert struct sdebug_queue { 286c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 287c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 288c4837394SDouglas Gilbert spinlock_t qc_lock; 289c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 290fd32119bSDouglas Gilbert }; 291fd32119bSDouglas Gilbert 292c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 293c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 294c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 295c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 296c4837394SDouglas Gilbert 297fd32119bSDouglas Gilbert struct opcode_info_t { 298b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 299b01f6f83SDouglas Gilbert /* for terminating element */ 300fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 301fd32119bSDouglas Gilbert u16 sa; /* service action */ 302fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 303fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 304fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 305fd32119bSDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 306fd32119bSDouglas Gilbert /* ignore cdb bytes after position 15 */ 307fd32119bSDouglas Gilbert }; 308fd32119bSDouglas Gilbert 309fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 310c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 311c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 312c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 313c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 314c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 315c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 316c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 317c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 318c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 319c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 320c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 321c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 322c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 323c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 324c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 325c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 326c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 327c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 328c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 329c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 330c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 331c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 332c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 333c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 334c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 335c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 336c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 337c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 338c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 339c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 340c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 341c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 342c2248fc9SDouglas Gilbert }; 343c2248fc9SDouglas Gilbert 344c4837394SDouglas Gilbert 345c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 346c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 347c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 348c2248fc9SDouglas Gilbert 0, 0, 0, 0, 349c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 350c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 351c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 352c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 353c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 354c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 355c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 356c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 357c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 358c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 359c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 360c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 361c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 362c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 363c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 364c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 365fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 366c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 368c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 369c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 370c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 371c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 372c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 373c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 374c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 375c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 376c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 377c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 378c2248fc9SDouglas Gilbert 0, 0, 0, 0, 379c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 380c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 381c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 382c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 383c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 384c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386c2248fc9SDouglas Gilbert }; 387c2248fc9SDouglas Gilbert 388c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 389c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 390c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 391c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 392c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 393c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 394c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 395c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 396c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 397c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 398c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 399c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 400c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 401c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 40238d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 40338d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 404c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 405c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 406c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 40738d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 408acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 409c2248fc9SDouglas Gilbert 410c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 411c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 412c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 413c2248fc9SDouglas Gilbert }; 414c2248fc9SDouglas Gilbert 415c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 416c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 417c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 418c2248fc9SDouglas Gilbert }; 419c2248fc9SDouglas Gilbert 420c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 421c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 422c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 423c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 424c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 425c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 426c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 427c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 428c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 429c2248fc9SDouglas Gilbert }; 430c2248fc9SDouglas Gilbert 431c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 432c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 433c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 434c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 435c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 436c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 437c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 438c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 439c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 440c2248fc9SDouglas Gilbert }; 441c2248fc9SDouglas Gilbert 442c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 443c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 444c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 445c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 446c2248fc9SDouglas Gilbert }; 447c2248fc9SDouglas Gilbert 448c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 449c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 450c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 451c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 452c2248fc9SDouglas Gilbert }; 453c2248fc9SDouglas Gilbert 454c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 45538d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 456c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 457c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 45838d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 459c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 460c2248fc9SDouglas Gilbert 0, 0} }, 461c2248fc9SDouglas Gilbert }; 462c2248fc9SDouglas Gilbert 463c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 464c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 465c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 466c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 467c2248fc9SDouglas Gilbert }; 468c2248fc9SDouglas Gilbert 469c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 470c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 471c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 472c2248fc9SDouglas Gilbert }; 473c2248fc9SDouglas Gilbert 474c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 475c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 476c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 477c2248fc9SDouglas Gilbert }; 478c2248fc9SDouglas Gilbert 479c2248fc9SDouglas Gilbert 480c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 481c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 482c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 483c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 484c2248fc9SDouglas Gilbert /* 0 */ 485c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 486c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 487c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 488c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 489c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 490c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 491c2248fc9SDouglas Gilbert 0, 0} }, 492c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 493c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 494c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 495c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 496c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 497c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 498c2248fc9SDouglas Gilbert 0} }, 499c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 500c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 501c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 502c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 503c2248fc9SDouglas Gilbert 0, 0, 0} }, 504c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 505c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 506c2248fc9SDouglas Gilbert 0, 0} }, 507c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 508c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 509c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 510c2248fc9SDouglas Gilbert /* 10 */ 511c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 512c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 513c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 514c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 515c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 516c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 517c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 518c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 519c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 520c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 521c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 522c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 523c2248fc9SDouglas Gilbert 0} }, 524c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 525c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 526f7f9f26bSDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ 527f7f9f26bSDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 528f7f9f26bSDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 529c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 530c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 531c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 532c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 533c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 534c2248fc9SDouglas Gilbert 0} }, 535c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 536c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 537c2248fc9SDouglas Gilbert 0} }, 538c2248fc9SDouglas Gilbert /* 20 */ 539f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 540f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 541c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 542c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 543c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 544c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 545c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 546c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 547c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 548c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 549c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 550c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 551c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 552acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 553acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 554acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 555c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 556c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 557c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 558c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 559c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 560c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 56138d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 562c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 563c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 564c2248fc9SDouglas Gilbert 565c2248fc9SDouglas Gilbert /* 30 */ 566c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 567c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 568c2248fc9SDouglas Gilbert }; 569c2248fc9SDouglas Gilbert 570773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; 571773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 572c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 573773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 574773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 575773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 576773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 577773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 578773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 579773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 580773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 581773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 582c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 583cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 584c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 585773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 586773642d9SDouglas Gilbert static int sdebug_no_uld; 587773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 588773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 589773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 590773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 591773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 592b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 593773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 594773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 595773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 596773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 597773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 598773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 599773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 600773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 601773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 602773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 603773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 604773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 605773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 60609ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 607773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 608773642d9SDouglas Gilbert static bool sdebug_clustering; 609773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 610773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 611817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 612773642d9SDouglas Gilbert static bool sdebug_verbose; 613f46eb0e9SDouglas Gilbert static bool have_dif_prot; 614c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 615c4837394SDouglas Gilbert static bool sdebug_mq_active; 6161da177e4SLinus Torvalds 617c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 6181da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 6191da177e4SLinus Torvalds 6201da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 6211da177e4SLinus Torvalds may still need them */ 6221da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 6231da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 6241da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 6251da177e4SLinus Torvalds 6261da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 6271da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds static unsigned char *fake_storep; /* ramdisk storage */ 630e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep; /* protection info */ 63144d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6321da177e4SLinus Torvalds 63344d92694SMartin K. Petersen static unsigned long map_size; 634cbf67842SDouglas Gilbert static int num_aborts; 635cbf67842SDouglas Gilbert static int num_dev_resets; 636cbf67842SDouglas Gilbert static int num_target_resets; 637cbf67842SDouglas Gilbert static int num_bus_resets; 638cbf67842SDouglas Gilbert static int num_host_resets; 639c6a44287SMartin K. Petersen static int dix_writes; 640c6a44287SMartin K. Petersen static int dix_reads; 641c6a44287SMartin K. Petersen static int dif_errors; 6421da177e4SLinus Torvalds 643c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 644c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 645fd32119bSDouglas Gilbert 6461da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6471da177e4SLinus Torvalds 648cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 649cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6521da177e4SLinus Torvalds 6531da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6541da177e4SLinus Torvalds .name = sdebug_proc_name, 6551da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6561da177e4SLinus Torvalds }; 6571da177e4SLinus Torvalds 6581da177e4SLinus Torvalds static const int check_condition_result = 6591da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6601da177e4SLinus Torvalds 661c6a44287SMartin K. Petersen static const int illegal_condition_result = 662c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 663c6a44287SMartin K. Petersen 664cbf67842SDouglas Gilbert static const int device_qfull_result = 665cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 666cbf67842SDouglas Gilbert 667fd32119bSDouglas Gilbert 668760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 669760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 670760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 671760f3b03SDouglas Gilbert */ 672760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 673fd32119bSDouglas Gilbert { 674fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 675fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 676fd32119bSDouglas Gilbert } 677c65b1445SDouglas Gilbert 67814faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 67914faa944SAkinobu Mita { 68014faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 68114faa944SAkinobu Mita 682773642d9SDouglas Gilbert return fake_storep + lba * sdebug_sector_size; 68314faa944SAkinobu Mita } 68414faa944SAkinobu Mita 68514faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector) 68614faa944SAkinobu Mita { 68749413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 68814faa944SAkinobu Mita 68914faa944SAkinobu Mita return dif_storep + sector; 69014faa944SAkinobu Mita } 69114faa944SAkinobu Mita 6928dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 6938dea0d02SFUJITA Tomonori { 6948dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 6958dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 6968dea0d02SFUJITA Tomonori 6978dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 6988dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 6998dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 7008dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 701773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 702773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 7038dea0d02SFUJITA Tomonori else 704773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 705773642d9SDouglas Gilbert /* sdebug_max_luns; */ 706f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 7078dea0d02SFUJITA Tomonori } 7088dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 7098dea0d02SFUJITA Tomonori } 7108dea0d02SFUJITA Tomonori 71122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 71222017ed2SDouglas Gilbert 71322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 714fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 715fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 71622017ed2SDouglas Gilbert int in_byte, int in_bit) 71722017ed2SDouglas Gilbert { 71822017ed2SDouglas Gilbert unsigned char *sbuff; 71922017ed2SDouglas Gilbert u8 sks[4]; 72022017ed2SDouglas Gilbert int sl, asc; 72122017ed2SDouglas Gilbert 72222017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 72322017ed2SDouglas Gilbert if (!sbuff) { 72422017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 72522017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 72622017ed2SDouglas Gilbert return; 72722017ed2SDouglas Gilbert } 72822017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 72922017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 730773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 73122017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 73222017ed2SDouglas Gilbert sks[0] = 0x80; 73322017ed2SDouglas Gilbert if (c_d) 73422017ed2SDouglas Gilbert sks[0] |= 0x40; 73522017ed2SDouglas Gilbert if (in_bit >= 0) { 73622017ed2SDouglas Gilbert sks[0] |= 0x8; 73722017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 73822017ed2SDouglas Gilbert } 73922017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 740773642d9SDouglas Gilbert if (sdebug_dsense) { 74122017ed2SDouglas Gilbert sl = sbuff[7] + 8; 74222017ed2SDouglas Gilbert sbuff[7] = sl; 74322017ed2SDouglas Gilbert sbuff[sl] = 0x2; 74422017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 74522017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 74622017ed2SDouglas Gilbert } else 74722017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 748773642d9SDouglas Gilbert if (sdebug_verbose) 74922017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 75022017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 75122017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 75222017ed2SDouglas Gilbert } 75322017ed2SDouglas Gilbert 754cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7558dea0d02SFUJITA Tomonori { 7568dea0d02SFUJITA Tomonori unsigned char *sbuff; 7578dea0d02SFUJITA Tomonori 758cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 759cbf67842SDouglas Gilbert if (!sbuff) { 760cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 761cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 762cbf67842SDouglas Gilbert return; 763cbf67842SDouglas Gilbert } 764cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7658dea0d02SFUJITA Tomonori 766773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 7678dea0d02SFUJITA Tomonori 768773642d9SDouglas Gilbert if (sdebug_verbose) 769cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 770cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 771cbf67842SDouglas Gilbert my_name, key, asc, asq); 7728dea0d02SFUJITA Tomonori } 7731da177e4SLinus Torvalds 774fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 77522017ed2SDouglas Gilbert { 77622017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 77722017ed2SDouglas Gilbert } 77822017ed2SDouglas Gilbert 7791da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7801da177e4SLinus Torvalds { 781773642d9SDouglas Gilbert if (sdebug_verbose) { 782cbf67842SDouglas Gilbert if (0x1261 == cmd) 783cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 784cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 785cbf67842SDouglas Gilbert else if (0x5331 == cmd) 786cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 787cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 788cbf67842SDouglas Gilbert __func__); 789cbf67842SDouglas Gilbert else 790cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 791cbf67842SDouglas Gilbert __func__, cmd); 7921da177e4SLinus Torvalds } 7931da177e4SLinus Torvalds return -EINVAL; 7941da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds 79719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 79819c8ead7SEwan D. Milne { 79919c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 80019c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 80119c8ead7SEwan D. Milne 80219c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 80319c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 80419c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 80519c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 80619c8ead7SEwan D. Milne (devip->target == dp->target)) 80719c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 80819c8ead7SEwan D. Milne } 80919c8ead7SEwan D. Milne } 81019c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 81119c8ead7SEwan D. Milne } 81219c8ead7SEwan D. Milne 813f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 8141da177e4SLinus Torvalds { 815cbf67842SDouglas Gilbert int k; 816cbf67842SDouglas Gilbert 817cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 818cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 819cbf67842SDouglas Gilbert const char *cp = NULL; 820cbf67842SDouglas Gilbert 821cbf67842SDouglas Gilbert switch (k) { 822cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 823f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 824f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 825773642d9SDouglas Gilbert if (sdebug_verbose) 826cbf67842SDouglas Gilbert cp = "power on reset"; 827cbf67842SDouglas Gilbert break; 828cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 829f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 830f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 831773642d9SDouglas Gilbert if (sdebug_verbose) 832cbf67842SDouglas Gilbert cp = "bus reset"; 833cbf67842SDouglas Gilbert break; 834cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 835f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 836f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 837773642d9SDouglas Gilbert if (sdebug_verbose) 838cbf67842SDouglas Gilbert cp = "mode parameters changed"; 839cbf67842SDouglas Gilbert break; 8400d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 841f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 842f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 843773642d9SDouglas Gilbert if (sdebug_verbose) 8440d01c5dfSDouglas Gilbert cp = "capacity data changed"; 845f49accf1SEwan D. Milne break; 846acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 847f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 848b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 849b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 850773642d9SDouglas Gilbert if (sdebug_verbose) 851acafd0b9SEwan D. Milne cp = "microcode has been changed"; 852acafd0b9SEwan D. Milne break; 853acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 854f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 855acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 856acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 857773642d9SDouglas Gilbert if (sdebug_verbose) 858acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 859acafd0b9SEwan D. Milne break; 86019c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 86119c8ead7SEwan D. Milne /* 86219c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 86319c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 86419c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 86519c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 866773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 86719c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 86819c8ead7SEwan D. Milne */ 869773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 87019c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 871f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 87219c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 87319c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 874773642d9SDouglas Gilbert if (sdebug_verbose) 87519c8ead7SEwan D. Milne cp = "reported luns data has changed"; 87619c8ead7SEwan D. Milne break; 877cbf67842SDouglas Gilbert default: 878773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 879773642d9SDouglas Gilbert if (sdebug_verbose) 880cbf67842SDouglas Gilbert cp = "unknown"; 881cbf67842SDouglas Gilbert break; 882cbf67842SDouglas Gilbert } 883cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 884773642d9SDouglas Gilbert if (sdebug_verbose) 885f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 886cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 887cbf67842SDouglas Gilbert my_name, cp); 8881da177e4SLinus Torvalds return check_condition_result; 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds return 0; 8911da177e4SLinus Torvalds } 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 8941da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 8951da177e4SLinus Torvalds int arr_len) 8961da177e4SLinus Torvalds { 89721a61829SFUJITA Tomonori int act_len; 898072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 8991da177e4SLinus Torvalds 900072d0bb3SFUJITA Tomonori if (!sdb->length) 9011da177e4SLinus Torvalds return 0; 902072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 903773642d9SDouglas Gilbert return DID_ERROR << 16; 90421a61829SFUJITA Tomonori 90521a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 90621a61829SFUJITA Tomonori arr, arr_len); 90721a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 90821a61829SFUJITA Tomonori 9091da177e4SLinus Torvalds return 0; 9101da177e4SLinus Torvalds } 9111da177e4SLinus Torvalds 9121da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 9131da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 91421a61829SFUJITA Tomonori int arr_len) 9151da177e4SLinus Torvalds { 91621a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 9171da177e4SLinus Torvalds return 0; 918072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 9191da177e4SLinus Torvalds return -1; 92021a61829SFUJITA Tomonori 92121a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 9221da177e4SLinus Torvalds } 9231da177e4SLinus Torvalds 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 9261da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 927773642d9SDouglas Gilbert static const char *inq_product_rev = "0186"; /* version less '.' */ 928773642d9SDouglas Gilbert static const u64 naa5_comp_a = 0x5222222000000000ULL; 929773642d9SDouglas Gilbert static const u64 naa5_comp_b = 0x5333333000000000ULL; 930773642d9SDouglas Gilbert static const u64 naa5_comp_c = 0x5111111000000000ULL; 9311da177e4SLinus Torvalds 932cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 933760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 9345a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 93509ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 93609ba24c1SDouglas Gilbert const uuid_be *lu_name) 9371da177e4SLinus Torvalds { 938c65b1445SDouglas Gilbert int num, port_a; 939c65b1445SDouglas Gilbert char b[32]; 9401da177e4SLinus Torvalds 941c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 9421da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 9431da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 9441da177e4SLinus Torvalds arr[1] = 0x1; 9451da177e4SLinus Torvalds arr[2] = 0x0; 9461da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 9471da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 9481da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 9491da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9501da177e4SLinus Torvalds arr[3] = num; 9511da177e4SLinus Torvalds num += 4; 952c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 95309ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 95409ba24c1SDouglas Gilbert /* Locally assigned UUID */ 95509ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 95609ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 95709ba24c1SDouglas Gilbert arr[num++] = 0x0; 95809ba24c1SDouglas Gilbert arr[num++] = 0x12; 95909ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 96009ba24c1SDouglas Gilbert arr[num++] = 0x0; 96109ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 96209ba24c1SDouglas Gilbert num += 16; 96309ba24c1SDouglas Gilbert } else { 964c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 965c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 966c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 967c65b1445SDouglas Gilbert arr[num++] = 0x0; 968c65b1445SDouglas Gilbert arr[num++] = 0x8; 969773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num); 970773642d9SDouglas Gilbert num += 8; 97109ba24c1SDouglas Gilbert } 972c65b1445SDouglas Gilbert /* Target relative port number */ 973c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 974c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 975c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 976c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 977c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 978c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 979c65b1445SDouglas Gilbert arr[num++] = 0x0; 980c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 981c65b1445SDouglas Gilbert } 982c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 983c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 984c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 985c65b1445SDouglas Gilbert arr[num++] = 0x0; 986c65b1445SDouglas Gilbert arr[num++] = 0x8; 987773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_a, arr + num); 988773642d9SDouglas Gilbert num += 8; 9895a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 9905a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 9915a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 9925a09e398SHannes Reinecke arr[num++] = 0x0; 9935a09e398SHannes Reinecke arr[num++] = 0x4; 9945a09e398SHannes Reinecke arr[num++] = 0; 9955a09e398SHannes Reinecke arr[num++] = 0; 996773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 997773642d9SDouglas Gilbert num += 2; 998c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 999c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1000c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1001c65b1445SDouglas Gilbert arr[num++] = 0x0; 1002c65b1445SDouglas Gilbert arr[num++] = 0x8; 1003773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num); 1004773642d9SDouglas Gilbert num += 8; 1005c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1006c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1007c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1008c65b1445SDouglas Gilbert arr[num++] = 0x0; 1009c65b1445SDouglas Gilbert arr[num++] = 24; 1010c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 1011c65b1445SDouglas Gilbert num += 12; 1012c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1013c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1014c65b1445SDouglas Gilbert num += 8; 1015c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1016c65b1445SDouglas Gilbert num += 4; 1017c65b1445SDouglas Gilbert return num; 1018c65b1445SDouglas Gilbert } 1019c65b1445SDouglas Gilbert 1020c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1021c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1022c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1023c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1024c65b1445SDouglas Gilbert }; 1025c65b1445SDouglas Gilbert 1026cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1027760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1028c65b1445SDouglas Gilbert { 1029c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1030c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1031c65b1445SDouglas Gilbert } 1032c65b1445SDouglas Gilbert 1033cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1034760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1035c65b1445SDouglas Gilbert { 1036c65b1445SDouglas Gilbert int num = 0; 1037c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1038c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1039c65b1445SDouglas Gilbert int plen, olen; 1040c65b1445SDouglas Gilbert 1041c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1042c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1043c65b1445SDouglas Gilbert arr[num++] = 0x0; 1044c65b1445SDouglas Gilbert olen = strlen(na1); 1045c65b1445SDouglas Gilbert plen = olen + 1; 1046c65b1445SDouglas Gilbert if (plen % 4) 1047c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1048c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1049c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1050c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1051c65b1445SDouglas Gilbert num += plen; 1052c65b1445SDouglas Gilbert 1053c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1054c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1055c65b1445SDouglas Gilbert arr[num++] = 0x0; 1056c65b1445SDouglas Gilbert olen = strlen(na2); 1057c65b1445SDouglas Gilbert plen = olen + 1; 1058c65b1445SDouglas Gilbert if (plen % 4) 1059c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1060c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1061c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1062c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1063c65b1445SDouglas Gilbert num += plen; 1064c65b1445SDouglas Gilbert 1065c65b1445SDouglas Gilbert return num; 1066c65b1445SDouglas Gilbert } 1067c65b1445SDouglas Gilbert 1068c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1069760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1070c65b1445SDouglas Gilbert { 1071c65b1445SDouglas Gilbert int num = 0; 1072c65b1445SDouglas Gilbert int port_a, port_b; 1073c65b1445SDouglas Gilbert 1074c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1075c65b1445SDouglas Gilbert port_b = port_a + 1; 1076c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1077c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1078c65b1445SDouglas Gilbert arr[num++] = 0x0; 1079c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1080c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1081c65b1445SDouglas Gilbert num += 6; 1082c65b1445SDouglas Gilbert arr[num++] = 0x0; 1083c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1084c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1085c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1086c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1087c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1088c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1089773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_a, arr + num); 1090773642d9SDouglas Gilbert num += 8; 1091c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1092c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1093c65b1445SDouglas Gilbert arr[num++] = 0x0; 1094c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1095c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1096c65b1445SDouglas Gilbert num += 6; 1097c65b1445SDouglas Gilbert arr[num++] = 0x0; 1098c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1099c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1100c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1101c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1102c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1103c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1104773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_b, arr + num); 1105773642d9SDouglas Gilbert num += 8; 1106c65b1445SDouglas Gilbert 1107c65b1445SDouglas Gilbert return num; 1108c65b1445SDouglas Gilbert } 1109c65b1445SDouglas Gilbert 1110c65b1445SDouglas Gilbert 1111c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1112c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1113c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1114c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1115c65b1445SDouglas Gilbert '1','2','3','4', 1116c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1117c65b1445SDouglas Gilbert 0xec,0,0,0, 1118c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1119c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1120c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1121c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1122c65b1445SDouglas Gilbert 0x53,0x41, 1123c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1124c65b1445SDouglas Gilbert 0x20,0x20, 1125c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1126c65b1445SDouglas Gilbert 0x10,0x80, 1127c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1128c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1129c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1130c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1131c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1132c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1133c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1134c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1135c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1136c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1137c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1138c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1139c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1140c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1141c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1142c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1143c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1144c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1145c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1146c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1147c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1148c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1149c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1150c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1151c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1152c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1153c65b1445SDouglas Gilbert }; 1154c65b1445SDouglas Gilbert 1155cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1156760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1157c65b1445SDouglas Gilbert { 1158c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1159c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1160c65b1445SDouglas Gilbert } 1161c65b1445SDouglas Gilbert 1162c65b1445SDouglas Gilbert 1163c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11641e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 11651e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11661e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11671e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1168c65b1445SDouglas Gilbert }; 1169c65b1445SDouglas Gilbert 1170cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1171760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1172c65b1445SDouglas Gilbert { 1173ea61fca5SMartin K. Petersen unsigned int gran; 1174ea61fca5SMartin K. Petersen 1175c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1176e308b3d1SMartin K. Petersen 1177e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 1178773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1179773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1180e308b3d1SMartin K. Petersen 1181e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1182773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1183773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 118444d92694SMartin K. Petersen 1185e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1186773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1187e308b3d1SMartin K. Petersen 1188773642d9SDouglas Gilbert if (sdebug_lbpu) { 1189e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1190773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1191e308b3d1SMartin K. Petersen 1192e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1193773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 119444d92694SMartin K. Petersen } 119544d92694SMartin K. Petersen 1196e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1197773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1198773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 119944d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 120044d92694SMartin K. Petersen } 120144d92694SMartin K. Petersen 1202e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1203773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 12046014759cSMartin K. Petersen 12055b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1206773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 12075b94e232SMartin K. Petersen 12085b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 120944d92694SMartin K. Petersen 1210c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 12111da177e4SLinus Torvalds } 12121da177e4SLinus Torvalds 12131e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1214760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1215eac6e8e4SMatthew Wilcox { 1216eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1217eac6e8e4SMatthew Wilcox arr[0] = 0; 12181e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 12191e49f785SDouglas Gilbert arr[2] = 0; 12201e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1221eac6e8e4SMatthew Wilcox 1222eac6e8e4SMatthew Wilcox return 0x3c; 1223eac6e8e4SMatthew Wilcox } 12241da177e4SLinus Torvalds 1225760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1226760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 12276014759cSMartin K. Petersen { 12283f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 12296014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1230773642d9SDouglas Gilbert if (sdebug_lbpu) 12316014759cSMartin K. Petersen arr[1] = 1 << 7; 1232773642d9SDouglas Gilbert if (sdebug_lbpws) 12336014759cSMartin K. Petersen arr[1] |= 1 << 6; 1234773642d9SDouglas Gilbert if (sdebug_lbpws10) 12355b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1236760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1237760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1238760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1239760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1240760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 12413f0bc3b3SMartin K. Petersen return 0x4; 12426014759cSMartin K. Petersen } 12436014759cSMartin K. Petersen 12441da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1245c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12461da177e4SLinus Torvalds 1247c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12481da177e4SLinus Torvalds { 12491da177e4SLinus Torvalds unsigned char pq_pdt; 12505a09e398SHannes Reinecke unsigned char * arr; 125101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12525a09e398SHannes Reinecke int alloc_len, n, ret; 1253760f3b03SDouglas Gilbert bool have_wlun, is_disk; 12541da177e4SLinus Torvalds 1255773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 12566f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12576f3cbf55SDouglas Gilbert if (! arr) 12586f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1259760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1260b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1261c2248fc9SDouglas Gilbert if (have_wlun) 1262b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1263b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1264b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1265c65b1445SDouglas Gilbert else 1266773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 12671da177e4SLinus Torvalds arr[0] = pq_pdt; 12681da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 126922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 12705a09e398SHannes Reinecke kfree(arr); 12711da177e4SLinus Torvalds return check_condition_result; 12721da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 12735a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1274c65b1445SDouglas Gilbert char lu_id_str[6]; 1275c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 12761da177e4SLinus Torvalds 12775a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 12785a09e398SHannes Reinecke (devip->channel & 0x7f); 1279b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 128023183910SDouglas Gilbert host_no = 0; 1281c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1282c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1283c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1284c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1285c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 12861da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1287c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1288c65b1445SDouglas Gilbert n = 4; 1289c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1290c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1291c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1292c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1293c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1294c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1295c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1296c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1297760f3b03SDouglas Gilbert if (is_disk) { /* SBC only */ 1298c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1299760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1300760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1301760f3b03SDouglas Gilbert arr[n++] = 0xb2; /* Logical Block Prov */ 1302760f3b03SDouglas Gilbert } 1303c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 13041da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1305c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 13061da177e4SLinus Torvalds arr[3] = len; 1307c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 13081da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1309c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1310760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 13115a09e398SHannes Reinecke target_dev_id, lu_id_num, 131209ba24c1SDouglas Gilbert lu_id_str, len, 131309ba24c1SDouglas Gilbert &devip->lu_name); 1314c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1315c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1316760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1317c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1318c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1319760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1320c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1321c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1322c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1323773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE3_PROTECTION) 1324c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1325760f3b03SDouglas Gilbert else if (have_dif_prot) 1326c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1327c6a44287SMartin K. Petersen else 1328c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1329c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1330c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1331c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1332c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1333c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1334c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1335c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1336c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1337c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1338c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1339760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1340760f3b03SDouglas Gilbert } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ 1341c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1342760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1343773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1344760f3b03SDouglas Gilbert } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ 1345c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1346760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1347760f3b03SDouglas Gilbert } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ 1348eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1349760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1350760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 13516014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1352760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 13531da177e4SLinus Torvalds } else { 135422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13555a09e398SHannes Reinecke kfree(arr); 13561da177e4SLinus Torvalds return check_condition_result; 13571da177e4SLinus Torvalds } 1358773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 13595a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1360c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13615a09e398SHannes Reinecke kfree(arr); 13625a09e398SHannes Reinecke return ret; 13631da177e4SLinus Torvalds } 13641da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1365773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1366773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 13671da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 13681da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1369f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1370b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 13715a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1372c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 13731da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1374c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 13751da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 13761da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 13771da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 13781da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1379760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1380760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1381c65b1445SDouglas Gilbert n = 62; 1382760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1383760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1384760f3b03SDouglas Gilbert n += 2; 1385760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1386760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1387760f3b03SDouglas Gilbert n += 2; 13881da177e4SLinus Torvalds } 1389760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 13905a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 13911da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 13925a09e398SHannes Reinecke kfree(arr); 13935a09e398SHannes Reinecke return ret; 13941da177e4SLinus Torvalds } 13951da177e4SLinus Torvalds 1396fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1397fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1398fd32119bSDouglas Gilbert 13991da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 14001da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14011da177e4SLinus Torvalds { 14021da177e4SLinus Torvalds unsigned char * sbuff; 140301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1404cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 14052492fc09STomas Winkler bool dsense; 14061da177e4SLinus Torvalds int len = 18; 14071da177e4SLinus Torvalds 1408c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1409c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1410cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1411c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1412c2248fc9SDouglas Gilbert if (dsense) { 1413c65b1445SDouglas Gilbert arr[0] = 0x72; 1414c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1415c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1416c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1417c2248fc9SDouglas Gilbert len = 8; 1418c65b1445SDouglas Gilbert } else { 1419c65b1445SDouglas Gilbert arr[0] = 0x70; 1420c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1421c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1422c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1423c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1424c65b1445SDouglas Gilbert } 1425c65b1445SDouglas Gilbert } else { 1426cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1427773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1428c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1429c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1430c2248fc9SDouglas Gilbert if (dsense) { 1431c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1432c2248fc9SDouglas Gilbert arr[0] = 0x72; 1433c2248fc9SDouglas Gilbert len = 8; 1434c2248fc9SDouglas Gilbert } else { 1435c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1436c2248fc9SDouglas Gilbert arr[0] = 0x70; 1437c2248fc9SDouglas Gilbert arr[7] = 0xa; 1438c2248fc9SDouglas Gilbert } 1439c2248fc9SDouglas Gilbert } else if (dsense) { 1440c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14411da177e4SLinus Torvalds arr[0] = 0x72; 14421da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14431da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14441da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14451da177e4SLinus Torvalds len = 8; 1446c2248fc9SDouglas Gilbert } else { 1447c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1448c2248fc9SDouglas Gilbert arr[0] = 0x70; 1449c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1450c2248fc9SDouglas Gilbert arr[7] = 0xa; 1451c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1452c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1453c65b1445SDouglas Gilbert } 1454c2248fc9SDouglas Gilbert 1455c65b1445SDouglas Gilbert } 1456cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14571da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14581da177e4SLinus Torvalds } 14591da177e4SLinus Torvalds 1460c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1461c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1462c65b1445SDouglas Gilbert { 146301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1464c4837394SDouglas Gilbert int power_cond, stop; 1465c65b1445SDouglas Gilbert 1466c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1467c65b1445SDouglas Gilbert if (power_cond) { 146822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1469c65b1445SDouglas Gilbert return check_condition_result; 1470c65b1445SDouglas Gilbert } 1471c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 1472c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 1473c65b1445SDouglas Gilbert return 0; 1474c65b1445SDouglas Gilbert } 1475c65b1445SDouglas Gilbert 147628898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 147728898873SFUJITA Tomonori { 1478773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1479773642d9SDouglas Gilbert 1480773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1481773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1482773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 148328898873SFUJITA Tomonori else 148428898873SFUJITA Tomonori return sdebug_store_sectors; 148528898873SFUJITA Tomonori } 148628898873SFUJITA Tomonori 14871da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 14881da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 14891da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14901da177e4SLinus Torvalds { 14911da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1492c65b1445SDouglas Gilbert unsigned int capac; 14931da177e4SLinus Torvalds 1494c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 149528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 14961da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1497c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1498c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1499773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1500773642d9SDouglas Gilbert } else 1501773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1502773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 15031da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 15041da177e4SLinus Torvalds } 15051da177e4SLinus Torvalds 1506c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1507c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1508c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1509c65b1445SDouglas Gilbert { 151001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1511c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1512773642d9SDouglas Gilbert int alloc_len; 1513c65b1445SDouglas Gilbert 1514773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1515c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 151628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1517c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1518773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1519773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1520773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1521773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 152244d92694SMartin K. Petersen 1523be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 15245b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1525760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1526760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1527760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1528760f3b03SDouglas Gilbert */ 1529760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1530760f3b03SDouglas Gilbert arr[14] |= 0x40; 1531be1dd78dSEric Sandeen } 153244d92694SMartin K. Petersen 1533773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1534c6a44287SMartin K. Petersen 1535760f3b03SDouglas Gilbert if (have_dif_prot) { 1536773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1537c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1538c6a44287SMartin K. Petersen } 1539c6a44287SMartin K. Petersen 1540c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1541c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1542c65b1445SDouglas Gilbert } 1543c65b1445SDouglas Gilbert 15445a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15455a09e398SHannes Reinecke 15465a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15475a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15485a09e398SHannes Reinecke { 154901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15505a09e398SHannes Reinecke unsigned char * arr; 15515a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15525a09e398SHannes Reinecke int n, ret, alen, rlen; 15535a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15545a09e398SHannes Reinecke 1555773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 15566f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15576f3cbf55SDouglas Gilbert if (! arr) 15586f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15595a09e398SHannes Reinecke /* 15605a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 15615a09e398SHannes Reinecke * real and a fake port with no device connected. 15625a09e398SHannes Reinecke * So we create two port groups with one port each 15635a09e398SHannes Reinecke * and set the group with port B to unavailable. 15645a09e398SHannes Reinecke */ 15655a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 15665a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 15675a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 15685a09e398SHannes Reinecke (devip->channel & 0x7f); 15695a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 15705a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 15715a09e398SHannes Reinecke 15725a09e398SHannes Reinecke /* 15735a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 15745a09e398SHannes Reinecke */ 15755a09e398SHannes Reinecke n = 4; 1576b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 15775a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 15785a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 15795a09e398SHannes Reinecke } else { 15805a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1581773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 15825a09e398SHannes Reinecke } 1583773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1584773642d9SDouglas Gilbert n += 2; 15855a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15865a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15875a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15885a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15895a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15905a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1591773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1592773642d9SDouglas Gilbert n += 2; 15935a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 15945a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1595773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1596773642d9SDouglas Gilbert n += 2; 15975a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15985a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15995a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16005a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16015a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16025a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1603773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1604773642d9SDouglas Gilbert n += 2; 16055a09e398SHannes Reinecke 16065a09e398SHannes Reinecke rlen = n - 4; 1607773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 16085a09e398SHannes Reinecke 16095a09e398SHannes Reinecke /* 16105a09e398SHannes Reinecke * Return the smallest value of either 16115a09e398SHannes Reinecke * - The allocated length 16125a09e398SHannes Reinecke * - The constructed command length 16135a09e398SHannes Reinecke * - The maximum array size 16145a09e398SHannes Reinecke */ 16155a09e398SHannes Reinecke rlen = min(alen,n); 16165a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 16175a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 16185a09e398SHannes Reinecke kfree(arr); 16195a09e398SHannes Reinecke return ret; 16205a09e398SHannes Reinecke } 16215a09e398SHannes Reinecke 1622fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1623fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 162438d5c833SDouglas Gilbert { 162538d5c833SDouglas Gilbert bool rctd; 162638d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 162738d5c833SDouglas Gilbert u16 req_sa, u; 162838d5c833SDouglas Gilbert u32 alloc_len, a_len; 162938d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 163038d5c833SDouglas Gilbert const struct opcode_info_t *oip; 163138d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 163238d5c833SDouglas Gilbert u8 *arr; 163338d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 163438d5c833SDouglas Gilbert 163538d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 163638d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 163738d5c833SDouglas Gilbert req_opcode = cmd[3]; 163838d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 163938d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16406d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 164138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 164238d5c833SDouglas Gilbert return check_condition_result; 164338d5c833SDouglas Gilbert } 164438d5c833SDouglas Gilbert if (alloc_len > 8192) 164538d5c833SDouglas Gilbert a_len = 8192; 164638d5c833SDouglas Gilbert else 164738d5c833SDouglas Gilbert a_len = alloc_len; 164899531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 164938d5c833SDouglas Gilbert if (NULL == arr) { 165038d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 165138d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 165238d5c833SDouglas Gilbert return check_condition_result; 165338d5c833SDouglas Gilbert } 165438d5c833SDouglas Gilbert switch (reporting_opts) { 165538d5c833SDouglas Gilbert case 0: /* all commands */ 165638d5c833SDouglas Gilbert /* count number of commands */ 165738d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 165838d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 165938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 166038d5c833SDouglas Gilbert continue; 166138d5c833SDouglas Gilbert count += (oip->num_attached + 1); 166238d5c833SDouglas Gilbert } 166338d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 166438d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 166538d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 166638d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 166738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 166838d5c833SDouglas Gilbert continue; 166938d5c833SDouglas Gilbert na = oip->num_attached; 167038d5c833SDouglas Gilbert arr[offset] = oip->opcode; 167138d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 167238d5c833SDouglas Gilbert if (rctd) 167338d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 167438d5c833SDouglas Gilbert if (FF_SA & oip->flags) 167538d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 167638d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 167738d5c833SDouglas Gilbert if (rctd) 167838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 167938d5c833SDouglas Gilbert r_oip = oip; 168038d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 168138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 168238d5c833SDouglas Gilbert continue; 168338d5c833SDouglas Gilbert offset += bump; 168438d5c833SDouglas Gilbert arr[offset] = oip->opcode; 168538d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 168638d5c833SDouglas Gilbert if (rctd) 168738d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 168838d5c833SDouglas Gilbert if (FF_SA & oip->flags) 168938d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 169038d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 169138d5c833SDouglas Gilbert arr + offset + 6); 169238d5c833SDouglas Gilbert if (rctd) 169338d5c833SDouglas Gilbert put_unaligned_be16(0xa, 169438d5c833SDouglas Gilbert arr + offset + 8); 169538d5c833SDouglas Gilbert } 169638d5c833SDouglas Gilbert oip = r_oip; 169738d5c833SDouglas Gilbert offset += bump; 169838d5c833SDouglas Gilbert } 169938d5c833SDouglas Gilbert break; 170038d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 170138d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 170238d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 170338d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 170438d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 170538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 170638d5c833SDouglas Gilbert supp = 1; 170738d5c833SDouglas Gilbert offset = 4; 170838d5c833SDouglas Gilbert } else { 170938d5c833SDouglas Gilbert if (1 == reporting_opts) { 171038d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 171138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 171238d5c833SDouglas Gilbert 2, 2); 171338d5c833SDouglas Gilbert kfree(arr); 171438d5c833SDouglas Gilbert return check_condition_result; 171538d5c833SDouglas Gilbert } 171638d5c833SDouglas Gilbert req_sa = 0; 171738d5c833SDouglas Gilbert } else if (2 == reporting_opts && 171838d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 171938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 172038d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 172138d5c833SDouglas Gilbert return check_condition_result; 172238d5c833SDouglas Gilbert } 172338d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 172438d5c833SDouglas Gilbert req_opcode == oip->opcode) 172538d5c833SDouglas Gilbert supp = 3; 172638d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 172738d5c833SDouglas Gilbert na = oip->num_attached; 172838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 172938d5c833SDouglas Gilbert ++k, ++oip) { 173038d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 173138d5c833SDouglas Gilbert break; 173238d5c833SDouglas Gilbert } 173338d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 173438d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 173538d5c833SDouglas Gilbert na = oip->num_attached; 173638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 173738d5c833SDouglas Gilbert ++k, ++oip) { 173838d5c833SDouglas Gilbert if (req_sa == oip->sa) 173938d5c833SDouglas Gilbert break; 174038d5c833SDouglas Gilbert } 174138d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 174238d5c833SDouglas Gilbert } else 174338d5c833SDouglas Gilbert supp = 3; 174438d5c833SDouglas Gilbert if (3 == supp) { 174538d5c833SDouglas Gilbert u = oip->len_mask[0]; 174638d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 174738d5c833SDouglas Gilbert arr[4] = oip->opcode; 174838d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 174938d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 175038d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 175138d5c833SDouglas Gilbert offset = 4 + u; 175238d5c833SDouglas Gilbert } else 175338d5c833SDouglas Gilbert offset = 4; 175438d5c833SDouglas Gilbert } 175538d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 175638d5c833SDouglas Gilbert if (rctd) { 175738d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 175838d5c833SDouglas Gilbert offset += 12; 175938d5c833SDouglas Gilbert } 176038d5c833SDouglas Gilbert break; 176138d5c833SDouglas Gilbert default: 176238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 176338d5c833SDouglas Gilbert kfree(arr); 176438d5c833SDouglas Gilbert return check_condition_result; 176538d5c833SDouglas Gilbert } 176638d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 176738d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 176838d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 176938d5c833SDouglas Gilbert kfree(arr); 177038d5c833SDouglas Gilbert return errsts; 177138d5c833SDouglas Gilbert } 177238d5c833SDouglas Gilbert 1773fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1774fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 177538d5c833SDouglas Gilbert { 177638d5c833SDouglas Gilbert bool repd; 177738d5c833SDouglas Gilbert u32 alloc_len, len; 177838d5c833SDouglas Gilbert u8 arr[16]; 177938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 178038d5c833SDouglas Gilbert 178138d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 178238d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 178338d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 178438d5c833SDouglas Gilbert if (alloc_len < 4) { 178538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 178638d5c833SDouglas Gilbert return check_condition_result; 178738d5c833SDouglas Gilbert } 178838d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 178938d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 179038d5c833SDouglas Gilbert if (repd) { 179138d5c833SDouglas Gilbert arr[3] = 0xc; 179238d5c833SDouglas Gilbert len = 16; 179338d5c833SDouglas Gilbert } else 179438d5c833SDouglas Gilbert len = 4; 179538d5c833SDouglas Gilbert 179638d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 179738d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 179838d5c833SDouglas Gilbert } 179938d5c833SDouglas Gilbert 18001da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 18011da177e4SLinus Torvalds 18021da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 18031da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 18041da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 18051da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 18061da177e4SLinus Torvalds 18071da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 18081da177e4SLinus Torvalds if (1 == pcontrol) 18091da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 18101da177e4SLinus Torvalds return sizeof(err_recov_pg); 18111da177e4SLinus Torvalds } 18121da177e4SLinus Torvalds 18131da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 18141da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 18151da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 18161da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 18171da177e4SLinus Torvalds 18181da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 18191da177e4SLinus Torvalds if (1 == pcontrol) 18201da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 18211da177e4SLinus Torvalds return sizeof(disconnect_pg); 18221da177e4SLinus Torvalds } 18231da177e4SLinus Torvalds 18241da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 18251da177e4SLinus Torvalds { /* Format device page for mode_sense */ 18261da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 18271da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 18281da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 18291da177e4SLinus Torvalds 18301da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 1831773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 1832773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 1833773642d9SDouglas Gilbert if (sdebug_removable) 18341da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 18351da177e4SLinus Torvalds if (1 == pcontrol) 18361da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 18371da177e4SLinus Torvalds return sizeof(format_pg); 18381da177e4SLinus Torvalds } 18391da177e4SLinus Torvalds 1840fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 1841fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 1842fd32119bSDouglas Gilbert 0, 0, 0, 0}; 1843fd32119bSDouglas Gilbert 18441da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18451da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1846cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1847cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1848cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18491da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18501da177e4SLinus Torvalds 1851773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 1852cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18531da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18541da177e4SLinus Torvalds if (1 == pcontrol) 1855cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1856cbf67842SDouglas Gilbert else if (2 == pcontrol) 1857cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18581da177e4SLinus Torvalds return sizeof(caching_pg); 18591da177e4SLinus Torvalds } 18601da177e4SLinus Torvalds 1861fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 1862fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 1863fd32119bSDouglas Gilbert 18641da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 18651da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1866c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1867c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1868c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 18691da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 18701da177e4SLinus Torvalds 1871773642d9SDouglas Gilbert if (sdebug_dsense) 18721da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1873c65b1445SDouglas Gilbert else 1874c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1875c6a44287SMartin K. Petersen 1876773642d9SDouglas Gilbert if (sdebug_ato) 1877c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1878c6a44287SMartin K. Petersen 18791da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 18801da177e4SLinus Torvalds if (1 == pcontrol) 1881c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1882c65b1445SDouglas Gilbert else if (2 == pcontrol) 1883c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 18841da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 18851da177e4SLinus Torvalds } 18861da177e4SLinus Torvalds 1887c65b1445SDouglas Gilbert 18881da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 18891da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1890c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 18911da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1892c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1893c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1894c65b1445SDouglas Gilbert 18951da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 18961da177e4SLinus Torvalds if (1 == pcontrol) 1897c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1898c65b1445SDouglas Gilbert else if (2 == pcontrol) 1899c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 19001da177e4SLinus Torvalds return sizeof(iec_m_pg); 19011da177e4SLinus Torvalds } 19021da177e4SLinus Torvalds 1903c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1904c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1905c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1906c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1907c65b1445SDouglas Gilbert 1908c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1909c65b1445SDouglas Gilbert if (1 == pcontrol) 1910c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1911c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1912c65b1445SDouglas Gilbert } 1913c65b1445SDouglas Gilbert 1914c65b1445SDouglas Gilbert 1915c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1916c65b1445SDouglas Gilbert int target_dev_id) 1917c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1918c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1919c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1920773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1921773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1922c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1923c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1924c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1925c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1926773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1927773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1928c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1929c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1930c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1931c65b1445SDouglas Gilbert }; 1932c65b1445SDouglas Gilbert int port_a, port_b; 1933c65b1445SDouglas Gilbert 1934773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16); 1935773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24); 1936773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64); 1937773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72); 1938c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1939c65b1445SDouglas Gilbert port_b = port_a + 1; 1940c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1941773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 1942773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 1943c65b1445SDouglas Gilbert if (1 == pcontrol) 1944c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1945c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1946c65b1445SDouglas Gilbert } 1947c65b1445SDouglas Gilbert 1948c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1949c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1950c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1951c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1952c65b1445SDouglas Gilbert }; 1953c65b1445SDouglas Gilbert 1954c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1955c65b1445SDouglas Gilbert if (1 == pcontrol) 1956c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1957c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1958c65b1445SDouglas Gilbert } 1959c65b1445SDouglas Gilbert 19601da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 19611da177e4SLinus Torvalds 1962fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 1963fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 19641da177e4SLinus Torvalds { 196523183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 19661da177e4SLinus Torvalds unsigned char dev_spec; 1967760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 1968c2248fc9SDouglas Gilbert int target = scp->device->id; 19691da177e4SLinus Torvalds unsigned char * ap; 19701da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 197101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1972760f3b03SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, bad_pcode; 19731da177e4SLinus Torvalds 1974760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 19751da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 19761da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 19771da177e4SLinus Torvalds subpcode = cmd[3]; 19781da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 1979760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 1980760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1981760f3b03SDouglas Gilbert if (is_disk && !dbd) 198223183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 198323183910SDouglas Gilbert else 198423183910SDouglas Gilbert bd_len = 0; 1985773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 19861da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 19871da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 1988cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 19891da177e4SLinus Torvalds return check_condition_result; 19901da177e4SLinus Torvalds } 1991c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1992c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1993b01f6f83SDouglas Gilbert /* for disks set DPOFUA bit and clear write protect (WP) bit */ 1994760f3b03SDouglas Gilbert if (is_disk) 1995b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 199623183910SDouglas Gilbert else 199723183910SDouglas Gilbert dev_spec = 0x0; 19981da177e4SLinus Torvalds if (msense_6) { 19991da177e4SLinus Torvalds arr[2] = dev_spec; 200023183910SDouglas Gilbert arr[3] = bd_len; 20011da177e4SLinus Torvalds offset = 4; 20021da177e4SLinus Torvalds } else { 20031da177e4SLinus Torvalds arr[3] = dev_spec; 200423183910SDouglas Gilbert if (16 == bd_len) 200523183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 200623183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 20071da177e4SLinus Torvalds offset = 8; 20081da177e4SLinus Torvalds } 20091da177e4SLinus Torvalds ap = arr + offset; 201028898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 201128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 201228898873SFUJITA Tomonori 201323183910SDouglas Gilbert if (8 == bd_len) { 2014773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2015773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2016773642d9SDouglas Gilbert else 2017773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2018773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 201923183910SDouglas Gilbert offset += bd_len; 202023183910SDouglas Gilbert ap = arr + offset; 202123183910SDouglas Gilbert } else if (16 == bd_len) { 2022773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2023773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 202423183910SDouglas Gilbert offset += bd_len; 202523183910SDouglas Gilbert ap = arr + offset; 202623183910SDouglas Gilbert } 20271da177e4SLinus Torvalds 2028c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2029c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 203022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 20311da177e4SLinus Torvalds return check_condition_result; 20321da177e4SLinus Torvalds } 2033760f3b03SDouglas Gilbert bad_pcode = false; 2034760f3b03SDouglas Gilbert 20351da177e4SLinus Torvalds switch (pcode) { 20361da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 20371da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20381da177e4SLinus Torvalds offset += len; 20391da177e4SLinus Torvalds break; 20401da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 20411da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20421da177e4SLinus Torvalds offset += len; 20431da177e4SLinus Torvalds break; 20441da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2045760f3b03SDouglas Gilbert if (is_disk) { 20461da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20471da177e4SLinus Torvalds offset += len; 2048760f3b03SDouglas Gilbert } else 2049760f3b03SDouglas Gilbert bad_pcode = true; 20501da177e4SLinus Torvalds break; 20511da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2052760f3b03SDouglas Gilbert if (is_disk) { 20531da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 20541da177e4SLinus Torvalds offset += len; 2055760f3b03SDouglas Gilbert } else 2056760f3b03SDouglas Gilbert bad_pcode = true; 20571da177e4SLinus Torvalds break; 20581da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 20591da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 20601da177e4SLinus Torvalds offset += len; 20611da177e4SLinus Torvalds break; 2062c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2063c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 206422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2065c65b1445SDouglas Gilbert return check_condition_result; 2066c65b1445SDouglas Gilbert } 2067c65b1445SDouglas Gilbert len = 0; 2068c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2069c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2070c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2071c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2072c65b1445SDouglas Gilbert target_dev_id); 2073c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2074c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2075c65b1445SDouglas Gilbert offset += len; 2076c65b1445SDouglas Gilbert break; 20771da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 20781da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 20791da177e4SLinus Torvalds offset += len; 20801da177e4SLinus Torvalds break; 20811da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2082c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 20831da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20841da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2085760f3b03SDouglas Gilbert if (is_disk) { 2086760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2087760f3b03SDouglas Gilbert target); 2088760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2089760f3b03SDouglas Gilbert target); 2090760f3b03SDouglas Gilbert } 20911da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2092c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2093c65b1445SDouglas Gilbert if (0xff == subpcode) { 2094c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2095c65b1445SDouglas Gilbert target, target_dev_id); 2096c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2097c65b1445SDouglas Gilbert } 20981da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2099760f3b03SDouglas Gilbert offset += len; 2100c65b1445SDouglas Gilbert } else { 210122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2102c65b1445SDouglas Gilbert return check_condition_result; 2103c65b1445SDouglas Gilbert } 21041da177e4SLinus Torvalds break; 21051da177e4SLinus Torvalds default: 2106760f3b03SDouglas Gilbert bad_pcode = true; 2107760f3b03SDouglas Gilbert break; 2108760f3b03SDouglas Gilbert } 2109760f3b03SDouglas Gilbert if (bad_pcode) { 211022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 21111da177e4SLinus Torvalds return check_condition_result; 21121da177e4SLinus Torvalds } 21131da177e4SLinus Torvalds if (msense_6) 21141da177e4SLinus Torvalds arr[0] = offset - 1; 2115773642d9SDouglas Gilbert else 2116773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 21171da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 21181da177e4SLinus Torvalds } 21191da177e4SLinus Torvalds 2120c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2121c65b1445SDouglas Gilbert 2122fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2123fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2124c65b1445SDouglas Gilbert { 2125c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2126c2248fc9SDouglas Gilbert int param_len, res, mpage; 2127c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 212801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2129c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2130c65b1445SDouglas Gilbert 2131c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2132c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2133c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2134773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2135c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 213622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2137c65b1445SDouglas Gilbert return check_condition_result; 2138c65b1445SDouglas Gilbert } 2139c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2140c65b1445SDouglas Gilbert if (-1 == res) 2141773642d9SDouglas Gilbert return DID_ERROR << 16; 2142773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2143cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2144cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2145cbf67842SDouglas Gilbert __func__, param_len, res); 2146773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2147773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 214823183910SDouglas Gilbert if (md_len > 2) { 214922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2150c65b1445SDouglas Gilbert return check_condition_result; 2151c65b1445SDouglas Gilbert } 2152c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2153c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2154c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2155c65b1445SDouglas Gilbert if (ps) { 215622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2157c65b1445SDouglas Gilbert return check_condition_result; 2158c65b1445SDouglas Gilbert } 2159c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2160773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2161c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2162c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2163cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2164c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2165c65b1445SDouglas Gilbert return check_condition_result; 2166c65b1445SDouglas Gilbert } 2167c65b1445SDouglas Gilbert switch (mpage) { 2168cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2169cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2170cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2171cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2172cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2173cbf67842SDouglas Gilbert } 2174cbf67842SDouglas Gilbert break; 2175c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2176c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2177c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2178c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2179773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2180cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2181c65b1445SDouglas Gilbert } 2182c65b1445SDouglas Gilbert break; 2183c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2184c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2185c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2186c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2187cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2188c65b1445SDouglas Gilbert } 2189c65b1445SDouglas Gilbert break; 2190c65b1445SDouglas Gilbert default: 2191c65b1445SDouglas Gilbert break; 2192c65b1445SDouglas Gilbert } 219322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2194c65b1445SDouglas Gilbert return check_condition_result; 2195cbf67842SDouglas Gilbert set_mode_changed_ua: 2196cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2197cbf67842SDouglas Gilbert return 0; 2198c65b1445SDouglas Gilbert } 2199c65b1445SDouglas Gilbert 2200c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2201c65b1445SDouglas Gilbert { 2202c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2203c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2204c65b1445SDouglas Gilbert }; 2205c65b1445SDouglas Gilbert 2206c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2207c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2208c65b1445SDouglas Gilbert } 2209c65b1445SDouglas Gilbert 2210c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2211c65b1445SDouglas Gilbert { 2212c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2213c65b1445SDouglas Gilbert }; 2214c65b1445SDouglas Gilbert 2215c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2216c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2217c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2218c65b1445SDouglas Gilbert arr[5] = 0xff; 2219c65b1445SDouglas Gilbert } 2220c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2221c65b1445SDouglas Gilbert } 2222c65b1445SDouglas Gilbert 2223c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2224c65b1445SDouglas Gilbert 2225c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2226c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2227c65b1445SDouglas Gilbert { 2228c2248fc9SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n; 2229c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 223001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2231c65b1445SDouglas Gilbert 2232c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2233c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2234c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2235c65b1445SDouglas Gilbert if (ppc || sp) { 223622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2237c65b1445SDouglas Gilbert return check_condition_result; 2238c65b1445SDouglas Gilbert } 2239c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 2240c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 224123183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2242773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2243c65b1445SDouglas Gilbert arr[0] = pcode; 224423183910SDouglas Gilbert if (0 == subpcode) { 2245c65b1445SDouglas Gilbert switch (pcode) { 2246c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2247c65b1445SDouglas Gilbert n = 4; 2248c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2249c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2250c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2251c65b1445SDouglas Gilbert arr[3] = n - 4; 2252c65b1445SDouglas Gilbert break; 2253c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2254c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2255c65b1445SDouglas Gilbert break; 2256c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2257c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2258c65b1445SDouglas Gilbert break; 2259c65b1445SDouglas Gilbert default: 226022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2261c65b1445SDouglas Gilbert return check_condition_result; 2262c65b1445SDouglas Gilbert } 226323183910SDouglas Gilbert } else if (0xff == subpcode) { 226423183910SDouglas Gilbert arr[0] |= 0x40; 226523183910SDouglas Gilbert arr[1] = subpcode; 226623183910SDouglas Gilbert switch (pcode) { 226723183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 226823183910SDouglas Gilbert n = 4; 226923183910SDouglas Gilbert arr[n++] = 0x0; 227023183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 227123183910SDouglas Gilbert arr[n++] = 0x0; 227223183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 227323183910SDouglas Gilbert arr[n++] = 0xd; 227423183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 227523183910SDouglas Gilbert arr[n++] = 0x2f; 227623183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 227723183910SDouglas Gilbert arr[3] = n - 4; 227823183910SDouglas Gilbert break; 227923183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 228023183910SDouglas Gilbert n = 4; 228123183910SDouglas Gilbert arr[n++] = 0xd; 228223183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 228323183910SDouglas Gilbert arr[3] = n - 4; 228423183910SDouglas Gilbert break; 228523183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 228623183910SDouglas Gilbert n = 4; 228723183910SDouglas Gilbert arr[n++] = 0x2f; 228823183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 228923183910SDouglas Gilbert arr[3] = n - 4; 229023183910SDouglas Gilbert break; 229123183910SDouglas Gilbert default: 229222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 229323183910SDouglas Gilbert return check_condition_result; 229423183910SDouglas Gilbert } 229523183910SDouglas Gilbert } else { 229622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 229723183910SDouglas Gilbert return check_condition_result; 229823183910SDouglas Gilbert } 2299773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 2300c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2301c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2302c65b1445SDouglas Gilbert } 2303c65b1445SDouglas Gilbert 2304cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 230519789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 23061da177e4SLinus Torvalds { 2307c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 230822017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 23091da177e4SLinus Torvalds return check_condition_result; 23101da177e4SLinus Torvalds } 2311c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2312c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 231322017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2314cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2315c65b1445SDouglas Gilbert return check_condition_result; 2316c65b1445SDouglas Gilbert } 231719789100SFUJITA Tomonori return 0; 231819789100SFUJITA Tomonori } 231919789100SFUJITA Tomonori 2320a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2321fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, 2322fd32119bSDouglas Gilbert bool do_write) 232319789100SFUJITA Tomonori { 232419789100SFUJITA Tomonori int ret; 2325c2248fc9SDouglas Gilbert u64 block, rest = 0; 2326a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2327a4517511SAkinobu Mita enum dma_data_direction dir; 232819789100SFUJITA Tomonori 2329c2248fc9SDouglas Gilbert if (do_write) { 2330a4517511SAkinobu Mita sdb = scsi_out(scmd); 2331a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2332a4517511SAkinobu Mita } else { 2333a4517511SAkinobu Mita sdb = scsi_in(scmd); 2334a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2335a4517511SAkinobu Mita } 2336a4517511SAkinobu Mita 2337a4517511SAkinobu Mita if (!sdb->length) 2338a4517511SAkinobu Mita return 0; 2339a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2340a4517511SAkinobu Mita return -1; 234119789100SFUJITA Tomonori 234219789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 234319789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 234419789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 234519789100SFUJITA Tomonori 2346386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2347773642d9SDouglas Gilbert fake_storep + (block * sdebug_sector_size), 2348773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, 0, do_write); 2349773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2350a4517511SAkinobu Mita return ret; 2351a4517511SAkinobu Mita 2352a4517511SAkinobu Mita if (rest) { 2353386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2354773642d9SDouglas Gilbert fake_storep, rest * sdebug_sector_size, 2355773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, do_write); 2356a4517511SAkinobu Mita } 235719789100SFUJITA Tomonori 235819789100SFUJITA Tomonori return ret; 235919789100SFUJITA Tomonori } 236019789100SFUJITA Tomonori 236138d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 236238d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 236338d5c833SDouglas Gilbert * return false. */ 2364fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr) 236538d5c833SDouglas Gilbert { 236638d5c833SDouglas Gilbert bool res; 236738d5c833SDouglas Gilbert u64 block, rest = 0; 236838d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2369773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 237038d5c833SDouglas Gilbert 237138d5c833SDouglas Gilbert block = do_div(lba, store_blks); 237238d5c833SDouglas Gilbert if (block + num > store_blks) 237338d5c833SDouglas Gilbert rest = block + num - store_blks; 237438d5c833SDouglas Gilbert 237538d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 237638d5c833SDouglas Gilbert (num - rest) * lb_size); 237738d5c833SDouglas Gilbert if (!res) 237838d5c833SDouglas Gilbert return res; 237938d5c833SDouglas Gilbert if (rest) 238038d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 238138d5c833SDouglas Gilbert rest * lb_size); 238238d5c833SDouglas Gilbert if (!res) 238338d5c833SDouglas Gilbert return res; 238438d5c833SDouglas Gilbert arr += num * lb_size; 238538d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 238638d5c833SDouglas Gilbert if (rest) 238738d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 238838d5c833SDouglas Gilbert rest * lb_size); 238938d5c833SDouglas Gilbert return res; 239038d5c833SDouglas Gilbert } 239138d5c833SDouglas Gilbert 239251d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2393beb40ea4SAkinobu Mita { 239451d648afSAkinobu Mita __be16 csum; 2395beb40ea4SAkinobu Mita 2396773642d9SDouglas Gilbert if (sdebug_guard) 239751d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 239851d648afSAkinobu Mita else 2399beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 240051d648afSAkinobu Mita 2401beb40ea4SAkinobu Mita return csum; 2402beb40ea4SAkinobu Mita } 2403beb40ea4SAkinobu Mita 2404beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 2405beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2406beb40ea4SAkinobu Mita { 2407773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2408beb40ea4SAkinobu Mita 2409beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2410c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2411beb40ea4SAkinobu Mita (unsigned long)sector, 2412beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2413beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2414beb40ea4SAkinobu Mita return 0x01; 2415beb40ea4SAkinobu Mita } 2416773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE1_PROTECTION && 2417beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2418c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2419c1287970STomas Winkler (unsigned long)sector); 2420beb40ea4SAkinobu Mita return 0x03; 2421beb40ea4SAkinobu Mita } 2422773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2423beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2424c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2425c1287970STomas Winkler (unsigned long)sector); 2426beb40ea4SAkinobu Mita return 0x03; 2427beb40ea4SAkinobu Mita } 2428beb40ea4SAkinobu Mita return 0; 2429beb40ea4SAkinobu Mita } 2430beb40ea4SAkinobu Mita 2431bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 243265f72f2aSAkinobu Mita unsigned int sectors, bool read) 2433c6a44287SMartin K. Petersen { 2434be4e11beSAkinobu Mita size_t resid; 2435c6a44287SMartin K. Petersen void *paddr; 243614faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2437be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2438c6a44287SMartin K. Petersen 2439e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2440e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2441c6a44287SMartin K. Petersen 2442be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2443be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2444be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2445be4e11beSAkinobu Mita 2446be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2447be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 244814faa944SAkinobu Mita void *start = dif_store(sector); 2449be4e11beSAkinobu Mita size_t rest = 0; 245014faa944SAkinobu Mita 245114faa944SAkinobu Mita if (dif_store_end < start + len) 245214faa944SAkinobu Mita rest = start + len - dif_store_end; 2453c6a44287SMartin K. Petersen 2454be4e11beSAkinobu Mita paddr = miter.addr; 245514faa944SAkinobu Mita 245665f72f2aSAkinobu Mita if (read) 245765f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 245865f72f2aSAkinobu Mita else 245965f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 246065f72f2aSAkinobu Mita 246165f72f2aSAkinobu Mita if (rest) { 246265f72f2aSAkinobu Mita if (read) 246314faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 246465f72f2aSAkinobu Mita else 246565f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 246665f72f2aSAkinobu Mita } 2467c6a44287SMartin K. Petersen 2468e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2469c6a44287SMartin K. Petersen resid -= len; 2470c6a44287SMartin K. Petersen } 2471be4e11beSAkinobu Mita sg_miter_stop(&miter); 2472bb8c063cSAkinobu Mita } 2473c6a44287SMartin K. Petersen 2474bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2475bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2476bb8c063cSAkinobu Mita { 2477bb8c063cSAkinobu Mita unsigned int i; 2478bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 2479bb8c063cSAkinobu Mita sector_t sector; 2480bb8c063cSAkinobu Mita 2481c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2482bb8c063cSAkinobu Mita int ret; 2483bb8c063cSAkinobu Mita 2484bb8c063cSAkinobu Mita sector = start_sec + i; 2485bb8c063cSAkinobu Mita sdt = dif_store(sector); 2486bb8c063cSAkinobu Mita 248751d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2488bb8c063cSAkinobu Mita continue; 2489bb8c063cSAkinobu Mita 2490bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2491bb8c063cSAkinobu Mita if (ret) { 2492bb8c063cSAkinobu Mita dif_errors++; 2493bb8c063cSAkinobu Mita return ret; 2494bb8c063cSAkinobu Mita } 2495bb8c063cSAkinobu Mita } 2496bb8c063cSAkinobu Mita 249765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2498c6a44287SMartin K. Petersen dix_reads++; 2499c6a44287SMartin K. Petersen 2500c6a44287SMartin K. Petersen return 0; 2501c6a44287SMartin K. Petersen } 2502c6a44287SMartin K. Petersen 2503fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 250419789100SFUJITA Tomonori { 2505c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2506c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 2507c2248fc9SDouglas Gilbert u64 lba; 2508c2248fc9SDouglas Gilbert u32 num; 2509c2248fc9SDouglas Gilbert u32 ei_lba; 251019789100SFUJITA Tomonori unsigned long iflags; 251119789100SFUJITA Tomonori int ret; 2512c2248fc9SDouglas Gilbert bool check_prot; 251319789100SFUJITA Tomonori 2514c2248fc9SDouglas Gilbert switch (cmd[0]) { 2515c2248fc9SDouglas Gilbert case READ_16: 2516c2248fc9SDouglas Gilbert ei_lba = 0; 2517c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2518c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2519c2248fc9SDouglas Gilbert check_prot = true; 2520c2248fc9SDouglas Gilbert break; 2521c2248fc9SDouglas Gilbert case READ_10: 2522c2248fc9SDouglas Gilbert ei_lba = 0; 2523c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2524c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2525c2248fc9SDouglas Gilbert check_prot = true; 2526c2248fc9SDouglas Gilbert break; 2527c2248fc9SDouglas Gilbert case READ_6: 2528c2248fc9SDouglas Gilbert ei_lba = 0; 2529c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2530c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2531c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2532c2248fc9SDouglas Gilbert check_prot = true; 2533c2248fc9SDouglas Gilbert break; 2534c2248fc9SDouglas Gilbert case READ_12: 2535c2248fc9SDouglas Gilbert ei_lba = 0; 2536c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2537c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2538c2248fc9SDouglas Gilbert check_prot = true; 2539c2248fc9SDouglas Gilbert break; 2540c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2541c2248fc9SDouglas Gilbert ei_lba = 0; 2542c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2543c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2544c2248fc9SDouglas Gilbert check_prot = false; 2545c2248fc9SDouglas Gilbert break; 2546c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2547c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2548c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2549c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2550c2248fc9SDouglas Gilbert check_prot = false; 2551c2248fc9SDouglas Gilbert break; 2552c2248fc9SDouglas Gilbert } 2553f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2554773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2555c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2556c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2557c2248fc9SDouglas Gilbert return check_condition_result; 2558c2248fc9SDouglas Gilbert } 2559773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2560773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2561c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2562c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2563c2248fc9SDouglas Gilbert "to DIF device\n"); 2564c2248fc9SDouglas Gilbert } 2565f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2566c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 2567c2248fc9SDouglas Gilbert 2568c4837394SDouglas Gilbert if (sqcp) { 2569c4837394SDouglas Gilbert if (sqcp->inj_short) 2570c2248fc9SDouglas Gilbert num /= 2; 2571c2248fc9SDouglas Gilbert } 2572c4837394SDouglas Gilbert } else 2573c4837394SDouglas Gilbert sqcp = NULL; 2574c2248fc9SDouglas Gilbert 2575c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2576f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2577c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2578c2248fc9SDouglas Gilbert return check_condition_result; 2579c2248fc9SDouglas Gilbert } 2580c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2581f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2582c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2583c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2584c2248fc9SDouglas Gilbert return check_condition_result; 2585c2248fc9SDouglas Gilbert } 258619789100SFUJITA Tomonori 2587f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 258832f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2589f46eb0e9SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { 2590c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2591c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2592c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2593c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2594c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 259532f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 259632f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2597c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2598c65b1445SDouglas Gilbert } 2599c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 26001da177e4SLinus Torvalds return check_condition_result; 26011da177e4SLinus Torvalds } 2602c6a44287SMartin K. Petersen 26036c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 26046c78cc06SAkinobu Mita 2605c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2606f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2607c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2608c6a44287SMartin K. Petersen 2609c6a44287SMartin K. Petersen if (prot_ret) { 26106c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2611c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2612c6a44287SMartin K. Petersen return illegal_condition_result; 2613c6a44287SMartin K. Petersen } 2614c6a44287SMartin K. Petersen } 2615c6a44287SMartin K. Petersen 2616c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 26171da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2618f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2619a4517511SAkinobu Mita return DID_ERROR << 16; 2620a4517511SAkinobu Mita 2621c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2622a4517511SAkinobu Mita 2623c4837394SDouglas Gilbert if (unlikely(sqcp)) { 2624c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2625c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2626c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2627c2248fc9SDouglas Gilbert return check_condition_result; 2628c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 2629c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2630c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2631c2248fc9SDouglas Gilbert return check_condition_result; 2632c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2633c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2634c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2635c2248fc9SDouglas Gilbert return illegal_condition_result; 2636c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2637c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2638c2248fc9SDouglas Gilbert return illegal_condition_result; 2639c2248fc9SDouglas Gilbert } 2640c2248fc9SDouglas Gilbert } 2641a4517511SAkinobu Mita return 0; 26421da177e4SLinus Torvalds } 26431da177e4SLinus Torvalds 264458a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2645c6a44287SMartin K. Petersen { 2646cbf67842SDouglas Gilbert int i, j, n; 2647c6a44287SMartin K. Petersen 2648cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2649c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2650cbf67842SDouglas Gilbert char b[128]; 2651c6a44287SMartin K. Petersen 2652cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2653c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2654c6a44287SMartin K. Petersen 2655cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2656cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2657cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2658cbf67842SDouglas Gilbert else 2659cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2660cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2661cbf67842SDouglas Gilbert } 2662cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2663c6a44287SMartin K. Petersen } 2664c6a44287SMartin K. Petersen } 2665c6a44287SMartin K. Petersen 2666c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2667395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2668c6a44287SMartin K. Petersen { 2669be4e11beSAkinobu Mita int ret; 2670c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 2671be4e11beSAkinobu Mita void *daddr; 267265f72f2aSAkinobu Mita sector_t sector = start_sec; 2673c6a44287SMartin K. Petersen int ppage_offset; 2674be4e11beSAkinobu Mita int dpage_offset; 2675be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2676be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2677c6a44287SMartin K. Petersen 2678c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2679c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2680c6a44287SMartin K. Petersen 2681be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2682be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2683be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2684be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2685be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2686c6a44287SMartin K. Petersen 2687be4e11beSAkinobu Mita /* For each protection page */ 2688be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2689be4e11beSAkinobu Mita dpage_offset = 0; 2690be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2691be4e11beSAkinobu Mita ret = 0x01; 2692be4e11beSAkinobu Mita goto out; 2693c6a44287SMartin K. Petersen } 2694c6a44287SMartin K. Petersen 2695be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 2696be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 2697be4e11beSAkinobu Mita /* If we're at the end of the current 2698be4e11beSAkinobu Mita * data page advance to the next one 2699be4e11beSAkinobu Mita */ 2700be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2701be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2702be4e11beSAkinobu Mita ret = 0x01; 2703be4e11beSAkinobu Mita goto out; 2704be4e11beSAkinobu Mita } 2705be4e11beSAkinobu Mita dpage_offset = 0; 2706be4e11beSAkinobu Mita } 2707c6a44287SMartin K. Petersen 2708be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2709be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2710be4e11beSAkinobu Mita 2711be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2712beb40ea4SAkinobu Mita if (ret) { 2713773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2714395cef03SMartin K. Petersen goto out; 2715395cef03SMartin K. Petersen } 2716395cef03SMartin K. Petersen 2717c6a44287SMartin K. Petersen sector++; 2718395cef03SMartin K. Petersen ei_lba++; 2719773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2720c6a44287SMartin K. Petersen } 2721be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2722be4e11beSAkinobu Mita sg_miter_stop(&diter); 2723c6a44287SMartin K. Petersen } 2724be4e11beSAkinobu Mita sg_miter_stop(&piter); 2725c6a44287SMartin K. Petersen 272665f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2727c6a44287SMartin K. Petersen dix_writes++; 2728c6a44287SMartin K. Petersen 2729c6a44287SMartin K. Petersen return 0; 2730c6a44287SMartin K. Petersen 2731c6a44287SMartin K. Petersen out: 2732c6a44287SMartin K. Petersen dif_errors++; 2733be4e11beSAkinobu Mita sg_miter_stop(&diter); 2734be4e11beSAkinobu Mita sg_miter_stop(&piter); 2735c6a44287SMartin K. Petersen return ret; 2736c6a44287SMartin K. Petersen } 2737c6a44287SMartin K. Petersen 2738b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2739b90ebc3dSAkinobu Mita { 2740773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2741773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2742773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2743b90ebc3dSAkinobu Mita return lba; 2744b90ebc3dSAkinobu Mita } 2745b90ebc3dSAkinobu Mita 2746b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2747b90ebc3dSAkinobu Mita { 2748773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2749a027b5b9SAkinobu Mita 2750773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2751773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2752a027b5b9SAkinobu Mita return lba; 2753a027b5b9SAkinobu Mita } 2754a027b5b9SAkinobu Mita 275544d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 275644d92694SMartin K. Petersen { 2757b90ebc3dSAkinobu Mita sector_t end; 2758b90ebc3dSAkinobu Mita unsigned int mapped; 2759b90ebc3dSAkinobu Mita unsigned long index; 2760b90ebc3dSAkinobu Mita unsigned long next; 276144d92694SMartin K. Petersen 2762b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2763b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 276444d92694SMartin K. Petersen 276544d92694SMartin K. Petersen if (mapped) 2766b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 276744d92694SMartin K. Petersen else 2768b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 276944d92694SMartin K. Petersen 2770b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 277144d92694SMartin K. Petersen *num = end - lba; 277244d92694SMartin K. Petersen return mapped; 277344d92694SMartin K. Petersen } 277444d92694SMartin K. Petersen 277544d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 277644d92694SMartin K. Petersen { 277744d92694SMartin K. Petersen sector_t end = lba + len; 277844d92694SMartin K. Petersen 277944d92694SMartin K. Petersen while (lba < end) { 2780b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 278144d92694SMartin K. Petersen 2782b90ebc3dSAkinobu Mita if (index < map_size) 2783b90ebc3dSAkinobu Mita set_bit(index, map_storep); 278444d92694SMartin K. Petersen 2785b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 278644d92694SMartin K. Petersen } 278744d92694SMartin K. Petersen } 278844d92694SMartin K. Petersen 278944d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 279044d92694SMartin K. Petersen { 279144d92694SMartin K. Petersen sector_t end = lba + len; 279244d92694SMartin K. Petersen 279344d92694SMartin K. Petersen while (lba < end) { 2794b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 279544d92694SMartin K. Petersen 2796b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2797773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 2798b90ebc3dSAkinobu Mita index < map_size) { 2799b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2800760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 2801be1dd78dSEric Sandeen memset(fake_storep + 2802760f3b03SDouglas Gilbert lba * sdebug_sector_size, 2803760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 2804773642d9SDouglas Gilbert sdebug_sector_size * 2805773642d9SDouglas Gilbert sdebug_unmap_granularity); 2806be1dd78dSEric Sandeen } 2807e9926b43SAkinobu Mita if (dif_storep) { 2808e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2809e9926b43SAkinobu Mita sizeof(*dif_storep) * 2810773642d9SDouglas Gilbert sdebug_unmap_granularity); 2811e9926b43SAkinobu Mita } 2812b90ebc3dSAkinobu Mita } 2813b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 281444d92694SMartin K. Petersen } 281544d92694SMartin K. Petersen } 281644d92694SMartin K. Petersen 2817fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 28181da177e4SLinus Torvalds { 2819c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2820c2248fc9SDouglas Gilbert u64 lba; 2821c2248fc9SDouglas Gilbert u32 num; 2822c2248fc9SDouglas Gilbert u32 ei_lba; 28231da177e4SLinus Torvalds unsigned long iflags; 282419789100SFUJITA Tomonori int ret; 2825c2248fc9SDouglas Gilbert bool check_prot; 28261da177e4SLinus Torvalds 2827c2248fc9SDouglas Gilbert switch (cmd[0]) { 2828c2248fc9SDouglas Gilbert case WRITE_16: 2829c2248fc9SDouglas Gilbert ei_lba = 0; 2830c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2831c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2832c2248fc9SDouglas Gilbert check_prot = true; 2833c2248fc9SDouglas Gilbert break; 2834c2248fc9SDouglas Gilbert case WRITE_10: 2835c2248fc9SDouglas Gilbert ei_lba = 0; 2836c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2837c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2838c2248fc9SDouglas Gilbert check_prot = true; 2839c2248fc9SDouglas Gilbert break; 2840c2248fc9SDouglas Gilbert case WRITE_6: 2841c2248fc9SDouglas Gilbert ei_lba = 0; 2842c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2843c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2844c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2845c2248fc9SDouglas Gilbert check_prot = true; 2846c2248fc9SDouglas Gilbert break; 2847c2248fc9SDouglas Gilbert case WRITE_12: 2848c2248fc9SDouglas Gilbert ei_lba = 0; 2849c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2850c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2851c2248fc9SDouglas Gilbert check_prot = true; 2852c2248fc9SDouglas Gilbert break; 2853c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2854c2248fc9SDouglas Gilbert ei_lba = 0; 2855c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2856c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2857c2248fc9SDouglas Gilbert check_prot = false; 2858c2248fc9SDouglas Gilbert break; 2859c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2860c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2861c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2862c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2863c2248fc9SDouglas Gilbert check_prot = false; 2864c2248fc9SDouglas Gilbert break; 2865c2248fc9SDouglas Gilbert } 2866f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2867773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2868c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2869c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2870c2248fc9SDouglas Gilbert return check_condition_result; 2871c2248fc9SDouglas Gilbert } 2872773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2873773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2874c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2875c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2876c2248fc9SDouglas Gilbert "to DIF device\n"); 2877c2248fc9SDouglas Gilbert } 2878c2248fc9SDouglas Gilbert 2879c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2880f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2881c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2882c2248fc9SDouglas Gilbert return check_condition_result; 2883c2248fc9SDouglas Gilbert } 2884c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2885f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2886c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2887c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2888c2248fc9SDouglas Gilbert return check_condition_result; 2889c2248fc9SDouglas Gilbert } 28901da177e4SLinus Torvalds 28916c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 28926c78cc06SAkinobu Mita 2893c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2894f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2895c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2896c6a44287SMartin K. Petersen 2897c6a44287SMartin K. Petersen if (prot_ret) { 28986c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2899c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2900c6a44287SMartin K. Petersen return illegal_condition_result; 2901c6a44287SMartin K. Petersen } 2902c6a44287SMartin K. Petersen } 2903c6a44287SMartin K. Petersen 2904c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 2905f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 290644d92694SMartin K. Petersen map_region(lba, num); 29071da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 2908f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 2909773642d9SDouglas Gilbert return DID_ERROR << 16; 2910c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 2911c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 2912c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2913cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2914773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 291544d92694SMartin K. Petersen 2916f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2917c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 2918c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 2919c2248fc9SDouglas Gilbert 2920c4837394SDouglas Gilbert if (sqcp) { 2921c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2922c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2923c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2924c2248fc9SDouglas Gilbert return check_condition_result; 2925c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2926c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2927c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2928c2248fc9SDouglas Gilbert return illegal_condition_result; 2929c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2930c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2931c2248fc9SDouglas Gilbert return illegal_condition_result; 2932c2248fc9SDouglas Gilbert } 2933c2248fc9SDouglas Gilbert } 2934c4837394SDouglas Gilbert } 29351da177e4SLinus Torvalds return 0; 29361da177e4SLinus Torvalds } 29371da177e4SLinus Torvalds 2938fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 2939fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 294044d92694SMartin K. Petersen { 294144d92694SMartin K. Petersen unsigned long iflags; 294244d92694SMartin K. Petersen unsigned long long i; 294344d92694SMartin K. Petersen int ret; 2944773642d9SDouglas Gilbert u64 lba_off; 294544d92694SMartin K. Petersen 2946c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 294744d92694SMartin K. Petersen if (ret) 294844d92694SMartin K. Petersen return ret; 294944d92694SMartin K. Petersen 295044d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 295144d92694SMartin K. Petersen 29529ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 295344d92694SMartin K. Petersen unmap_region(lba, num); 295444d92694SMartin K. Petersen goto out; 295544d92694SMartin K. Petersen } 295644d92694SMartin K. Petersen 2957773642d9SDouglas Gilbert lba_off = lba * sdebug_sector_size; 2958c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 2959c2248fc9SDouglas Gilbert if (ndob) { 2960773642d9SDouglas Gilbert memset(fake_storep + lba_off, 0, sdebug_sector_size); 2961c2248fc9SDouglas Gilbert ret = 0; 2962c2248fc9SDouglas Gilbert } else 2963773642d9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + lba_off, 2964773642d9SDouglas Gilbert sdebug_sector_size); 296544d92694SMartin K. Petersen 296644d92694SMartin K. Petersen if (-1 == ret) { 296744d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 2968773642d9SDouglas Gilbert return DID_ERROR << 16; 2969773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) 2970c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2971cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 2972cbf67842SDouglas Gilbert my_name, "write same", 2973773642d9SDouglas Gilbert num * sdebug_sector_size, ret); 297444d92694SMartin K. Petersen 297544d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 297644d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 2977773642d9SDouglas Gilbert memcpy(fake_storep + ((lba + i) * sdebug_sector_size), 2978773642d9SDouglas Gilbert fake_storep + lba_off, 2979773642d9SDouglas Gilbert sdebug_sector_size); 298044d92694SMartin K. Petersen 29819ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 298244d92694SMartin K. Petersen map_region(lba, num); 298344d92694SMartin K. Petersen out: 298444d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 298544d92694SMartin K. Petersen 298644d92694SMartin K. Petersen return 0; 298744d92694SMartin K. Petersen } 298844d92694SMartin K. Petersen 2989fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 2990fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2991c2248fc9SDouglas Gilbert { 2992c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2993c2248fc9SDouglas Gilbert u32 lba; 2994c2248fc9SDouglas Gilbert u16 num; 2995c2248fc9SDouglas Gilbert u32 ei_lba = 0; 2996c2248fc9SDouglas Gilbert bool unmap = false; 2997c2248fc9SDouglas Gilbert 2998c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 2999773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3000c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3001c2248fc9SDouglas Gilbert return check_condition_result; 3002c2248fc9SDouglas Gilbert } else 3003c2248fc9SDouglas Gilbert unmap = true; 3004c2248fc9SDouglas Gilbert } 3005c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3006c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3007773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3008c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3009c2248fc9SDouglas Gilbert return check_condition_result; 3010c2248fc9SDouglas Gilbert } 3011c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3012c2248fc9SDouglas Gilbert } 3013c2248fc9SDouglas Gilbert 3014fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3015fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3016c2248fc9SDouglas Gilbert { 3017c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3018c2248fc9SDouglas Gilbert u64 lba; 3019c2248fc9SDouglas Gilbert u32 num; 3020c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3021c2248fc9SDouglas Gilbert bool unmap = false; 3022c2248fc9SDouglas Gilbert bool ndob = false; 3023c2248fc9SDouglas Gilbert 3024c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3025773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3026c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3027c2248fc9SDouglas Gilbert return check_condition_result; 3028c2248fc9SDouglas Gilbert } else 3029c2248fc9SDouglas Gilbert unmap = true; 3030c2248fc9SDouglas Gilbert } 3031c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3032c2248fc9SDouglas Gilbert ndob = true; 3033c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3034c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3035773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3036c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3037c2248fc9SDouglas Gilbert return check_condition_result; 3038c2248fc9SDouglas Gilbert } 3039c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3040c2248fc9SDouglas Gilbert } 3041c2248fc9SDouglas Gilbert 3042acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3043acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3044acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3045fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3046fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3047acafd0b9SEwan D. Milne { 3048acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3049acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3050acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3051acafd0b9SEwan D. Milne u8 mode; 3052acafd0b9SEwan D. Milne 3053acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3054acafd0b9SEwan D. Milne switch (mode) { 3055acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3056acafd0b9SEwan D. Milne /* set UAs on this device only */ 3057acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3058acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3059acafd0b9SEwan D. Milne break; 3060acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3061acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3062acafd0b9SEwan D. Milne break; 3063acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3064acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3065acafd0b9SEwan D. Milne list_for_each_entry(dp, 3066acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3067acafd0b9SEwan D. Milne dev_list) 3068acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3069acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3070acafd0b9SEwan D. Milne if (devip != dp) 3071acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3072acafd0b9SEwan D. Milne dp->uas_bm); 3073acafd0b9SEwan D. Milne } 3074acafd0b9SEwan D. Milne break; 3075acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3076acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3077acafd0b9SEwan D. Milne list_for_each_entry(dp, 3078acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3079acafd0b9SEwan D. Milne dev_list) 3080acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3081acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3082acafd0b9SEwan D. Milne dp->uas_bm); 3083acafd0b9SEwan D. Milne break; 3084acafd0b9SEwan D. Milne default: 3085acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3086acafd0b9SEwan D. Milne break; 3087acafd0b9SEwan D. Milne } 3088acafd0b9SEwan D. Milne return 0; 3089acafd0b9SEwan D. Milne } 3090acafd0b9SEwan D. Milne 3091fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3092fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 309338d5c833SDouglas Gilbert { 309438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 309538d5c833SDouglas Gilbert u8 *arr; 309638d5c833SDouglas Gilbert u8 *fake_storep_hold; 309738d5c833SDouglas Gilbert u64 lba; 309838d5c833SDouglas Gilbert u32 dnum; 3099773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 310038d5c833SDouglas Gilbert u8 num; 310138d5c833SDouglas Gilbert unsigned long iflags; 310238d5c833SDouglas Gilbert int ret; 3103d467d31fSDouglas Gilbert int retval = 0; 310438d5c833SDouglas Gilbert 3105d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 310638d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 310738d5c833SDouglas Gilbert if (0 == num) 310838d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 3109773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 311038d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 311138d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 311238d5c833SDouglas Gilbert return check_condition_result; 311338d5c833SDouglas Gilbert } 3114773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 3115773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 311638d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 311738d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 311838d5c833SDouglas Gilbert "to DIF device\n"); 311938d5c833SDouglas Gilbert 312038d5c833SDouglas Gilbert /* inline check_device_access_params() */ 312138d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 312238d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 312338d5c833SDouglas Gilbert return check_condition_result; 312438d5c833SDouglas Gilbert } 312538d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 312638d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 312738d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 312838d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 312938d5c833SDouglas Gilbert return check_condition_result; 313038d5c833SDouglas Gilbert } 3131d467d31fSDouglas Gilbert dnum = 2 * num; 3132d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3133d467d31fSDouglas Gilbert if (NULL == arr) { 3134d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3135d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3136d467d31fSDouglas Gilbert return check_condition_result; 3137d467d31fSDouglas Gilbert } 313838d5c833SDouglas Gilbert 313938d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 314038d5c833SDouglas Gilbert 314138d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 314238d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 314338d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 314438d5c833SDouglas Gilbert fake_storep = arr; 314538d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 314638d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 314738d5c833SDouglas Gilbert if (ret == -1) { 3148d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3149d467d31fSDouglas Gilbert goto cleanup; 3150773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 315138d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 315238d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 315338d5c833SDouglas Gilbert dnum * lb_size, ret); 315438d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 315538d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3156d467d31fSDouglas Gilbert retval = check_condition_result; 3157d467d31fSDouglas Gilbert goto cleanup; 315838d5c833SDouglas Gilbert } 315938d5c833SDouglas Gilbert if (scsi_debug_lbp()) 316038d5c833SDouglas Gilbert map_region(lba, num); 3161d467d31fSDouglas Gilbert cleanup: 316238d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3163d467d31fSDouglas Gilbert kfree(arr); 3164d467d31fSDouglas Gilbert return retval; 316538d5c833SDouglas Gilbert } 316638d5c833SDouglas Gilbert 316744d92694SMartin K. Petersen struct unmap_block_desc { 316844d92694SMartin K. Petersen __be64 lba; 316944d92694SMartin K. Petersen __be32 blocks; 317044d92694SMartin K. Petersen __be32 __reserved; 317144d92694SMartin K. Petersen }; 317244d92694SMartin K. Petersen 3173fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 317444d92694SMartin K. Petersen { 317544d92694SMartin K. Petersen unsigned char *buf; 317644d92694SMartin K. Petersen struct unmap_block_desc *desc; 317744d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 317844d92694SMartin K. Petersen int ret; 31796c78cc06SAkinobu Mita unsigned long iflags; 318044d92694SMartin K. Petersen 318144d92694SMartin K. Petersen 3182c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3183c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3184c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3185c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 318644d92694SMartin K. Petersen 318744d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3188773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3189c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 319044d92694SMartin K. Petersen return check_condition_result; 3191c2248fc9SDouglas Gilbert } 319244d92694SMartin K. Petersen 3193b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3194c2248fc9SDouglas Gilbert if (!buf) { 3195c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3196c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3197c2248fc9SDouglas Gilbert return check_condition_result; 3198c2248fc9SDouglas Gilbert } 3199c2248fc9SDouglas Gilbert 3200c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 320144d92694SMartin K. Petersen 320244d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 320344d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 320444d92694SMartin K. Petersen 320544d92694SMartin K. Petersen desc = (void *)&buf[8]; 320644d92694SMartin K. Petersen 32076c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 32086c78cc06SAkinobu Mita 320944d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 321044d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 321144d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 321244d92694SMartin K. Petersen 3213c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 321444d92694SMartin K. Petersen if (ret) 321544d92694SMartin K. Petersen goto out; 321644d92694SMartin K. Petersen 321744d92694SMartin K. Petersen unmap_region(lba, num); 321844d92694SMartin K. Petersen } 321944d92694SMartin K. Petersen 322044d92694SMartin K. Petersen ret = 0; 322144d92694SMartin K. Petersen 322244d92694SMartin K. Petersen out: 32236c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 322444d92694SMartin K. Petersen kfree(buf); 322544d92694SMartin K. Petersen 322644d92694SMartin K. Petersen return ret; 322744d92694SMartin K. Petersen } 322844d92694SMartin K. Petersen 322944d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 323044d92694SMartin K. Petersen 3231fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3232fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 323344d92694SMartin K. Petersen { 3234c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3235c2248fc9SDouglas Gilbert u64 lba; 3236c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3237c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 323844d92694SMartin K. Petersen int ret; 323944d92694SMartin K. Petersen 3240c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3241c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 324244d92694SMartin K. Petersen 324344d92694SMartin K. Petersen if (alloc_len < 24) 324444d92694SMartin K. Petersen return 0; 324544d92694SMartin K. Petersen 3246c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 324744d92694SMartin K. Petersen if (ret) 324844d92694SMartin K. Petersen return ret; 324944d92694SMartin K. Petersen 3250c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 325144d92694SMartin K. Petersen mapped = map_state(lba, &num); 3252c2248fc9SDouglas Gilbert else { 3253c2248fc9SDouglas Gilbert mapped = 1; 3254c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3255c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3256c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3257c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3258c2248fc9SDouglas Gilbert else 3259c2248fc9SDouglas Gilbert num = 0xffffffff; 3260c2248fc9SDouglas Gilbert } 326144d92694SMartin K. Petersen 326244d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3263c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3264c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3265c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3266c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 326744d92694SMartin K. Petersen 3268c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 326944d92694SMartin K. Petersen } 327044d92694SMartin K. Petersen 32718d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 32728d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 32738d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 32748d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 32758d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 32768d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 32778d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 32788d039e22SDouglas Gilbert */ 32791da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 32801da177e4SLinus Torvalds struct sdebug_dev_info *devip) 32811da177e4SLinus Torvalds { 328201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 32838d039e22SDouglas Gilbert unsigned int alloc_len; 32848d039e22SDouglas Gilbert unsigned char select_report; 32858d039e22SDouglas Gilbert u64 lun; 32868d039e22SDouglas Gilbert struct scsi_lun *lun_p; 32878d039e22SDouglas Gilbert u8 *arr; 32888d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 32898d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 32908d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 32918d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 32928d039e22SDouglas Gilbert int i, res; 32931da177e4SLinus Torvalds 329419c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 32958d039e22SDouglas Gilbert 32968d039e22SDouglas Gilbert select_report = cmd[2]; 32978d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 32988d039e22SDouglas Gilbert 32998d039e22SDouglas Gilbert if (alloc_len < 4) { 33008d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 33018d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 33021da177e4SLinus Torvalds return check_condition_result; 33031da177e4SLinus Torvalds } 33048d039e22SDouglas Gilbert 33058d039e22SDouglas Gilbert switch (select_report) { 33068d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 3307773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 33088d039e22SDouglas Gilbert wlun_cnt = 0; 33098d039e22SDouglas Gilbert break; 33108d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 3311c65b1445SDouglas Gilbert lun_cnt = 0; 33128d039e22SDouglas Gilbert wlun_cnt = 1; 33138d039e22SDouglas Gilbert break; 33148d039e22SDouglas Gilbert case 2: /* all LUNs */ 33158d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 33168d039e22SDouglas Gilbert wlun_cnt = 1; 33178d039e22SDouglas Gilbert break; 33188d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 33198d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 33208d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 33218d039e22SDouglas Gilbert default: 33228d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 33238d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 33248d039e22SDouglas Gilbert return check_condition_result; 33258d039e22SDouglas Gilbert } 33268d039e22SDouglas Gilbert 33278d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 3328c65b1445SDouglas Gilbert --lun_cnt; 33298d039e22SDouglas Gilbert 33308d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 33318d039e22SDouglas Gilbert 33328d039e22SDouglas Gilbert rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8; 33338d039e22SDouglas Gilbert arr = vmalloc(rlen); 33348d039e22SDouglas Gilbert if (!arr) { 33358d039e22SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 33368d039e22SDouglas Gilbert INSUFF_RES_ASCQ); 33378d039e22SDouglas Gilbert return check_condition_result; 3338c65b1445SDouglas Gilbert } 33398d039e22SDouglas Gilbert memset(arr, 0, rlen); 33408d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 33418d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 33428d039e22SDouglas Gilbert 33438d039e22SDouglas Gilbert /* luns start at byte 8 in response following the header */ 33448d039e22SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[8]; 33458d039e22SDouglas Gilbert 33468d039e22SDouglas Gilbert /* LUNs use single level peripheral device addressing method */ 33478d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 33488d039e22SDouglas Gilbert for (i = 0; i < lun_cnt; i++) 33498d039e22SDouglas Gilbert int_to_scsilun(lun++, lun_p++); 33508d039e22SDouglas Gilbert 33518d039e22SDouglas Gilbert if (wlun_cnt) 33528d039e22SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++); 33538d039e22SDouglas Gilbert 33548d039e22SDouglas Gilbert put_unaligned_be32(rlen - 8, &arr[0]); 33558d039e22SDouglas Gilbert 33568d039e22SDouglas Gilbert res = fill_from_dev_buffer(scp, arr, rlen); 33578d039e22SDouglas Gilbert vfree(arr); 33588d039e22SDouglas Gilbert return res; 33591da177e4SLinus Torvalds } 33601da177e4SLinus Torvalds 3361c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3362c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3363c639d14eSFUJITA Tomonori { 3364be4e11beSAkinobu Mita int j; 3365c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3366c639d14eSFUJITA Tomonori unsigned int offset; 3367c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3368be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3369c639d14eSFUJITA Tomonori 3370c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3371b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3372c5af0db9SAkinobu Mita if (!buf) { 337322017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 337422017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3375c5af0db9SAkinobu Mita return check_condition_result; 3376c5af0db9SAkinobu Mita } 3377c639d14eSFUJITA Tomonori 337821a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3379c639d14eSFUJITA Tomonori 3380c639d14eSFUJITA Tomonori offset = 0; 3381be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3382be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3383c639d14eSFUJITA Tomonori 3384be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3385be4e11beSAkinobu Mita kaddr = miter.addr; 3386be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3387be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3388c639d14eSFUJITA Tomonori 3389be4e11beSAkinobu Mita offset += miter.length; 3390c639d14eSFUJITA Tomonori } 3391be4e11beSAkinobu Mita sg_miter_stop(&miter); 3392c639d14eSFUJITA Tomonori kfree(buf); 3393c639d14eSFUJITA Tomonori 3394be4e11beSAkinobu Mita return 0; 3395c639d14eSFUJITA Tomonori } 3396c639d14eSFUJITA Tomonori 3397fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp, 3398fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3399c2248fc9SDouglas Gilbert { 3400c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3401c2248fc9SDouglas Gilbert u64 lba; 3402c2248fc9SDouglas Gilbert u32 num; 3403c2248fc9SDouglas Gilbert int errsts; 3404c2248fc9SDouglas Gilbert 3405c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3406c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3407c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3408c2248fc9SDouglas Gilbert return check_condition_result; 3409c2248fc9SDouglas Gilbert } 3410c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3411c2248fc9SDouglas Gilbert if (errsts) 3412c2248fc9SDouglas Gilbert return errsts; 3413c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3414c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3415c2248fc9SDouglas Gilbert if (errsts) 3416c2248fc9SDouglas Gilbert return errsts; 3417c2248fc9SDouglas Gilbert } 3418c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3419c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3420c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3421c2248fc9SDouglas Gilbert } 3422c2248fc9SDouglas Gilbert 3423c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 3424c4837394SDouglas Gilbert { 3425c4837394SDouglas Gilbert struct sdebug_queue *sqp = sdebug_q_arr; 3426c4837394SDouglas Gilbert 3427c4837394SDouglas Gilbert if (sdebug_mq_active) { 3428c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 3429c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 3430c4837394SDouglas Gilbert 3431c4837394SDouglas Gilbert if (unlikely(hwq >= submit_queues)) { 3432c4837394SDouglas Gilbert pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); 3433c4837394SDouglas Gilbert hwq %= submit_queues; 3434c4837394SDouglas Gilbert } 3435c4837394SDouglas Gilbert pr_debug("tag=%u, hwq=%d\n", tag, hwq); 3436c4837394SDouglas Gilbert return sqp + hwq; 3437c4837394SDouglas Gilbert } else 3438c4837394SDouglas Gilbert return sqp; 3439c4837394SDouglas Gilbert } 3440c4837394SDouglas Gilbert 3441c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 3442fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 34431da177e4SLinus Torvalds { 3444c4837394SDouglas Gilbert int qc_idx; 3445cbf67842SDouglas Gilbert int retiring = 0; 34461da177e4SLinus Torvalds unsigned long iflags; 3447c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3448cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3449cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3450cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 34511da177e4SLinus Torvalds 3452c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 3453c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 3454c4837394SDouglas Gilbert if (sdebug_statistics) { 3455cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3456c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 3457c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 3458c4837394SDouglas Gilbert } 3459c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 3460c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 34611da177e4SLinus Torvalds return; 34621da177e4SLinus Torvalds } 3463c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3464c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 3465cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3466b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 3467c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3468c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 3469c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 34701da177e4SLinus Torvalds return; 34711da177e4SLinus Torvalds } 3472cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3473f46eb0e9SDouglas Gilbert if (likely(devip)) 3474cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3475cbf67842SDouglas Gilbert else 3476c1287970STomas Winkler pr_err("devip=NULL\n"); 3477f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3478cbf67842SDouglas Gilbert retiring = 1; 3479cbf67842SDouglas Gilbert 3480cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3481c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 3482c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3483c1287970STomas Winkler pr_err("Unexpected completion\n"); 3484cbf67842SDouglas Gilbert return; 34851da177e4SLinus Torvalds } 34861da177e4SLinus Torvalds 3487cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3488cbf67842SDouglas Gilbert int k, retval; 3489cbf67842SDouglas Gilbert 3490cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3491c4837394SDouglas Gilbert if (qc_idx >= retval) { 3492c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3493c1287970STomas Winkler pr_err("index %d too large\n", retval); 3494cbf67842SDouglas Gilbert return; 3495cbf67842SDouglas Gilbert } 3496c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 3497773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3498cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3499cbf67842SDouglas Gilbert else 3500cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3501cbf67842SDouglas Gilbert } 3502c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3503cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3504cbf67842SDouglas Gilbert } 3505cbf67842SDouglas Gilbert 3506cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3507fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3508cbf67842SDouglas Gilbert { 3509a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 3510a10bc12aSDouglas Gilbert hrt); 3511a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3512cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3513cbf67842SDouglas Gilbert } 35141da177e4SLinus Torvalds 3515a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 3516fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 3517a10bc12aSDouglas Gilbert { 3518a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 3519a10bc12aSDouglas Gilbert ew.work); 3520a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3521a10bc12aSDouglas Gilbert } 3522a10bc12aSDouglas Gilbert 352309ba24c1SDouglas Gilbert static bool got_shared_uuid; 352409ba24c1SDouglas Gilbert static uuid_be shared_uuid; 352509ba24c1SDouglas Gilbert 3526fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 3527fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 35285cb2fc06SFUJITA Tomonori { 35295cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 35305cb2fc06SFUJITA Tomonori 35315cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 35325cb2fc06SFUJITA Tomonori if (devip) { 353309ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 353409ba24c1SDouglas Gilbert uuid_be_gen(&devip->lu_name); 353509ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 353609ba24c1SDouglas Gilbert if (got_shared_uuid) 353709ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 353809ba24c1SDouglas Gilbert else { 353909ba24c1SDouglas Gilbert uuid_be_gen(&shared_uuid); 354009ba24c1SDouglas Gilbert got_shared_uuid = true; 354109ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 354209ba24c1SDouglas Gilbert } 354309ba24c1SDouglas Gilbert } 35445cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 35455cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 35465cb2fc06SFUJITA Tomonori } 35475cb2fc06SFUJITA Tomonori return devip; 35485cb2fc06SFUJITA Tomonori } 35495cb2fc06SFUJITA Tomonori 3550f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 35511da177e4SLinus Torvalds { 35521da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 35531da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 3554f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 35551da177e4SLinus Torvalds 3556d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 35571da177e4SLinus Torvalds if (!sdbg_host) { 3558c1287970STomas Winkler pr_err("Host info NULL\n"); 35591da177e4SLinus Torvalds return NULL; 35601da177e4SLinus Torvalds } 35611da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 35621da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 35631da177e4SLinus Torvalds (devip->target == sdev->id) && 35641da177e4SLinus Torvalds (devip->lun == sdev->lun)) 35651da177e4SLinus Torvalds return devip; 35661da177e4SLinus Torvalds else { 35671da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 35681da177e4SLinus Torvalds open_devip = devip; 35691da177e4SLinus Torvalds } 35701da177e4SLinus Torvalds } 35715cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 35725cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 35735cb2fc06SFUJITA Tomonori if (!open_devip) { 3574c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 35751da177e4SLinus Torvalds return NULL; 35761da177e4SLinus Torvalds } 35771da177e4SLinus Torvalds } 3578a75869d1SFUJITA Tomonori 35791da177e4SLinus Torvalds open_devip->channel = sdev->channel; 35801da177e4SLinus Torvalds open_devip->target = sdev->id; 35811da177e4SLinus Torvalds open_devip->lun = sdev->lun; 35821da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3583cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3584cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3585c2248fc9SDouglas Gilbert open_devip->used = true; 35861da177e4SLinus Torvalds return open_devip; 35871da177e4SLinus Torvalds } 35881da177e4SLinus Torvalds 35898dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 35901da177e4SLinus Torvalds { 3591773642d9SDouglas Gilbert if (sdebug_verbose) 3592c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 35938dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 359475ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 35958dea0d02SFUJITA Tomonori return 0; 35968dea0d02SFUJITA Tomonori } 35971da177e4SLinus Torvalds 35988dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 35998dea0d02SFUJITA Tomonori { 3600f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3601f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3602a34c4e98SFUJITA Tomonori 3603773642d9SDouglas Gilbert if (sdebug_verbose) 3604c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 36058dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 3606b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 3607b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 3608b01f6f83SDouglas Gilbert if (devip == NULL) { 3609f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 3610b01f6f83SDouglas Gilbert if (devip == NULL) 36118dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3612f46eb0e9SDouglas Gilbert } 3613c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 36146bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 3615773642d9SDouglas Gilbert if (sdebug_no_uld) 361678d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 36178dea0d02SFUJITA Tomonori return 0; 36188dea0d02SFUJITA Tomonori } 36198dea0d02SFUJITA Tomonori 36208dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 36218dea0d02SFUJITA Tomonori { 36228dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 36238dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 36248dea0d02SFUJITA Tomonori 3625773642d9SDouglas Gilbert if (sdebug_verbose) 3626c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 36278dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 36288dea0d02SFUJITA Tomonori if (devip) { 362925985edcSLucas De Marchi /* make this slot available for re-use */ 3630c2248fc9SDouglas Gilbert devip->used = false; 36318dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 36328dea0d02SFUJITA Tomonori } 36338dea0d02SFUJITA Tomonori } 36348dea0d02SFUJITA Tomonori 3635c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp) 3636c4837394SDouglas Gilbert { 3637c4837394SDouglas Gilbert if (!sd_dp) 3638c4837394SDouglas Gilbert return; 3639c4837394SDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) 3640c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3641c4837394SDouglas Gilbert else if (sdebug_jdelay < 0) 3642c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3643c4837394SDouglas Gilbert } 3644c4837394SDouglas Gilbert 3645a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 3646a10bc12aSDouglas Gilbert returns false */ 3647a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 36488dea0d02SFUJITA Tomonori { 36498dea0d02SFUJITA Tomonori unsigned long iflags; 3650c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 3651c4837394SDouglas Gilbert struct sdebug_queue *sqp; 36528dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3653cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3654a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 36558dea0d02SFUJITA Tomonori 3656c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3657c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3658773642d9SDouglas Gilbert qmax = sdebug_max_queue; 3659cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3660cbf67842SDouglas Gilbert if (r_qmax > qmax) 3661cbf67842SDouglas Gilbert qmax = r_qmax; 3662cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3663c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3664c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3665a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 3666a10bc12aSDouglas Gilbert continue; 3667c4837394SDouglas Gilbert /* found */ 3668db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3669db525fceSDouglas Gilbert cmnd->device->hostdata; 3670db525fceSDouglas Gilbert if (devip) 3671db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3672db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3673a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3674c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3675c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3676c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3677a10bc12aSDouglas Gilbert return true; 36788dea0d02SFUJITA Tomonori } 3679cbf67842SDouglas Gilbert } 3680c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3681c4837394SDouglas Gilbert } 3682a10bc12aSDouglas Gilbert return false; 36838dea0d02SFUJITA Tomonori } 36848dea0d02SFUJITA Tomonori 3685a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 36868dea0d02SFUJITA Tomonori static void stop_all_queued(void) 36878dea0d02SFUJITA Tomonori { 36888dea0d02SFUJITA Tomonori unsigned long iflags; 3689c4837394SDouglas Gilbert int j, k; 3690c4837394SDouglas Gilbert struct sdebug_queue *sqp; 36918dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3692cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3693a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 36948dea0d02SFUJITA Tomonori 3695c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3696c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3697c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3698c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3699c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3700c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 3701a10bc12aSDouglas Gilbert continue; 3702db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3703db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3704db525fceSDouglas Gilbert if (devip) 3705db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3706db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3707a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3708c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3709c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3710c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3711c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 37128dea0d02SFUJITA Tomonori } 37138dea0d02SFUJITA Tomonori } 3714c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3715c4837394SDouglas Gilbert } 3716cbf67842SDouglas Gilbert } 3717cbf67842SDouglas Gilbert 3718cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3719cbf67842SDouglas Gilbert static void free_all_queued(void) 3720cbf67842SDouglas Gilbert { 3721c4837394SDouglas Gilbert int j, k; 3722c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3723cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3724cbf67842SDouglas Gilbert 3725c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3726c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3727c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3728a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 3729a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 3730cbf67842SDouglas Gilbert } 37311da177e4SLinus Torvalds } 3732c4837394SDouglas Gilbert } 37331da177e4SLinus Torvalds 37341da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 37351da177e4SLinus Torvalds { 3736a10bc12aSDouglas Gilbert bool ok; 3737a10bc12aSDouglas Gilbert 37381da177e4SLinus Torvalds ++num_aborts; 3739cbf67842SDouglas Gilbert if (SCpnt) { 3740a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 3741a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3742a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3743a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 3744a10bc12aSDouglas Gilbert ok ? "" : " not"); 3745cbf67842SDouglas Gilbert } 37461da177e4SLinus Torvalds return SUCCESS; 37471da177e4SLinus Torvalds } 37481da177e4SLinus Torvalds 37491da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 37501da177e4SLinus Torvalds { 37511da177e4SLinus Torvalds ++num_dev_resets; 3752cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3753cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3754f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3755f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3756cbf67842SDouglas Gilbert 3757773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3758cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 37591da177e4SLinus Torvalds if (devip) 3760cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 37611da177e4SLinus Torvalds } 37621da177e4SLinus Torvalds return SUCCESS; 37631da177e4SLinus Torvalds } 37641da177e4SLinus Torvalds 3765cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3766cbf67842SDouglas Gilbert { 3767cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3768cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3769cbf67842SDouglas Gilbert struct scsi_device *sdp; 3770cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3771cbf67842SDouglas Gilbert int k = 0; 3772cbf67842SDouglas Gilbert 3773cbf67842SDouglas Gilbert ++num_target_resets; 3774cbf67842SDouglas Gilbert if (!SCpnt) 3775cbf67842SDouglas Gilbert goto lie; 3776cbf67842SDouglas Gilbert sdp = SCpnt->device; 3777cbf67842SDouglas Gilbert if (!sdp) 3778cbf67842SDouglas Gilbert goto lie; 3779773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3780cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3781cbf67842SDouglas Gilbert hp = sdp->host; 3782cbf67842SDouglas Gilbert if (!hp) 3783cbf67842SDouglas Gilbert goto lie; 3784cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3785cbf67842SDouglas Gilbert if (sdbg_host) { 3786cbf67842SDouglas Gilbert list_for_each_entry(devip, 3787cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3788cbf67842SDouglas Gilbert dev_list) 3789cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3790cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3791cbf67842SDouglas Gilbert ++k; 3792cbf67842SDouglas Gilbert } 3793cbf67842SDouglas Gilbert } 3794773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3795cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3796cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3797cbf67842SDouglas Gilbert lie: 3798cbf67842SDouglas Gilbert return SUCCESS; 3799cbf67842SDouglas Gilbert } 3800cbf67842SDouglas Gilbert 38011da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 38021da177e4SLinus Torvalds { 38031da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3804cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 38051da177e4SLinus Torvalds struct scsi_device * sdp; 38061da177e4SLinus Torvalds struct Scsi_Host * hp; 3807cbf67842SDouglas Gilbert int k = 0; 38081da177e4SLinus Torvalds 38091da177e4SLinus Torvalds ++num_bus_resets; 3810cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3811cbf67842SDouglas Gilbert goto lie; 3812cbf67842SDouglas Gilbert sdp = SCpnt->device; 3813773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3814cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3815cbf67842SDouglas Gilbert hp = sdp->host; 3816cbf67842SDouglas Gilbert if (hp) { 3817d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 38181da177e4SLinus Torvalds if (sdbg_host) { 3819cbf67842SDouglas Gilbert list_for_each_entry(devip, 38201da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3821cbf67842SDouglas Gilbert dev_list) { 3822cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3823cbf67842SDouglas Gilbert ++k; 38241da177e4SLinus Torvalds } 38251da177e4SLinus Torvalds } 3826cbf67842SDouglas Gilbert } 3827773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3828cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3829cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3830cbf67842SDouglas Gilbert lie: 38311da177e4SLinus Torvalds return SUCCESS; 38321da177e4SLinus Torvalds } 38331da177e4SLinus Torvalds 38341da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 38351da177e4SLinus Torvalds { 38361da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3837cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3838cbf67842SDouglas Gilbert int k = 0; 38391da177e4SLinus Torvalds 38401da177e4SLinus Torvalds ++num_host_resets; 3841773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3842cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 38431da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 38441da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3845cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3846cbf67842SDouglas Gilbert dev_list) { 3847cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3848cbf67842SDouglas Gilbert ++k; 3849cbf67842SDouglas Gilbert } 38501da177e4SLinus Torvalds } 38511da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 38521da177e4SLinus Torvalds stop_all_queued(); 3853773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3854cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3855cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 38561da177e4SLinus Torvalds return SUCCESS; 38571da177e4SLinus Torvalds } 38581da177e4SLinus Torvalds 3859f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 38605f2578e5SFUJITA Tomonori unsigned long store_size) 38611da177e4SLinus Torvalds { 38621da177e4SLinus Torvalds struct partition * pp; 38631da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 38641da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 38651da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 38661da177e4SLinus Torvalds 38671da177e4SLinus Torvalds /* assume partition table already zeroed */ 3868773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 38691da177e4SLinus Torvalds return; 3870773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 3871773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 3872c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 38731da177e4SLinus Torvalds } 3874c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 38751da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 3876773642d9SDouglas Gilbert / sdebug_num_parts; 38771da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 38781da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 3879773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 38801da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 38811da177e4SLinus Torvalds * heads_by_sects; 3882773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 3883773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 38841da177e4SLinus Torvalds 38851da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 38861da177e4SLinus Torvalds ramp[511] = 0xAA; 38871da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 38881da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 38891da177e4SLinus Torvalds start_sec = starts[k]; 38901da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 38911da177e4SLinus Torvalds pp->boot_ind = 0; 38921da177e4SLinus Torvalds 38931da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 38941da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 38951da177e4SLinus Torvalds / sdebug_sectors_per; 38961da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 38971da177e4SLinus Torvalds 38981da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 38991da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 39001da177e4SLinus Torvalds / sdebug_sectors_per; 39011da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 39021da177e4SLinus Torvalds 3903150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3904150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 39051da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 39061da177e4SLinus Torvalds } 39071da177e4SLinus Torvalds } 39081da177e4SLinus Torvalds 3909c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 3910c4837394SDouglas Gilbert { 3911c4837394SDouglas Gilbert int j; 3912c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3913c4837394SDouglas Gilbert 3914c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 3915c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 3916c4837394SDouglas Gilbert } 3917c4837394SDouglas Gilbert 3918c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 3919c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 3920c4837394SDouglas Gilbert */ 3921c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 3922c4837394SDouglas Gilbert { 3923c4837394SDouglas Gilbert int count, modulo; 3924c4837394SDouglas Gilbert 3925c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 3926c4837394SDouglas Gilbert if (modulo < 2) 3927c4837394SDouglas Gilbert return; 3928c4837394SDouglas Gilbert block_unblock_all_queues(true); 3929c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 3930c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 3931c4837394SDouglas Gilbert block_unblock_all_queues(false); 3932c4837394SDouglas Gilbert } 3933c4837394SDouglas Gilbert 3934c4837394SDouglas Gilbert static void clear_queue_stats(void) 3935c4837394SDouglas Gilbert { 3936c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 3937c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 3938c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 3939c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3940c4837394SDouglas Gilbert } 3941c4837394SDouglas Gilbert 3942c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 3943c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 3944c4837394SDouglas Gilbert { 3945c4837394SDouglas Gilbert if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) 3946c4837394SDouglas Gilbert return; 3947c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 3948c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 3949c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 3950c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 3951c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 3952c4837394SDouglas Gilbert } 3953c4837394SDouglas Gilbert 3954c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 3955c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 3956c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 3957c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 3958c4837394SDouglas Gilbert */ 3959fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 3960cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 39611da177e4SLinus Torvalds { 3962cbf67842SDouglas Gilbert unsigned long iflags; 3963cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 3964c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3965c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3966299b6c07STomas Winkler struct scsi_device *sdp; 3967a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 39681da177e4SLinus Torvalds 3969b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 3970b01f6f83SDouglas Gilbert if (scsi_result == 0) 3971f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 3972f46eb0e9SDouglas Gilbert goto respond_in_thread; 39731da177e4SLinus Torvalds } 3974299b6c07STomas Winkler sdp = cmnd->device; 3975299b6c07STomas Winkler 3976f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && scsi_result)) 3977cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 3978cbf67842SDouglas Gilbert __func__, scsi_result); 3979cd62b7daSDouglas Gilbert if (delta_jiff == 0) 3980cd62b7daSDouglas Gilbert goto respond_in_thread; 39811da177e4SLinus Torvalds 3982cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 3983c4837394SDouglas Gilbert sqp = get_queue(cmnd); 3984c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3985c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 3986c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3987c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3988c4837394SDouglas Gilbert } 3989cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 3990cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 3991cbf67842SDouglas Gilbert inject = 0; 3992f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 3993cd62b7daSDouglas Gilbert if (scsi_result) { 3994c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3995cd62b7daSDouglas Gilbert goto respond_in_thread; 3996cd62b7daSDouglas Gilbert } else 3997cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3998c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 3999773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 4000f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 4001cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 4002cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 4003773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 4004cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4005cbf67842SDouglas Gilbert inject = 1; 4006cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 40071da177e4SLinus Torvalds } 4008cbf67842SDouglas Gilbert } 4009cbf67842SDouglas Gilbert 4010c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 4011f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 4012c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4013cd62b7daSDouglas Gilbert if (scsi_result) 4014cd62b7daSDouglas Gilbert goto respond_in_thread; 4015773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 4016cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4017773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 4018cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4019cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 4020773642d9SDouglas Gilbert __func__, sdebug_max_queue, 4021cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 4022cbf67842SDouglas Gilbert "report: host busy")); 4023cd62b7daSDouglas Gilbert if (scsi_result) 4024cd62b7daSDouglas Gilbert goto respond_in_thread; 4025cd62b7daSDouglas Gilbert else 4026cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 40271da177e4SLinus Torvalds } 4028c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 4029cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4030c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 40311da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4032c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 4033cbf67842SDouglas Gilbert cmnd->result = scsi_result; 4034a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 4035c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4036c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 4037c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 4038b01f6f83SDouglas Gilbert if (delta_jiff > 0 || sdebug_ndelay > 0) { 4039b333a819SDouglas Gilbert ktime_t kt; 4040cbf67842SDouglas Gilbert 4041b333a819SDouglas Gilbert if (delta_jiff > 0) { 4042b333a819SDouglas Gilbert struct timespec ts; 4043b333a819SDouglas Gilbert 4044b333a819SDouglas Gilbert jiffies_to_timespec(delta_jiff, &ts); 4045b333a819SDouglas Gilbert kt = ktime_set(ts.tv_sec, ts.tv_nsec); 4046b333a819SDouglas Gilbert } else 4047b333a819SDouglas Gilbert kt = ktime_set(0, sdebug_ndelay); 4048a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4049a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 4050a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4051cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4052a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4053a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 4054c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 4055a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 4056c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4057c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4058cbf67842SDouglas Gilbert } 4059c4837394SDouglas Gilbert if (sdebug_statistics) 4060c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4061c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 4062c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 4063a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4064a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); 4065a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4066cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4067a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4068c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4069c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4070a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 4071cbf67842SDouglas Gilbert } 4072c4837394SDouglas Gilbert if (sdebug_statistics) 4073c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4074a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 4075cbf67842SDouglas Gilbert } 4076f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 4077f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 4078cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4079cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4080cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4081cbf67842SDouglas Gilbert "status: TASK SET FULL"); 40821da177e4SLinus Torvalds return 0; 4083cd62b7daSDouglas Gilbert 4084cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4085cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4086cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4087cd62b7daSDouglas Gilbert return 0; 40881da177e4SLinus Torvalds } 4089cbf67842SDouglas Gilbert 409023183910SDouglas Gilbert /* Note: The following macros create attribute files in the 409123183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 409223183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 409323183910SDouglas Gilbert as it can when the corresponding attribute in the 409423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 409523183910SDouglas Gilbert */ 4096773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 4097773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 4098773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 4099c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 4100773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 4101773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 4102773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 4103773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 4104773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 4105773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 4106773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 4107773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 4108773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 4109773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 4110773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 4111773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 4112773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 4113773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 4114773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 4115773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 4116773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 4117773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 4118773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 4119773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 4120773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 4121773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 4122773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 4123773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 4124773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 4125773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 4126773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 4127c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 4128773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 4129c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 4130773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 4131773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 4132773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 4133773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 4134773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 413509ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 4136773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 413723183910SDouglas Gilbert S_IRUGO | S_IWUSR); 4138773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 41395b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 41401da177e4SLinus Torvalds 41411da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 41421da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 41431da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4144b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 41451da177e4SLinus Torvalds 41461da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 41475b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 41480759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4149cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4150c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 41515b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 41525b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4153c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4154beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 415523183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 41565b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4157185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 41585b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 41595b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 41605b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4161760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz, 4162760f3b03SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 41635b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4164c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4165cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4166cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4167c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 416878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 41691da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4170c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 417132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 41726f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 41735b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 41741da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4175d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4176760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 4177ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4178c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 4179c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 4180c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 41815b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 41825b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 41836014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 41846014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 418509ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 418609ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 4187c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 41885b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 41895b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 41901da177e4SLinus Torvalds 4191760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 4192760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 41931da177e4SLinus Torvalds 41941da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 41951da177e4SLinus Torvalds { 4196c4837394SDouglas Gilbert int k; 4197c4837394SDouglas Gilbert 4198760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 4199760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 4200760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 4201c4837394SDouglas Gilbert return sdebug_info; 4202760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 4203760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 4204760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 4205760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 42061da177e4SLinus Torvalds return sdebug_info; 42071da177e4SLinus Torvalds } 42081da177e4SLinus Torvalds 4209cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4210fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 4211fd32119bSDouglas Gilbert int length) 42121da177e4SLinus Torvalds { 42131da177e4SLinus Torvalds char arr[16]; 4214c8ed555aSAl Viro int opts; 42151da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 42161da177e4SLinus Torvalds 42171da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 42181da177e4SLinus Torvalds return -EACCES; 42191da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 42201da177e4SLinus Torvalds arr[minLen] = '\0'; 4221c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 42221da177e4SLinus Torvalds return -EINVAL; 4223773642d9SDouglas Gilbert sdebug_opts = opts; 4224773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4225773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4226773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4227c4837394SDouglas Gilbert tweak_cmnd_count(); 42281da177e4SLinus Torvalds return length; 42291da177e4SLinus Torvalds } 4230c8ed555aSAl Viro 4231cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4232cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4233cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4234c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4235c8ed555aSAl Viro { 4236c4837394SDouglas Gilbert int f, j, l; 4237c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4238cbf67842SDouglas Gilbert 4239c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 4240c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 4241c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 4242c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 4243c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 4244c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 4245c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 4246c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 4247c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 4248c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 4249c4837394SDouglas Gilbert num_aborts); 4250c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 4251c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 4252c4837394SDouglas Gilbert num_host_resets); 4253c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 4254c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 4255c4837394SDouglas Gilbert seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", 4256c4837394SDouglas Gilbert TICK_NSEC / 1000, "statistics", sdebug_statistics, 4257c4837394SDouglas Gilbert sdebug_mq_active); 4258c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 4259c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 4260c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 4261c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 4262c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 4263cbf67842SDouglas Gilbert 4264c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 4265c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4266c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 4267c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 4268773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4269c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 4270c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 4271c4837394SDouglas Gilbert "first,last bits", f, l); 4272c4837394SDouglas Gilbert } 4273cbf67842SDouglas Gilbert } 4274c8ed555aSAl Viro return 0; 42751da177e4SLinus Torvalds } 42761da177e4SLinus Torvalds 427782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 42781da177e4SLinus Torvalds { 4279c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 42801da177e4SLinus Torvalds } 4281c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 4282c4837394SDouglas Gilbert * of delay is jiffies. 4283c4837394SDouglas Gilbert */ 428482069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 428582069379SAkinobu Mita size_t count) 42861da177e4SLinus Torvalds { 4287c2206098SDouglas Gilbert int jdelay, res; 42881da177e4SLinus Torvalds 4289b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 4290cbf67842SDouglas Gilbert res = count; 4291c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4292c4837394SDouglas Gilbert int j, k; 4293c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4294cbf67842SDouglas Gilbert 4295c4837394SDouglas Gilbert block_unblock_all_queues(true); 4296c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4297c4837394SDouglas Gilbert ++j, ++sqp) { 4298c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4299c4837394SDouglas Gilbert sdebug_max_queue); 4300c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4301c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4302c4837394SDouglas Gilbert break; 4303c4837394SDouglas Gilbert } 4304c4837394SDouglas Gilbert } 4305c4837394SDouglas Gilbert if (res > 0) { 4306a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4307a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4308a10bc12aSDouglas Gilbert free_all_queued(); 4309c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4310773642d9SDouglas Gilbert sdebug_ndelay = 0; 43111da177e4SLinus Torvalds } 4312c4837394SDouglas Gilbert block_unblock_all_queues(false); 4313cbf67842SDouglas Gilbert } 4314cbf67842SDouglas Gilbert return res; 43151da177e4SLinus Torvalds } 43161da177e4SLinus Torvalds return -EINVAL; 43171da177e4SLinus Torvalds } 431882069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 43191da177e4SLinus Torvalds 4320cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4321cbf67842SDouglas Gilbert { 4322773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4323cbf67842SDouglas Gilbert } 4324cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4325c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4326cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4327cbf67842SDouglas Gilbert size_t count) 4328cbf67842SDouglas Gilbert { 4329c4837394SDouglas Gilbert int ndelay, res; 4330cbf67842SDouglas Gilbert 4331cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4332c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 4333cbf67842SDouglas Gilbert res = count; 4334773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4335c4837394SDouglas Gilbert int j, k; 4336c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4337c4837394SDouglas Gilbert 4338c4837394SDouglas Gilbert block_unblock_all_queues(true); 4339c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4340c4837394SDouglas Gilbert ++j, ++sqp) { 4341c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4342c4837394SDouglas Gilbert sdebug_max_queue); 4343c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4344c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4345c4837394SDouglas Gilbert break; 4346c4837394SDouglas Gilbert } 4347c4837394SDouglas Gilbert } 4348c4837394SDouglas Gilbert if (res > 0) { 4349a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4350a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4351a10bc12aSDouglas Gilbert free_all_queued(); 4352773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4353c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4354c2206098SDouglas Gilbert : DEF_JDELAY; 4355cbf67842SDouglas Gilbert } 4356c4837394SDouglas Gilbert block_unblock_all_queues(false); 4357cbf67842SDouglas Gilbert } 4358cbf67842SDouglas Gilbert return res; 4359cbf67842SDouglas Gilbert } 4360cbf67842SDouglas Gilbert return -EINVAL; 4361cbf67842SDouglas Gilbert } 4362cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4363cbf67842SDouglas Gilbert 436482069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 43651da177e4SLinus Torvalds { 4366773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 43671da177e4SLinus Torvalds } 43681da177e4SLinus Torvalds 436982069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 437082069379SAkinobu Mita size_t count) 43711da177e4SLinus Torvalds { 43721da177e4SLinus Torvalds int opts; 43731da177e4SLinus Torvalds char work[20]; 43741da177e4SLinus Torvalds 43751da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 437648a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 43771da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 43781da177e4SLinus Torvalds goto opts_done; 43791da177e4SLinus Torvalds } else { 43801da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 43811da177e4SLinus Torvalds goto opts_done; 43821da177e4SLinus Torvalds } 43831da177e4SLinus Torvalds } 43841da177e4SLinus Torvalds return -EINVAL; 43851da177e4SLinus Torvalds opts_done: 4386773642d9SDouglas Gilbert sdebug_opts = opts; 4387773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4388773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4389c4837394SDouglas Gilbert tweak_cmnd_count(); 43901da177e4SLinus Torvalds return count; 43911da177e4SLinus Torvalds } 439282069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 43931da177e4SLinus Torvalds 439482069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 43951da177e4SLinus Torvalds { 4396773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 43971da177e4SLinus Torvalds } 439882069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 439982069379SAkinobu Mita size_t count) 44001da177e4SLinus Torvalds { 44011da177e4SLinus Torvalds int n; 44021da177e4SLinus Torvalds 44031da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4404773642d9SDouglas Gilbert sdebug_ptype = n; 44051da177e4SLinus Torvalds return count; 44061da177e4SLinus Torvalds } 44071da177e4SLinus Torvalds return -EINVAL; 44081da177e4SLinus Torvalds } 440982069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 44101da177e4SLinus Torvalds 441182069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 44121da177e4SLinus Torvalds { 4413773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 44141da177e4SLinus Torvalds } 441582069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 441682069379SAkinobu Mita size_t count) 44171da177e4SLinus Torvalds { 44181da177e4SLinus Torvalds int n; 44191da177e4SLinus Torvalds 44201da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4421773642d9SDouglas Gilbert sdebug_dsense = n; 44221da177e4SLinus Torvalds return count; 44231da177e4SLinus Torvalds } 44241da177e4SLinus Torvalds return -EINVAL; 44251da177e4SLinus Torvalds } 442682069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 44271da177e4SLinus Torvalds 442882069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 442923183910SDouglas Gilbert { 4430773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 443123183910SDouglas Gilbert } 443282069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 443382069379SAkinobu Mita size_t count) 443423183910SDouglas Gilbert { 443523183910SDouglas Gilbert int n; 443623183910SDouglas Gilbert 443723183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4438cbf67842SDouglas Gilbert n = (n > 0); 4439773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 4440773642d9SDouglas Gilbert if (sdebug_fake_rw != n) { 4441cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4442cbf67842SDouglas Gilbert unsigned long sz = 4443773642d9SDouglas Gilbert (unsigned long)sdebug_dev_size_mb * 4444cbf67842SDouglas Gilbert 1048576; 4445cbf67842SDouglas Gilbert 4446cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4447cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4448c1287970STomas Winkler pr_err("out of memory, 9\n"); 4449cbf67842SDouglas Gilbert return -ENOMEM; 4450cbf67842SDouglas Gilbert } 4451cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4452cbf67842SDouglas Gilbert } 4453773642d9SDouglas Gilbert sdebug_fake_rw = n; 4454cbf67842SDouglas Gilbert } 445523183910SDouglas Gilbert return count; 445623183910SDouglas Gilbert } 445723183910SDouglas Gilbert return -EINVAL; 445823183910SDouglas Gilbert } 445982069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 446023183910SDouglas Gilbert 446182069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4462c65b1445SDouglas Gilbert { 4463773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 4464c65b1445SDouglas Gilbert } 446582069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 446682069379SAkinobu Mita size_t count) 4467c65b1445SDouglas Gilbert { 4468c65b1445SDouglas Gilbert int n; 4469c65b1445SDouglas Gilbert 4470c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4471773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 4472c65b1445SDouglas Gilbert return count; 4473c65b1445SDouglas Gilbert } 4474c65b1445SDouglas Gilbert return -EINVAL; 4475c65b1445SDouglas Gilbert } 447682069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4477c65b1445SDouglas Gilbert 447882069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 44791da177e4SLinus Torvalds { 4480773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 44811da177e4SLinus Torvalds } 448282069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 448382069379SAkinobu Mita size_t count) 44841da177e4SLinus Torvalds { 44851da177e4SLinus Torvalds int n; 44861da177e4SLinus Torvalds 44871da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4488773642d9SDouglas Gilbert sdebug_num_tgts = n; 44891da177e4SLinus Torvalds sdebug_max_tgts_luns(); 44901da177e4SLinus Torvalds return count; 44911da177e4SLinus Torvalds } 44921da177e4SLinus Torvalds return -EINVAL; 44931da177e4SLinus Torvalds } 449482069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 44951da177e4SLinus Torvalds 449682069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 44971da177e4SLinus Torvalds { 4498773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 44991da177e4SLinus Torvalds } 450082069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 45011da177e4SLinus Torvalds 450282069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 45031da177e4SLinus Torvalds { 4504773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 45051da177e4SLinus Torvalds } 450682069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 45071da177e4SLinus Torvalds 450882069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 45091da177e4SLinus Torvalds { 4510773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 45111da177e4SLinus Torvalds } 451282069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 451382069379SAkinobu Mita size_t count) 45141da177e4SLinus Torvalds { 45151da177e4SLinus Torvalds int nth; 45161da177e4SLinus Torvalds 45171da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 4518773642d9SDouglas Gilbert sdebug_every_nth = nth; 4519c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 4520c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 4521c4837394SDouglas Gilbert sdebug_statistics = true; 4522c4837394SDouglas Gilbert } 4523c4837394SDouglas Gilbert tweak_cmnd_count(); 45241da177e4SLinus Torvalds return count; 45251da177e4SLinus Torvalds } 45261da177e4SLinus Torvalds return -EINVAL; 45271da177e4SLinus Torvalds } 452882069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 45291da177e4SLinus Torvalds 453082069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 45311da177e4SLinus Torvalds { 4532773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 45331da177e4SLinus Torvalds } 453482069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 453582069379SAkinobu Mita size_t count) 45361da177e4SLinus Torvalds { 45371da177e4SLinus Torvalds int n; 453819c8ead7SEwan D. Milne bool changed; 45391da177e4SLinus Torvalds 45401da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 45418d039e22SDouglas Gilbert if (n > 256) { 45428d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 45438d039e22SDouglas Gilbert return -EINVAL; 45448d039e22SDouglas Gilbert } 4545773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 4546773642d9SDouglas Gilbert sdebug_max_luns = n; 45471da177e4SLinus Torvalds sdebug_max_tgts_luns(); 4548773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 454919c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 455019c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 455119c8ead7SEwan D. Milne 455219c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 455319c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 455419c8ead7SEwan D. Milne host_list) { 455519c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 455619c8ead7SEwan D. Milne dev_list) { 455719c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 455819c8ead7SEwan D. Milne dp->uas_bm); 455919c8ead7SEwan D. Milne } 456019c8ead7SEwan D. Milne } 456119c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 456219c8ead7SEwan D. Milne } 45631da177e4SLinus Torvalds return count; 45641da177e4SLinus Torvalds } 45651da177e4SLinus Torvalds return -EINVAL; 45661da177e4SLinus Torvalds } 456782069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 45681da177e4SLinus Torvalds 456982069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 457078d4e5a0SDouglas Gilbert { 4571773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 457278d4e5a0SDouglas Gilbert } 4573cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4574cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 457582069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 457682069379SAkinobu Mita size_t count) 457778d4e5a0SDouglas Gilbert { 4578c4837394SDouglas Gilbert int j, n, k, a; 4579c4837394SDouglas Gilbert struct sdebug_queue *sqp; 458078d4e5a0SDouglas Gilbert 458178d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 4582c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 4583c4837394SDouglas Gilbert block_unblock_all_queues(true); 4584c4837394SDouglas Gilbert k = 0; 4585c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4586c4837394SDouglas Gilbert ++j, ++sqp) { 4587c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 4588c4837394SDouglas Gilbert if (a > k) 4589c4837394SDouglas Gilbert k = a; 4590c4837394SDouglas Gilbert } 4591773642d9SDouglas Gilbert sdebug_max_queue = n; 4592c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 4593cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4594cbf67842SDouglas Gilbert else if (k >= n) 4595cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4596cbf67842SDouglas Gilbert else 4597cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4598c4837394SDouglas Gilbert block_unblock_all_queues(false); 459978d4e5a0SDouglas Gilbert return count; 460078d4e5a0SDouglas Gilbert } 460178d4e5a0SDouglas Gilbert return -EINVAL; 460278d4e5a0SDouglas Gilbert } 460382069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 460478d4e5a0SDouglas Gilbert 460582069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 460678d4e5a0SDouglas Gilbert { 4607773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 460878d4e5a0SDouglas Gilbert } 460982069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 461078d4e5a0SDouglas Gilbert 461182069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 46121da177e4SLinus Torvalds { 4613773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 46141da177e4SLinus Torvalds } 461582069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 46161da177e4SLinus Torvalds 461782069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4618c65b1445SDouglas Gilbert { 4619773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 4620c65b1445SDouglas Gilbert } 462182069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 462282069379SAkinobu Mita size_t count) 4623c65b1445SDouglas Gilbert { 4624c65b1445SDouglas Gilbert int n; 46250d01c5dfSDouglas Gilbert bool changed; 4626c65b1445SDouglas Gilbert 4627c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4628773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 4629773642d9SDouglas Gilbert sdebug_virtual_gb = n; 463028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 46310d01c5dfSDouglas Gilbert if (changed) { 46320d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 46330d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 463428898873SFUJITA Tomonori 46354bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 46360d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 46370d01c5dfSDouglas Gilbert host_list) { 46380d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 46390d01c5dfSDouglas Gilbert dev_list) { 46400d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 46410d01c5dfSDouglas Gilbert dp->uas_bm); 46420d01c5dfSDouglas Gilbert } 46430d01c5dfSDouglas Gilbert } 46444bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 46450d01c5dfSDouglas Gilbert } 4646c65b1445SDouglas Gilbert return count; 4647c65b1445SDouglas Gilbert } 4648c65b1445SDouglas Gilbert return -EINVAL; 4649c65b1445SDouglas Gilbert } 465082069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4651c65b1445SDouglas Gilbert 465282069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 46531da177e4SLinus Torvalds { 4654773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host); 46551da177e4SLinus Torvalds } 46561da177e4SLinus Torvalds 4657fd32119bSDouglas Gilbert static int sdebug_add_adapter(void); 4658fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void); 4659fd32119bSDouglas Gilbert 466082069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 466182069379SAkinobu Mita size_t count) 46621da177e4SLinus Torvalds { 46631da177e4SLinus Torvalds int delta_hosts; 46641da177e4SLinus Torvalds 4665f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 46661da177e4SLinus Torvalds return -EINVAL; 46671da177e4SLinus Torvalds if (delta_hosts > 0) { 46681da177e4SLinus Torvalds do { 46691da177e4SLinus Torvalds sdebug_add_adapter(); 46701da177e4SLinus Torvalds } while (--delta_hosts); 46711da177e4SLinus Torvalds } else if (delta_hosts < 0) { 46721da177e4SLinus Torvalds do { 46731da177e4SLinus Torvalds sdebug_remove_adapter(); 46741da177e4SLinus Torvalds } while (++delta_hosts); 46751da177e4SLinus Torvalds } 46761da177e4SLinus Torvalds return count; 46771da177e4SLinus Torvalds } 467882069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 46791da177e4SLinus Torvalds 468082069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 468123183910SDouglas Gilbert { 4682773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 468323183910SDouglas Gilbert } 468482069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 468582069379SAkinobu Mita size_t count) 468623183910SDouglas Gilbert { 468723183910SDouglas Gilbert int n; 468823183910SDouglas Gilbert 468923183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4690773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 469123183910SDouglas Gilbert return count; 469223183910SDouglas Gilbert } 469323183910SDouglas Gilbert return -EINVAL; 469423183910SDouglas Gilbert } 469582069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 469623183910SDouglas Gilbert 4697c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 4698c4837394SDouglas Gilbert { 4699c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 4700c4837394SDouglas Gilbert } 4701c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 4702c4837394SDouglas Gilbert size_t count) 4703c4837394SDouglas Gilbert { 4704c4837394SDouglas Gilbert int n; 4705c4837394SDouglas Gilbert 4706c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 4707c4837394SDouglas Gilbert if (n > 0) 4708c4837394SDouglas Gilbert sdebug_statistics = true; 4709c4837394SDouglas Gilbert else { 4710c4837394SDouglas Gilbert clear_queue_stats(); 4711c4837394SDouglas Gilbert sdebug_statistics = false; 4712c4837394SDouglas Gilbert } 4713c4837394SDouglas Gilbert return count; 4714c4837394SDouglas Gilbert } 4715c4837394SDouglas Gilbert return -EINVAL; 4716c4837394SDouglas Gilbert } 4717c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 4718c4837394SDouglas Gilbert 471982069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4720597136abSMartin K. Petersen { 4721773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 4722597136abSMartin K. Petersen } 472382069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4724597136abSMartin K. Petersen 4725c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 4726c4837394SDouglas Gilbert { 4727c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 4728c4837394SDouglas Gilbert } 4729c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 4730c4837394SDouglas Gilbert 473182069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4732c6a44287SMartin K. Petersen { 4733773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 4734c6a44287SMartin K. Petersen } 473582069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4736c6a44287SMartin K. Petersen 473782069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4738c6a44287SMartin K. Petersen { 4739773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 4740c6a44287SMartin K. Petersen } 474182069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4742c6a44287SMartin K. Petersen 474382069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4744c6a44287SMartin K. Petersen { 4745773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 4746c6a44287SMartin K. Petersen } 474782069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4748c6a44287SMartin K. Petersen 474982069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4750c6a44287SMartin K. Petersen { 4751773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 4752c6a44287SMartin K. Petersen } 475382069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4754c6a44287SMartin K. Petersen 475582069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 475644d92694SMartin K. Petersen { 475744d92694SMartin K. Petersen ssize_t count; 475844d92694SMartin K. Petersen 47595b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 476044d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 476144d92694SMartin K. Petersen sdebug_store_sectors); 476244d92694SMartin K. Petersen 4763c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4764c7badc90STejun Heo (int)map_size, map_storep); 476544d92694SMartin K. Petersen buf[count++] = '\n'; 4766c7badc90STejun Heo buf[count] = '\0'; 476744d92694SMartin K. Petersen 476844d92694SMartin K. Petersen return count; 476944d92694SMartin K. Petersen } 477082069379SAkinobu Mita static DRIVER_ATTR_RO(map); 477144d92694SMartin K. Petersen 477282069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4773d986788bSMartin Pitt { 4774773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 4775d986788bSMartin Pitt } 477682069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 477782069379SAkinobu Mita size_t count) 4778d986788bSMartin Pitt { 4779d986788bSMartin Pitt int n; 4780d986788bSMartin Pitt 4781d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4782773642d9SDouglas Gilbert sdebug_removable = (n > 0); 4783d986788bSMartin Pitt return count; 4784d986788bSMartin Pitt } 4785d986788bSMartin Pitt return -EINVAL; 4786d986788bSMartin Pitt } 478782069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4788d986788bSMartin Pitt 4789cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4790cbf67842SDouglas Gilbert { 4791773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 4792cbf67842SDouglas Gilbert } 4793185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 4794cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4795cbf67842SDouglas Gilbert size_t count) 4796cbf67842SDouglas Gilbert { 4797185dd232SDouglas Gilbert int n; 4798cbf67842SDouglas Gilbert 4799cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4800185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 4801185dd232SDouglas Gilbert return count; 4802cbf67842SDouglas Gilbert } 4803cbf67842SDouglas Gilbert return -EINVAL; 4804cbf67842SDouglas Gilbert } 4805cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4806cbf67842SDouglas Gilbert 4807c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4808c2248fc9SDouglas Gilbert { 4809773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 4810c2248fc9SDouglas Gilbert } 4811c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4812c2248fc9SDouglas Gilbert size_t count) 4813c2248fc9SDouglas Gilbert { 4814c2248fc9SDouglas Gilbert int n; 4815c2248fc9SDouglas Gilbert 4816c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4817773642d9SDouglas Gilbert sdebug_strict = (n > 0); 4818c2248fc9SDouglas Gilbert return count; 4819c2248fc9SDouglas Gilbert } 4820c2248fc9SDouglas Gilbert return -EINVAL; 4821c2248fc9SDouglas Gilbert } 4822c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4823c2248fc9SDouglas Gilbert 482409ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 482509ba24c1SDouglas Gilbert { 482609ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 482709ba24c1SDouglas Gilbert } 482809ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 482909ba24c1SDouglas Gilbert 4830cbf67842SDouglas Gilbert 483182069379SAkinobu Mita /* Note: The following array creates attribute files in the 483223183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 483323183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 483423183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 483523183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 483623183910SDouglas Gilbert */ 48376ecaff7fSRandy Dunlap 483882069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 483982069379SAkinobu Mita &driver_attr_delay.attr, 484082069379SAkinobu Mita &driver_attr_opts.attr, 484182069379SAkinobu Mita &driver_attr_ptype.attr, 484282069379SAkinobu Mita &driver_attr_dsense.attr, 484382069379SAkinobu Mita &driver_attr_fake_rw.attr, 484482069379SAkinobu Mita &driver_attr_no_lun_0.attr, 484582069379SAkinobu Mita &driver_attr_num_tgts.attr, 484682069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 484782069379SAkinobu Mita &driver_attr_num_parts.attr, 484882069379SAkinobu Mita &driver_attr_every_nth.attr, 484982069379SAkinobu Mita &driver_attr_max_luns.attr, 485082069379SAkinobu Mita &driver_attr_max_queue.attr, 485182069379SAkinobu Mita &driver_attr_no_uld.attr, 485282069379SAkinobu Mita &driver_attr_scsi_level.attr, 485382069379SAkinobu Mita &driver_attr_virtual_gb.attr, 485482069379SAkinobu Mita &driver_attr_add_host.attr, 485582069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 485682069379SAkinobu Mita &driver_attr_sector_size.attr, 4857c4837394SDouglas Gilbert &driver_attr_statistics.attr, 4858c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 485982069379SAkinobu Mita &driver_attr_dix.attr, 486082069379SAkinobu Mita &driver_attr_dif.attr, 486182069379SAkinobu Mita &driver_attr_guard.attr, 486282069379SAkinobu Mita &driver_attr_ato.attr, 486382069379SAkinobu Mita &driver_attr_map.attr, 486482069379SAkinobu Mita &driver_attr_removable.attr, 4865cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4866cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4867c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 486809ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 486982069379SAkinobu Mita NULL, 487082069379SAkinobu Mita }; 487182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 48721da177e4SLinus Torvalds 487311ddcecaSAkinobu Mita static struct device *pseudo_primary; 48748dea0d02SFUJITA Tomonori 48751da177e4SLinus Torvalds static int __init scsi_debug_init(void) 48761da177e4SLinus Torvalds { 48775f2578e5SFUJITA Tomonori unsigned long sz; 48781da177e4SLinus Torvalds int host_to_add; 48791da177e4SLinus Torvalds int k; 48806ecaff7fSRandy Dunlap int ret; 48811da177e4SLinus Torvalds 4882cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4883cbf67842SDouglas Gilbert 4884773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 4885c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 4886773642d9SDouglas Gilbert sdebug_ndelay = 0; 4887773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 4888c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 4889cbf67842SDouglas Gilbert 4890773642d9SDouglas Gilbert switch (sdebug_sector_size) { 4891597136abSMartin K. Petersen case 512: 4892597136abSMartin K. Petersen case 1024: 4893597136abSMartin K. Petersen case 2048: 4894597136abSMartin K. Petersen case 4096: 4895597136abSMartin K. Petersen break; 4896597136abSMartin K. Petersen default: 4897773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 4898597136abSMartin K. Petersen return -EINVAL; 4899597136abSMartin K. Petersen } 4900597136abSMartin K. Petersen 4901773642d9SDouglas Gilbert switch (sdebug_dif) { 4902c6a44287SMartin K. Petersen 4903c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 4904f46eb0e9SDouglas Gilbert break; 4905c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4906395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4907c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4908f46eb0e9SDouglas Gilbert have_dif_prot = true; 4909c6a44287SMartin K. Petersen break; 4910c6a44287SMartin K. Petersen 4911c6a44287SMartin K. Petersen default: 4912c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 4913c6a44287SMartin K. Petersen return -EINVAL; 4914c6a44287SMartin K. Petersen } 4915c6a44287SMartin K. Petersen 4916773642d9SDouglas Gilbert if (sdebug_guard > 1) { 4917c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 4918c6a44287SMartin K. Petersen return -EINVAL; 4919c6a44287SMartin K. Petersen } 4920c6a44287SMartin K. Petersen 4921773642d9SDouglas Gilbert if (sdebug_ato > 1) { 4922c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 4923c6a44287SMartin K. Petersen return -EINVAL; 4924c6a44287SMartin K. Petersen } 4925c6a44287SMartin K. Petersen 4926773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 4927773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 4928ea61fca5SMartin K. Petersen return -EINVAL; 4929ea61fca5SMartin K. Petersen } 49308d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 49318d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 49328d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 49338d039e22SDouglas Gilbert } 4934ea61fca5SMartin K. Petersen 4935773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 4936773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 4937ea61fca5SMartin K. Petersen return -EINVAL; 4938ea61fca5SMartin K. Petersen } 4939ea61fca5SMartin K. Petersen 4940c4837394SDouglas Gilbert if (submit_queues < 1) { 4941c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 4942c4837394SDouglas Gilbert return -EINVAL; 4943c4837394SDouglas Gilbert } 4944c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 4945c4837394SDouglas Gilbert GFP_KERNEL); 4946c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 4947c4837394SDouglas Gilbert return -ENOMEM; 4948c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 4949c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 4950c4837394SDouglas Gilbert 4951773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 4952773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 4953773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 4954773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 495528898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 49561da177e4SLinus Torvalds 49571da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 49581da177e4SLinus Torvalds sdebug_heads = 8; 49591da177e4SLinus Torvalds sdebug_sectors_per = 32; 4960773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 49611da177e4SLinus Torvalds sdebug_heads = 64; 4962773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 4963fa785f0aSAndy Shevchenko sdebug_heads = 32; 49641da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 49651da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 49661da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 49671da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 49681da177e4SLinus Torvalds sdebug_heads = 255; 49691da177e4SLinus Torvalds sdebug_sectors_per = 63; 49701da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 49711da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 49721da177e4SLinus Torvalds } 49731da177e4SLinus Torvalds 4974b01f6f83SDouglas Gilbert if (sdebug_fake_rw == 0) { 49751da177e4SLinus Torvalds fake_storep = vmalloc(sz); 49761da177e4SLinus Torvalds if (NULL == fake_storep) { 4977c1287970STomas Winkler pr_err("out of memory, 1\n"); 4978c4837394SDouglas Gilbert ret = -ENOMEM; 4979c4837394SDouglas Gilbert goto free_q_arr; 49801da177e4SLinus Torvalds } 49811da177e4SLinus Torvalds memset(fake_storep, 0, sz); 4982773642d9SDouglas Gilbert if (sdebug_num_parts > 0) 4983f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 4984cbf67842SDouglas Gilbert } 49851da177e4SLinus Torvalds 4986773642d9SDouglas Gilbert if (sdebug_dix) { 4987c6a44287SMartin K. Petersen int dif_size; 4988c6a44287SMartin K. Petersen 4989c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 4990c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 4991c6a44287SMartin K. Petersen 4992c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 4993c6a44287SMartin K. Petersen 4994c6a44287SMartin K. Petersen if (dif_storep == NULL) { 4995c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 4996c6a44287SMartin K. Petersen ret = -ENOMEM; 4997c6a44287SMartin K. Petersen goto free_vm; 4998c6a44287SMartin K. Petersen } 4999c6a44287SMartin K. Petersen 5000c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 5001c6a44287SMartin K. Petersen } 5002c6a44287SMartin K. Petersen 50035b94e232SMartin K. Petersen /* Logical Block Provisioning */ 50045b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 5005773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 5006773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 50076014759cSMartin K. Petersen 5008773642d9SDouglas Gilbert sdebug_unmap_max_desc = 5009773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 50106014759cSMartin K. Petersen 5011773642d9SDouglas Gilbert sdebug_unmap_granularity = 5012773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 50136014759cSMartin K. Petersen 5014773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 5015773642d9SDouglas Gilbert sdebug_unmap_granularity <= 5016773642d9SDouglas Gilbert sdebug_unmap_alignment) { 5017c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 5018c4837394SDouglas Gilbert ret = -EINVAL; 5019c4837394SDouglas Gilbert goto free_vm; 502044d92694SMartin K. Petersen } 502144d92694SMartin K. Petersen 5022b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 5023b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 502444d92694SMartin K. Petersen 5025c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 502644d92694SMartin K. Petersen 502744d92694SMartin K. Petersen if (map_storep == NULL) { 5028c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 502944d92694SMartin K. Petersen ret = -ENOMEM; 503044d92694SMartin K. Petersen goto free_vm; 503144d92694SMartin K. Petersen } 503244d92694SMartin K. Petersen 5033b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 503444d92694SMartin K. Petersen 503544d92694SMartin K. Petersen /* Map first 1KB for partition table */ 5036773642d9SDouglas Gilbert if (sdebug_num_parts) 503744d92694SMartin K. Petersen map_region(0, 2); 503844d92694SMartin K. Petersen } 503944d92694SMartin K. Petersen 50409b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 50419b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 5042c1287970STomas Winkler pr_warn("root_device_register() error\n"); 50439b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 50446ecaff7fSRandy Dunlap goto free_vm; 50456ecaff7fSRandy Dunlap } 50466ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 50476ecaff7fSRandy Dunlap if (ret < 0) { 5048c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 50496ecaff7fSRandy Dunlap goto dev_unreg; 50506ecaff7fSRandy Dunlap } 50516ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 50526ecaff7fSRandy Dunlap if (ret < 0) { 5053c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 50546ecaff7fSRandy Dunlap goto bus_unreg; 50556ecaff7fSRandy Dunlap } 50561da177e4SLinus Torvalds 5057773642d9SDouglas Gilbert host_to_add = sdebug_add_host; 5058773642d9SDouglas Gilbert sdebug_add_host = 0; 50591da177e4SLinus Torvalds 50601da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 50611da177e4SLinus Torvalds if (sdebug_add_adapter()) { 5062c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 50631da177e4SLinus Torvalds break; 50641da177e4SLinus Torvalds } 50651da177e4SLinus Torvalds } 50661da177e4SLinus Torvalds 5067773642d9SDouglas Gilbert if (sdebug_verbose) 5068773642d9SDouglas Gilbert pr_info("built %d host(s)\n", sdebug_add_host); 5069c1287970STomas Winkler 50701da177e4SLinus Torvalds return 0; 50716ecaff7fSRandy Dunlap 50726ecaff7fSRandy Dunlap bus_unreg: 50736ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 50746ecaff7fSRandy Dunlap dev_unreg: 50759b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 50766ecaff7fSRandy Dunlap free_vm: 507744d92694SMartin K. Petersen vfree(map_storep); 5078c6a44287SMartin K. Petersen vfree(dif_storep); 50796ecaff7fSRandy Dunlap vfree(fake_storep); 5080c4837394SDouglas Gilbert free_q_arr: 5081c4837394SDouglas Gilbert kfree(sdebug_q_arr); 50826ecaff7fSRandy Dunlap return ret; 50831da177e4SLinus Torvalds } 50841da177e4SLinus Torvalds 50851da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 50861da177e4SLinus Torvalds { 5087773642d9SDouglas Gilbert int k = sdebug_add_host; 50881da177e4SLinus Torvalds 50891da177e4SLinus Torvalds stop_all_queued(); 5090cbf67842SDouglas Gilbert free_all_queued(); 50911da177e4SLinus Torvalds for (; k; k--) 50921da177e4SLinus Torvalds sdebug_remove_adapter(); 50931da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 50941da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 50959b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 50961da177e4SLinus Torvalds 5097c6a44287SMartin K. Petersen vfree(dif_storep); 50981da177e4SLinus Torvalds vfree(fake_storep); 5099c4837394SDouglas Gilbert kfree(sdebug_q_arr); 51001da177e4SLinus Torvalds } 51011da177e4SLinus Torvalds 51021da177e4SLinus Torvalds device_initcall(scsi_debug_init); 51031da177e4SLinus Torvalds module_exit(scsi_debug_exit); 51041da177e4SLinus Torvalds 51051da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 51061da177e4SLinus Torvalds { 51071da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51081da177e4SLinus Torvalds 51091da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 51101da177e4SLinus Torvalds kfree(sdbg_host); 51111da177e4SLinus Torvalds } 51121da177e4SLinus Torvalds 51131da177e4SLinus Torvalds static int sdebug_add_adapter(void) 51141da177e4SLinus Torvalds { 51151da177e4SLinus Torvalds int k, devs_per_host; 51161da177e4SLinus Torvalds int error = 0; 51171da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51188b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 51191da177e4SLinus Torvalds 512024669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 51211da177e4SLinus Torvalds if (NULL == sdbg_host) { 5122c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51231da177e4SLinus Torvalds return -ENOMEM; 51241da177e4SLinus Torvalds } 51251da177e4SLinus Torvalds 51261da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 51271da177e4SLinus Torvalds 5128773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 51291da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 51305cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 51315cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 5132c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51331da177e4SLinus Torvalds error = -ENOMEM; 51341da177e4SLinus Torvalds goto clean; 51351da177e4SLinus Torvalds } 51361da177e4SLinus Torvalds } 51371da177e4SLinus Torvalds 51381da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51391da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 51401da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51411da177e4SLinus Torvalds 51421da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 51439b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 51441da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 5145773642d9SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host); 51461da177e4SLinus Torvalds 51471da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 51481da177e4SLinus Torvalds 51491da177e4SLinus Torvalds if (error) 51501da177e4SLinus Torvalds goto clean; 51511da177e4SLinus Torvalds 5152773642d9SDouglas Gilbert ++sdebug_add_host; 51531da177e4SLinus Torvalds return error; 51541da177e4SLinus Torvalds 51551da177e4SLinus Torvalds clean: 51568b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 51578b40228fSFUJITA Tomonori dev_list) { 51581da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 51591da177e4SLinus Torvalds kfree(sdbg_devinfo); 51601da177e4SLinus Torvalds } 51611da177e4SLinus Torvalds 51621da177e4SLinus Torvalds kfree(sdbg_host); 51631da177e4SLinus Torvalds return error; 51641da177e4SLinus Torvalds } 51651da177e4SLinus Torvalds 51661da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 51671da177e4SLinus Torvalds { 51681da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 51691da177e4SLinus Torvalds 51701da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51711da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 51721da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 51731da177e4SLinus Torvalds struct sdebug_host_info, host_list); 51741da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 51751da177e4SLinus Torvalds } 51761da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51771da177e4SLinus Torvalds 51781da177e4SLinus Torvalds if (!sdbg_host) 51791da177e4SLinus Torvalds return; 51801da177e4SLinus Torvalds 51811da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 5182773642d9SDouglas Gilbert --sdebug_add_host; 51831da177e4SLinus Torvalds } 51841da177e4SLinus Torvalds 5185fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 5186cbf67842SDouglas Gilbert { 5187cbf67842SDouglas Gilbert int num_in_q = 0; 5188cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5189cbf67842SDouglas Gilbert 5190c4837394SDouglas Gilbert block_unblock_all_queues(true); 5191cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 5192cbf67842SDouglas Gilbert if (NULL == devip) { 5193c4837394SDouglas Gilbert block_unblock_all_queues(false); 5194cbf67842SDouglas Gilbert return -ENODEV; 5195cbf67842SDouglas Gilbert } 5196cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5197c40ecc12SChristoph Hellwig 5198cbf67842SDouglas Gilbert if (qdepth < 1) 5199cbf67842SDouglas Gilbert qdepth = 1; 5200c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 5201c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 5202c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 5203db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 5204cbf67842SDouglas Gilbert 5205773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 5206c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 5207c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 5208cbf67842SDouglas Gilbert } 5209c4837394SDouglas Gilbert block_unblock_all_queues(false); 5210cbf67842SDouglas Gilbert return sdev->queue_depth; 5211cbf67842SDouglas Gilbert } 5212cbf67842SDouglas Gilbert 5213c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 5214817fd66bSDouglas Gilbert { 5215c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 5216773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 5217773642d9SDouglas Gilbert sdebug_every_nth = -1; 5218773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 5219c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 5220773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 5221817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5222c4837394SDouglas Gilbert return true; /* time out reads and writes */ 5223817fd66bSDouglas Gilbert } 5224c4837394SDouglas Gilbert return false; 5225817fd66bSDouglas Gilbert } 5226817fd66bSDouglas Gilbert 5227fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 5228fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 5229c2248fc9SDouglas Gilbert { 5230c2248fc9SDouglas Gilbert u8 sdeb_i; 5231c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5232c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5233c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5234c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5235c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5236c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5237c2248fc9SDouglas Gilbert int k, na; 5238c2248fc9SDouglas Gilbert int errsts = 0; 5239c2248fc9SDouglas Gilbert u32 flags; 5240c2248fc9SDouglas Gilbert u16 sa; 5241c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5242c2248fc9SDouglas Gilbert bool has_wlun_rl; 5243c2248fc9SDouglas Gilbert 5244c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5245c4837394SDouglas Gilbert if (sdebug_statistics) 5246c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 5247f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 5248f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 5249c2248fc9SDouglas Gilbert char b[120]; 5250c2248fc9SDouglas Gilbert int n, len, sb; 5251c2248fc9SDouglas Gilbert 5252c2248fc9SDouglas Gilbert len = scp->cmd_len; 5253c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5254c2248fc9SDouglas Gilbert if (len > 32) 5255c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5256c2248fc9SDouglas Gilbert else { 5257c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5258c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5259c2248fc9SDouglas Gilbert (u32)cmd[k]); 5260c2248fc9SDouglas Gilbert } 5261c4837394SDouglas Gilbert if (sdebug_mq_active) 5262c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", 5263c4837394SDouglas Gilbert my_name, blk_mq_unique_tag(scp->request), 5264c4837394SDouglas Gilbert b); 5265c4837394SDouglas Gilbert else 5266c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, 5267c4837394SDouglas Gilbert b); 5268c2248fc9SDouglas Gilbert } 526934d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 5270f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 5271f46eb0e9SDouglas Gilbert goto err_out; 5272c2248fc9SDouglas Gilbert 5273c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5274c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5275c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5276f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 5277f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5278c2248fc9SDouglas Gilbert if (NULL == devip) 5279f46eb0e9SDouglas Gilbert goto err_out; 5280c2248fc9SDouglas Gilbert } 5281c2248fc9SDouglas Gilbert na = oip->num_attached; 5282c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5283c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5284c2248fc9SDouglas Gilbert r_oip = oip; 5285c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5286c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5287c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5288c2248fc9SDouglas Gilbert else 5289c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5290c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5291c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5292c2248fc9SDouglas Gilbert break; 5293c2248fc9SDouglas Gilbert } 5294c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5295c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5296c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5297c2248fc9SDouglas Gilbert break; 5298c2248fc9SDouglas Gilbert } 5299c2248fc9SDouglas Gilbert } 5300c2248fc9SDouglas Gilbert if (k > na) { 5301c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5302c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5303c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5304c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5305c2248fc9SDouglas Gilbert else 5306c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5307c2248fc9SDouglas Gilbert goto check_cond; 5308c2248fc9SDouglas Gilbert } 5309c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5310c2248fc9SDouglas Gilbert flags = oip->flags; 5311f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 5312c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5313c2248fc9SDouglas Gilbert goto check_cond; 5314c2248fc9SDouglas Gilbert } 5315f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 5316773642d9SDouglas Gilbert if (sdebug_verbose) 5317773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 5318773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 5319c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5320c2248fc9SDouglas Gilbert goto check_cond; 5321c2248fc9SDouglas Gilbert } 5322f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 5323c2248fc9SDouglas Gilbert u8 rem; 5324c2248fc9SDouglas Gilbert int j; 5325c2248fc9SDouglas Gilbert 5326c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5327c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5328c2248fc9SDouglas Gilbert if (rem) { 5329c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5330c2248fc9SDouglas Gilbert if (0x80 & rem) 5331c2248fc9SDouglas Gilbert break; 5332c2248fc9SDouglas Gilbert } 5333c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5334c2248fc9SDouglas Gilbert goto check_cond; 5335c2248fc9SDouglas Gilbert } 5336c2248fc9SDouglas Gilbert } 5337c2248fc9SDouglas Gilbert } 5338f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 5339b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 5340b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 5341f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 5342c2248fc9SDouglas Gilbert if (errsts) 5343c2248fc9SDouglas Gilbert goto check_cond; 5344c2248fc9SDouglas Gilbert } 5345c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 5346c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5347773642d9SDouglas Gilbert if (sdebug_verbose) 5348c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5349c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5350c2248fc9SDouglas Gilbert "required"); 5351c2248fc9SDouglas Gilbert errsts = check_condition_result; 5352c2248fc9SDouglas Gilbert goto fini; 5353c2248fc9SDouglas Gilbert } 5354773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 5355c2248fc9SDouglas Gilbert goto fini; 5356f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 5357c4837394SDouglas Gilbert if (fake_timeout(scp)) 5358c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5359c2248fc9SDouglas Gilbert } 5360f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 5361f46eb0e9SDouglas Gilbert errsts = oip->pfp(scp, devip); /* calls a resp_* function */ 5362c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5363c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5364c2248fc9SDouglas Gilbert 5365c2248fc9SDouglas Gilbert fini: 5366c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5367c2206098SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay)); 5368c2248fc9SDouglas Gilbert check_cond: 5369c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5370f46eb0e9SDouglas Gilbert err_out: 5371f46eb0e9SDouglas Gilbert return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0); 5372c2248fc9SDouglas Gilbert } 5373c2248fc9SDouglas Gilbert 53749e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5375c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5376c8ed555aSAl Viro .write_info = scsi_debug_write_info, 53779e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 53789e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 53799e603ca0SFUJITA Tomonori .info = scsi_debug_info, 53809e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 53819e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 53829e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 53839e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5384185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 5385cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 53869e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 53879e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5388cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5389cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 53909e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 5391c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 53929e603ca0SFUJITA Tomonori .this_id = 7, 539365e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 5394cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 53956bb5e6e7SAkinobu Mita .max_sectors = -1U, 53969e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 53979e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5398c40ecc12SChristoph Hellwig .track_queue_depth = 1, 53999e603ca0SFUJITA Tomonori }; 54009e603ca0SFUJITA Tomonori 54011da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 54021da177e4SLinus Torvalds { 54031da177e4SLinus Torvalds int error = 0; 54041da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 54051da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5406f46eb0e9SDouglas Gilbert int hprot; 54071da177e4SLinus Torvalds 54081da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 54091da177e4SLinus Torvalds 5410773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 5411773642d9SDouglas Gilbert if (sdebug_clustering) 54120759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 54131da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 54141da177e4SLinus Torvalds if (NULL == hpnt) { 5415c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 54161da177e4SLinus Torvalds error = -ENODEV; 54171da177e4SLinus Torvalds return error; 54181da177e4SLinus Torvalds } 5419c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 5420c4837394SDouglas Gilbert pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n", 5421c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 5422c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 5423c4837394SDouglas Gilbert } 5424c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 5425c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 5426c4837394SDouglas Gilbert sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); 5427c4837394SDouglas Gilbert if (sdebug_mq_active) 5428c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 54291da177e4SLinus Torvalds 54301da177e4SLinus Torvalds sdbg_host->shost = hpnt; 54311da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 5432773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 5433773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 54341da177e4SLinus Torvalds else 5435773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 5436773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 5437f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 54381da177e4SLinus Torvalds 5439f46eb0e9SDouglas Gilbert hprot = 0; 5440c6a44287SMartin K. Petersen 5441773642d9SDouglas Gilbert switch (sdebug_dif) { 5442c6a44287SMartin K. Petersen 5443c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 5444f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 5445773642d9SDouglas Gilbert if (sdebug_dix) 5446f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 5447c6a44287SMartin K. Petersen break; 5448c6a44287SMartin K. Petersen 5449c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 5450f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 5451773642d9SDouglas Gilbert if (sdebug_dix) 5452f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 5453c6a44287SMartin K. Petersen break; 5454c6a44287SMartin K. Petersen 5455c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 5456f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 5457773642d9SDouglas Gilbert if (sdebug_dix) 5458f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 5459c6a44287SMartin K. Petersen break; 5460c6a44287SMartin K. Petersen 5461c6a44287SMartin K. Petersen default: 5462773642d9SDouglas Gilbert if (sdebug_dix) 5463f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 5464c6a44287SMartin K. Petersen break; 5465c6a44287SMartin K. Petersen } 5466c6a44287SMartin K. Petersen 5467f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 5468c6a44287SMartin K. Petersen 5469f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 5470c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5471f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5472f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5473f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5474f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5475f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5476f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5477f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5478c6a44287SMartin K. Petersen 5479773642d9SDouglas Gilbert if (sdebug_guard == 1) 5480c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5481c6a44287SMartin K. Petersen else 5482c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5483c6a44287SMartin K. Petersen 5484773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 5485773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 5486c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 5487c4837394SDouglas Gilbert sdebug_statistics = true; 54881da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 54891da177e4SLinus Torvalds if (error) { 5490c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 54911da177e4SLinus Torvalds error = -ENODEV; 54921da177e4SLinus Torvalds scsi_host_put(hpnt); 54931da177e4SLinus Torvalds } else 54941da177e4SLinus Torvalds scsi_scan_host(hpnt); 54951da177e4SLinus Torvalds 54961da177e4SLinus Torvalds return error; 54971da177e4SLinus Torvalds } 54981da177e4SLinus Torvalds 54991da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 55001da177e4SLinus Torvalds { 55011da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 55028b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 55031da177e4SLinus Torvalds 55041da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 55051da177e4SLinus Torvalds 55061da177e4SLinus Torvalds if (!sdbg_host) { 5507c1287970STomas Winkler pr_err("Unable to locate host info\n"); 55081da177e4SLinus Torvalds return -ENODEV; 55091da177e4SLinus Torvalds } 55101da177e4SLinus Torvalds 55111da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 55121da177e4SLinus Torvalds 55138b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 55148b40228fSFUJITA Tomonori dev_list) { 55151da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 55161da177e4SLinus Torvalds kfree(sdbg_devinfo); 55171da177e4SLinus Torvalds } 55181da177e4SLinus Torvalds 55191da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 55201da177e4SLinus Torvalds return 0; 55211da177e4SLinus Torvalds } 55221da177e4SLinus Torvalds 55238dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 55248dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 55251da177e4SLinus Torvalds { 55268dea0d02SFUJITA Tomonori return 1; 55278dea0d02SFUJITA Tomonori } 55281da177e4SLinus Torvalds 55298dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 55308dea0d02SFUJITA Tomonori .name = "pseudo", 55318dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 55328dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 55338dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 553482069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 55358dea0d02SFUJITA Tomonori }; 5536