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 '.' */ 9281b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 9291b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 9301b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 9311b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 9321da177e4SLinus Torvalds 933cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 934760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 9355a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 93609ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 93709ba24c1SDouglas Gilbert const uuid_be *lu_name) 9381da177e4SLinus Torvalds { 939c65b1445SDouglas Gilbert int num, port_a; 940c65b1445SDouglas Gilbert char b[32]; 9411da177e4SLinus Torvalds 942c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 9431da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 9441da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 9451da177e4SLinus Torvalds arr[1] = 0x1; 9461da177e4SLinus Torvalds arr[2] = 0x0; 9471da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 9481da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 9491da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 9501da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9511da177e4SLinus Torvalds arr[3] = num; 9521da177e4SLinus Torvalds num += 4; 953c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 95409ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 95509ba24c1SDouglas Gilbert /* Locally assigned UUID */ 95609ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 95709ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 95809ba24c1SDouglas Gilbert arr[num++] = 0x0; 95909ba24c1SDouglas Gilbert arr[num++] = 0x12; 96009ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 96109ba24c1SDouglas Gilbert arr[num++] = 0x0; 96209ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 96309ba24c1SDouglas Gilbert num += 16; 96409ba24c1SDouglas Gilbert } else { 9651b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 966c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 967c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 968c65b1445SDouglas Gilbert arr[num++] = 0x0; 969c65b1445SDouglas Gilbert arr[num++] = 0x8; 9701b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 971773642d9SDouglas Gilbert num += 8; 97209ba24c1SDouglas Gilbert } 973c65b1445SDouglas Gilbert /* Target relative port number */ 974c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 975c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 976c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 977c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 978c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 979c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 980c65b1445SDouglas Gilbert arr[num++] = 0x0; 981c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 982c65b1445SDouglas Gilbert } 9831b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 984c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 985c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 986c65b1445SDouglas Gilbert arr[num++] = 0x0; 987c65b1445SDouglas Gilbert arr[num++] = 0x8; 9881b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 989773642d9SDouglas Gilbert num += 8; 9901b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 9915a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 9925a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 9935a09e398SHannes Reinecke arr[num++] = 0x0; 9945a09e398SHannes Reinecke arr[num++] = 0x4; 9955a09e398SHannes Reinecke arr[num++] = 0; 9965a09e398SHannes Reinecke arr[num++] = 0; 997773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 998773642d9SDouglas Gilbert num += 2; 9991b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1000c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1001c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1002c65b1445SDouglas Gilbert arr[num++] = 0x0; 1003c65b1445SDouglas Gilbert arr[num++] = 0x8; 10041b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1005773642d9SDouglas Gilbert num += 8; 1006c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1007c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1008c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1009c65b1445SDouglas Gilbert arr[num++] = 0x0; 1010c65b1445SDouglas Gilbert arr[num++] = 24; 10111b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1012c65b1445SDouglas Gilbert num += 12; 1013c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1014c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1015c65b1445SDouglas Gilbert num += 8; 1016c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1017c65b1445SDouglas Gilbert num += 4; 1018c65b1445SDouglas Gilbert return num; 1019c65b1445SDouglas Gilbert } 1020c65b1445SDouglas Gilbert 1021c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1022c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1023c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1024c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1025c65b1445SDouglas Gilbert }; 1026c65b1445SDouglas Gilbert 1027cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1028760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1029c65b1445SDouglas Gilbert { 1030c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1031c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1032c65b1445SDouglas Gilbert } 1033c65b1445SDouglas Gilbert 1034cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1035760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1036c65b1445SDouglas Gilbert { 1037c65b1445SDouglas Gilbert int num = 0; 1038c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1039c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1040c65b1445SDouglas Gilbert int plen, olen; 1041c65b1445SDouglas Gilbert 1042c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1043c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1044c65b1445SDouglas Gilbert arr[num++] = 0x0; 1045c65b1445SDouglas Gilbert olen = strlen(na1); 1046c65b1445SDouglas Gilbert plen = olen + 1; 1047c65b1445SDouglas Gilbert if (plen % 4) 1048c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1049c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1050c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1051c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1052c65b1445SDouglas Gilbert num += plen; 1053c65b1445SDouglas Gilbert 1054c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1055c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1056c65b1445SDouglas Gilbert arr[num++] = 0x0; 1057c65b1445SDouglas Gilbert olen = strlen(na2); 1058c65b1445SDouglas Gilbert plen = olen + 1; 1059c65b1445SDouglas Gilbert if (plen % 4) 1060c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1061c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1062c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1063c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1064c65b1445SDouglas Gilbert num += plen; 1065c65b1445SDouglas Gilbert 1066c65b1445SDouglas Gilbert return num; 1067c65b1445SDouglas Gilbert } 1068c65b1445SDouglas Gilbert 1069c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1070760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1071c65b1445SDouglas Gilbert { 1072c65b1445SDouglas Gilbert int num = 0; 1073c65b1445SDouglas Gilbert int port_a, port_b; 1074c65b1445SDouglas Gilbert 1075c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1076c65b1445SDouglas Gilbert port_b = port_a + 1; 1077c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1078c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1079c65b1445SDouglas Gilbert arr[num++] = 0x0; 1080c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1081c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1082c65b1445SDouglas Gilbert num += 6; 1083c65b1445SDouglas Gilbert arr[num++] = 0x0; 1084c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1085c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1086c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1087c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1088c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1089c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 10901b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1091773642d9SDouglas Gilbert num += 8; 1092c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1093c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1094c65b1445SDouglas Gilbert arr[num++] = 0x0; 1095c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1096c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1097c65b1445SDouglas Gilbert num += 6; 1098c65b1445SDouglas Gilbert arr[num++] = 0x0; 1099c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1100c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1101c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1102c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1103c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1104c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 11051b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1106773642d9SDouglas Gilbert num += 8; 1107c65b1445SDouglas Gilbert 1108c65b1445SDouglas Gilbert return num; 1109c65b1445SDouglas Gilbert } 1110c65b1445SDouglas Gilbert 1111c65b1445SDouglas Gilbert 1112c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1113c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1114c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1115c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1116c65b1445SDouglas Gilbert '1','2','3','4', 1117c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1118c65b1445SDouglas Gilbert 0xec,0,0,0, 1119c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1120c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1121c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1122c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1123c65b1445SDouglas Gilbert 0x53,0x41, 1124c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1125c65b1445SDouglas Gilbert 0x20,0x20, 1126c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1127c65b1445SDouglas Gilbert 0x10,0x80, 1128c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1129c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1130c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1131c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1132c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1133c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1134c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,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 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1138c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1139c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1140c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1141c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0, 1153c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1154c65b1445SDouglas Gilbert }; 1155c65b1445SDouglas Gilbert 1156cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1157760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1158c65b1445SDouglas Gilbert { 1159c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1160c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1161c65b1445SDouglas Gilbert } 1162c65b1445SDouglas Gilbert 1163c65b1445SDouglas Gilbert 1164c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11651e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 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, 11681e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1169c65b1445SDouglas Gilbert }; 1170c65b1445SDouglas Gilbert 1171cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1172760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1173c65b1445SDouglas Gilbert { 1174ea61fca5SMartin K. Petersen unsigned int gran; 1175ea61fca5SMartin K. Petersen 1176c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1177e308b3d1SMartin K. Petersen 1178e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 1179773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1180773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1181e308b3d1SMartin K. Petersen 1182e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1183773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1184773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 118544d92694SMartin K. Petersen 1186e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1187773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1188e308b3d1SMartin K. Petersen 1189773642d9SDouglas Gilbert if (sdebug_lbpu) { 1190e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1191773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1192e308b3d1SMartin K. Petersen 1193e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1194773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 119544d92694SMartin K. Petersen } 119644d92694SMartin K. Petersen 1197e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1198773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1199773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 120044d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 120144d92694SMartin K. Petersen } 120244d92694SMartin K. Petersen 1203e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1204773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 12056014759cSMartin K. Petersen 12065b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1207773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 12085b94e232SMartin K. Petersen 12095b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 121044d92694SMartin K. Petersen 1211c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 12141e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1215760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1216eac6e8e4SMatthew Wilcox { 1217eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1218eac6e8e4SMatthew Wilcox arr[0] = 0; 12191e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 12201e49f785SDouglas Gilbert arr[2] = 0; 12211e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1222eac6e8e4SMatthew Wilcox 1223eac6e8e4SMatthew Wilcox return 0x3c; 1224eac6e8e4SMatthew Wilcox } 12251da177e4SLinus Torvalds 1226760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1227760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 12286014759cSMartin K. Petersen { 12293f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 12306014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1231773642d9SDouglas Gilbert if (sdebug_lbpu) 12326014759cSMartin K. Petersen arr[1] = 1 << 7; 1233773642d9SDouglas Gilbert if (sdebug_lbpws) 12346014759cSMartin K. Petersen arr[1] |= 1 << 6; 1235773642d9SDouglas Gilbert if (sdebug_lbpws10) 12365b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1237760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1238760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1239760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1240760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1241760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 12423f0bc3b3SMartin K. Petersen return 0x4; 12436014759cSMartin K. Petersen } 12446014759cSMartin K. Petersen 12451da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1246c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12471da177e4SLinus Torvalds 1248c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12491da177e4SLinus Torvalds { 12501da177e4SLinus Torvalds unsigned char pq_pdt; 12515a09e398SHannes Reinecke unsigned char * arr; 125201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12535a09e398SHannes Reinecke int alloc_len, n, ret; 1254760f3b03SDouglas Gilbert bool have_wlun, is_disk; 12551da177e4SLinus Torvalds 1256773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 12576f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12586f3cbf55SDouglas Gilbert if (! arr) 12596f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1260760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1261b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1262c2248fc9SDouglas Gilbert if (have_wlun) 1263b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1264b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1265b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1266c65b1445SDouglas Gilbert else 1267773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 12681da177e4SLinus Torvalds arr[0] = pq_pdt; 12691da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 127022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 12715a09e398SHannes Reinecke kfree(arr); 12721da177e4SLinus Torvalds return check_condition_result; 12731da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 12745a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1275c65b1445SDouglas Gilbert char lu_id_str[6]; 1276c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 12771da177e4SLinus Torvalds 12785a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 12795a09e398SHannes Reinecke (devip->channel & 0x7f); 1280b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 128123183910SDouglas Gilbert host_no = 0; 1282c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1283c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1284c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1285c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1286c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 12871da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1288c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1289c65b1445SDouglas Gilbert n = 4; 1290c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1291c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1292c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1293c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1294c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1295c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1296c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1297c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1298760f3b03SDouglas Gilbert if (is_disk) { /* SBC only */ 1299c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1300760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1301760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1302760f3b03SDouglas Gilbert arr[n++] = 0xb2; /* Logical Block Prov */ 1303760f3b03SDouglas Gilbert } 1304c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 13051da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1306c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 13071da177e4SLinus Torvalds arr[3] = len; 1308c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 13091da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1310c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1311760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 13125a09e398SHannes Reinecke target_dev_id, lu_id_num, 131309ba24c1SDouglas Gilbert lu_id_str, len, 131409ba24c1SDouglas Gilbert &devip->lu_name); 1315c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1316c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1317760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1318c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1319c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1320760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1321c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1322c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1323c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1324773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE3_PROTECTION) 1325c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1326760f3b03SDouglas Gilbert else if (have_dif_prot) 1327c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1328c6a44287SMartin K. Petersen else 1329c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1330c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1331c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1332c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1333c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1334c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1335c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1336c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1337c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1338c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1339c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1340760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1341760f3b03SDouglas Gilbert } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ 1342c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1343760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1344773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1345760f3b03SDouglas Gilbert } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ 1346c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1347760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1348760f3b03SDouglas Gilbert } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ 1349eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1350760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1351760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 13526014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1353760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 13541da177e4SLinus Torvalds } else { 135522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13565a09e398SHannes Reinecke kfree(arr); 13571da177e4SLinus Torvalds return check_condition_result; 13581da177e4SLinus Torvalds } 1359773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 13605a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1361c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13625a09e398SHannes Reinecke kfree(arr); 13635a09e398SHannes Reinecke return ret; 13641da177e4SLinus Torvalds } 13651da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1366773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1367773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 13681da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 13691da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1370f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1371b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 13725a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1373c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 13741da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1375c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 13761da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 13771da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 13781da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 13791da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1380760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1381760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1382c65b1445SDouglas Gilbert n = 62; 1383760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1384760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1385760f3b03SDouglas Gilbert n += 2; 1386760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1387760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1388760f3b03SDouglas Gilbert n += 2; 13891da177e4SLinus Torvalds } 1390760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 13915a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 13921da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 13935a09e398SHannes Reinecke kfree(arr); 13945a09e398SHannes Reinecke return ret; 13951da177e4SLinus Torvalds } 13961da177e4SLinus Torvalds 1397fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1398fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1399fd32119bSDouglas Gilbert 14001da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 14011da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14021da177e4SLinus Torvalds { 14031da177e4SLinus Torvalds unsigned char * sbuff; 140401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1405cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 14062492fc09STomas Winkler bool dsense; 14071da177e4SLinus Torvalds int len = 18; 14081da177e4SLinus Torvalds 1409c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1410c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1411cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1412c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1413c2248fc9SDouglas Gilbert if (dsense) { 1414c65b1445SDouglas Gilbert arr[0] = 0x72; 1415c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1416c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1417c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1418c2248fc9SDouglas Gilbert len = 8; 1419c65b1445SDouglas Gilbert } else { 1420c65b1445SDouglas Gilbert arr[0] = 0x70; 1421c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1422c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1423c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1424c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1425c65b1445SDouglas Gilbert } 1426c65b1445SDouglas Gilbert } else { 1427cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1428773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1429c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1430c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1431c2248fc9SDouglas Gilbert if (dsense) { 1432c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1433c2248fc9SDouglas Gilbert arr[0] = 0x72; 1434c2248fc9SDouglas Gilbert len = 8; 1435c2248fc9SDouglas Gilbert } else { 1436c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1437c2248fc9SDouglas Gilbert arr[0] = 0x70; 1438c2248fc9SDouglas Gilbert arr[7] = 0xa; 1439c2248fc9SDouglas Gilbert } 1440c2248fc9SDouglas Gilbert } else if (dsense) { 1441c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14421da177e4SLinus Torvalds arr[0] = 0x72; 14431da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14441da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14451da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14461da177e4SLinus Torvalds len = 8; 1447c2248fc9SDouglas Gilbert } else { 1448c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1449c2248fc9SDouglas Gilbert arr[0] = 0x70; 1450c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1451c2248fc9SDouglas Gilbert arr[7] = 0xa; 1452c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1453c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1454c65b1445SDouglas Gilbert } 1455c2248fc9SDouglas Gilbert 1456c65b1445SDouglas Gilbert } 1457cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14581da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds 1461c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1462c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1463c65b1445SDouglas Gilbert { 146401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1465c4837394SDouglas Gilbert int power_cond, stop; 1466c65b1445SDouglas Gilbert 1467c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1468c65b1445SDouglas Gilbert if (power_cond) { 146922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1470c65b1445SDouglas Gilbert return check_condition_result; 1471c65b1445SDouglas Gilbert } 1472c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 1473c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 1474c65b1445SDouglas Gilbert return 0; 1475c65b1445SDouglas Gilbert } 1476c65b1445SDouglas Gilbert 147728898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 147828898873SFUJITA Tomonori { 1479773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1480773642d9SDouglas Gilbert 1481773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1482773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1483773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 148428898873SFUJITA Tomonori else 148528898873SFUJITA Tomonori return sdebug_store_sectors; 148628898873SFUJITA Tomonori } 148728898873SFUJITA Tomonori 14881da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 14891da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 14901da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14911da177e4SLinus Torvalds { 14921da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1493c65b1445SDouglas Gilbert unsigned int capac; 14941da177e4SLinus Torvalds 1495c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 149628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 14971da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1498c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1499c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1500773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1501773642d9SDouglas Gilbert } else 1502773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1503773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 15041da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds 1507c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1508c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1509c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1510c65b1445SDouglas Gilbert { 151101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1512c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1513773642d9SDouglas Gilbert int alloc_len; 1514c65b1445SDouglas Gilbert 1515773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1516c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 151728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1518c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1519773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1520773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1521773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1522773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 152344d92694SMartin K. Petersen 1524be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 15255b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1526760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1527760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1528760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1529760f3b03SDouglas Gilbert */ 1530760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1531760f3b03SDouglas Gilbert arr[14] |= 0x40; 1532be1dd78dSEric Sandeen } 153344d92694SMartin K. Petersen 1534773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1535c6a44287SMartin K. Petersen 1536760f3b03SDouglas Gilbert if (have_dif_prot) { 1537773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1538c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1539c6a44287SMartin K. Petersen } 1540c6a44287SMartin K. Petersen 1541c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1542c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1543c65b1445SDouglas Gilbert } 1544c65b1445SDouglas Gilbert 15455a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15465a09e398SHannes Reinecke 15475a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15485a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15495a09e398SHannes Reinecke { 155001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15515a09e398SHannes Reinecke unsigned char * arr; 15525a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15535a09e398SHannes Reinecke int n, ret, alen, rlen; 15545a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15555a09e398SHannes Reinecke 1556773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 15576f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15586f3cbf55SDouglas Gilbert if (! arr) 15596f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15605a09e398SHannes Reinecke /* 15615a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 15625a09e398SHannes Reinecke * real and a fake port with no device connected. 15635a09e398SHannes Reinecke * So we create two port groups with one port each 15645a09e398SHannes Reinecke * and set the group with port B to unavailable. 15655a09e398SHannes Reinecke */ 15665a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 15675a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 15685a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 15695a09e398SHannes Reinecke (devip->channel & 0x7f); 15705a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 15715a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 15725a09e398SHannes Reinecke 15735a09e398SHannes Reinecke /* 15745a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 15755a09e398SHannes Reinecke */ 15765a09e398SHannes Reinecke n = 4; 1577b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 15785a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 15795a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 15805a09e398SHannes Reinecke } else { 15815a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1582773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 15835a09e398SHannes Reinecke } 1584773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1585773642d9SDouglas Gilbert n += 2; 15865a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15875a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15885a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15895a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15905a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15915a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1592773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1593773642d9SDouglas Gilbert n += 2; 15945a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 15955a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1596773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1597773642d9SDouglas Gilbert n += 2; 15985a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15995a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16005a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16015a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16025a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16035a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1604773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1605773642d9SDouglas Gilbert n += 2; 16065a09e398SHannes Reinecke 16075a09e398SHannes Reinecke rlen = n - 4; 1608773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 16095a09e398SHannes Reinecke 16105a09e398SHannes Reinecke /* 16115a09e398SHannes Reinecke * Return the smallest value of either 16125a09e398SHannes Reinecke * - The allocated length 16135a09e398SHannes Reinecke * - The constructed command length 16145a09e398SHannes Reinecke * - The maximum array size 16155a09e398SHannes Reinecke */ 16165a09e398SHannes Reinecke rlen = min(alen,n); 16175a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 16185a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 16195a09e398SHannes Reinecke kfree(arr); 16205a09e398SHannes Reinecke return ret; 16215a09e398SHannes Reinecke } 16225a09e398SHannes Reinecke 1623fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1624fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 162538d5c833SDouglas Gilbert { 162638d5c833SDouglas Gilbert bool rctd; 162738d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 162838d5c833SDouglas Gilbert u16 req_sa, u; 162938d5c833SDouglas Gilbert u32 alloc_len, a_len; 163038d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 163138d5c833SDouglas Gilbert const struct opcode_info_t *oip; 163238d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 163338d5c833SDouglas Gilbert u8 *arr; 163438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 163538d5c833SDouglas Gilbert 163638d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 163738d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 163838d5c833SDouglas Gilbert req_opcode = cmd[3]; 163938d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 164038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16416d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 164238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 164338d5c833SDouglas Gilbert return check_condition_result; 164438d5c833SDouglas Gilbert } 164538d5c833SDouglas Gilbert if (alloc_len > 8192) 164638d5c833SDouglas Gilbert a_len = 8192; 164738d5c833SDouglas Gilbert else 164838d5c833SDouglas Gilbert a_len = alloc_len; 164999531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 165038d5c833SDouglas Gilbert if (NULL == arr) { 165138d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 165238d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 165338d5c833SDouglas Gilbert return check_condition_result; 165438d5c833SDouglas Gilbert } 165538d5c833SDouglas Gilbert switch (reporting_opts) { 165638d5c833SDouglas Gilbert case 0: /* all commands */ 165738d5c833SDouglas Gilbert /* count number of commands */ 165838d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 165938d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 166038d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 166138d5c833SDouglas Gilbert continue; 166238d5c833SDouglas Gilbert count += (oip->num_attached + 1); 166338d5c833SDouglas Gilbert } 166438d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 166538d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 166638d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 166738d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 166838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 166938d5c833SDouglas Gilbert continue; 167038d5c833SDouglas Gilbert na = oip->num_attached; 167138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 167238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 167338d5c833SDouglas Gilbert if (rctd) 167438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 167538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 167638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 167738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 167838d5c833SDouglas Gilbert if (rctd) 167938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 168038d5c833SDouglas Gilbert r_oip = oip; 168138d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 168238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 168338d5c833SDouglas Gilbert continue; 168438d5c833SDouglas Gilbert offset += bump; 168538d5c833SDouglas Gilbert arr[offset] = oip->opcode; 168638d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 168738d5c833SDouglas Gilbert if (rctd) 168838d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 168938d5c833SDouglas Gilbert if (FF_SA & oip->flags) 169038d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 169138d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 169238d5c833SDouglas Gilbert arr + offset + 6); 169338d5c833SDouglas Gilbert if (rctd) 169438d5c833SDouglas Gilbert put_unaligned_be16(0xa, 169538d5c833SDouglas Gilbert arr + offset + 8); 169638d5c833SDouglas Gilbert } 169738d5c833SDouglas Gilbert oip = r_oip; 169838d5c833SDouglas Gilbert offset += bump; 169938d5c833SDouglas Gilbert } 170038d5c833SDouglas Gilbert break; 170138d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 170238d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 170338d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 170438d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 170538d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 170638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 170738d5c833SDouglas Gilbert supp = 1; 170838d5c833SDouglas Gilbert offset = 4; 170938d5c833SDouglas Gilbert } else { 171038d5c833SDouglas Gilbert if (1 == reporting_opts) { 171138d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 171238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 171338d5c833SDouglas Gilbert 2, 2); 171438d5c833SDouglas Gilbert kfree(arr); 171538d5c833SDouglas Gilbert return check_condition_result; 171638d5c833SDouglas Gilbert } 171738d5c833SDouglas Gilbert req_sa = 0; 171838d5c833SDouglas Gilbert } else if (2 == reporting_opts && 171938d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 172038d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 172138d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 172238d5c833SDouglas Gilbert return check_condition_result; 172338d5c833SDouglas Gilbert } 172438d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 172538d5c833SDouglas Gilbert req_opcode == oip->opcode) 172638d5c833SDouglas Gilbert supp = 3; 172738d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 172838d5c833SDouglas Gilbert na = oip->num_attached; 172938d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 173038d5c833SDouglas Gilbert ++k, ++oip) { 173138d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 173238d5c833SDouglas Gilbert break; 173338d5c833SDouglas Gilbert } 173438d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 173538d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 173638d5c833SDouglas Gilbert na = oip->num_attached; 173738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 173838d5c833SDouglas Gilbert ++k, ++oip) { 173938d5c833SDouglas Gilbert if (req_sa == oip->sa) 174038d5c833SDouglas Gilbert break; 174138d5c833SDouglas Gilbert } 174238d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 174338d5c833SDouglas Gilbert } else 174438d5c833SDouglas Gilbert supp = 3; 174538d5c833SDouglas Gilbert if (3 == supp) { 174638d5c833SDouglas Gilbert u = oip->len_mask[0]; 174738d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 174838d5c833SDouglas Gilbert arr[4] = oip->opcode; 174938d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 175038d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 175138d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 175238d5c833SDouglas Gilbert offset = 4 + u; 175338d5c833SDouglas Gilbert } else 175438d5c833SDouglas Gilbert offset = 4; 175538d5c833SDouglas Gilbert } 175638d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 175738d5c833SDouglas Gilbert if (rctd) { 175838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 175938d5c833SDouglas Gilbert offset += 12; 176038d5c833SDouglas Gilbert } 176138d5c833SDouglas Gilbert break; 176238d5c833SDouglas Gilbert default: 176338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 176438d5c833SDouglas Gilbert kfree(arr); 176538d5c833SDouglas Gilbert return check_condition_result; 176638d5c833SDouglas Gilbert } 176738d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 176838d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 176938d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 177038d5c833SDouglas Gilbert kfree(arr); 177138d5c833SDouglas Gilbert return errsts; 177238d5c833SDouglas Gilbert } 177338d5c833SDouglas Gilbert 1774fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1775fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 177638d5c833SDouglas Gilbert { 177738d5c833SDouglas Gilbert bool repd; 177838d5c833SDouglas Gilbert u32 alloc_len, len; 177938d5c833SDouglas Gilbert u8 arr[16]; 178038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 178138d5c833SDouglas Gilbert 178238d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 178338d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 178438d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 178538d5c833SDouglas Gilbert if (alloc_len < 4) { 178638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 178738d5c833SDouglas Gilbert return check_condition_result; 178838d5c833SDouglas Gilbert } 178938d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 179038d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 179138d5c833SDouglas Gilbert if (repd) { 179238d5c833SDouglas Gilbert arr[3] = 0xc; 179338d5c833SDouglas Gilbert len = 16; 179438d5c833SDouglas Gilbert } else 179538d5c833SDouglas Gilbert len = 4; 179638d5c833SDouglas Gilbert 179738d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 179838d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 179938d5c833SDouglas Gilbert } 180038d5c833SDouglas Gilbert 18011da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 18041da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 18051da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 18061da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 18091da177e4SLinus Torvalds if (1 == pcontrol) 18101da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 18111da177e4SLinus Torvalds return sizeof(err_recov_pg); 18121da177e4SLinus Torvalds } 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 18151da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 18161da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 18171da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 18181da177e4SLinus Torvalds 18191da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 18201da177e4SLinus Torvalds if (1 == pcontrol) 18211da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 18221da177e4SLinus Torvalds return sizeof(disconnect_pg); 18231da177e4SLinus Torvalds } 18241da177e4SLinus Torvalds 18251da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 18261da177e4SLinus Torvalds { /* Format device page for mode_sense */ 18271da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 18281da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 18291da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 18301da177e4SLinus Torvalds 18311da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 1832773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 1833773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 1834773642d9SDouglas Gilbert if (sdebug_removable) 18351da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 18361da177e4SLinus Torvalds if (1 == pcontrol) 18371da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 18381da177e4SLinus Torvalds return sizeof(format_pg); 18391da177e4SLinus Torvalds } 18401da177e4SLinus Torvalds 1841fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 1842fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 1843fd32119bSDouglas Gilbert 0, 0, 0, 0}; 1844fd32119bSDouglas Gilbert 18451da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18461da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1847cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1848cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1849cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18501da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18511da177e4SLinus Torvalds 1852773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 1853cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18541da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18551da177e4SLinus Torvalds if (1 == pcontrol) 1856cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1857cbf67842SDouglas Gilbert else if (2 == pcontrol) 1858cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18591da177e4SLinus Torvalds return sizeof(caching_pg); 18601da177e4SLinus Torvalds } 18611da177e4SLinus Torvalds 1862fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 1863fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 1864fd32119bSDouglas Gilbert 18651da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 18661da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1867c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1868c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1869c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 18701da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 18711da177e4SLinus Torvalds 1872773642d9SDouglas Gilbert if (sdebug_dsense) 18731da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1874c65b1445SDouglas Gilbert else 1875c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1876c6a44287SMartin K. Petersen 1877773642d9SDouglas Gilbert if (sdebug_ato) 1878c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1879c6a44287SMartin K. Petersen 18801da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 18811da177e4SLinus Torvalds if (1 == pcontrol) 1882c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1883c65b1445SDouglas Gilbert else if (2 == pcontrol) 1884c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 18851da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 18861da177e4SLinus Torvalds } 18871da177e4SLinus Torvalds 1888c65b1445SDouglas Gilbert 18891da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 18901da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1891c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 18921da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1893c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1894c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1895c65b1445SDouglas Gilbert 18961da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 18971da177e4SLinus Torvalds if (1 == pcontrol) 1898c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1899c65b1445SDouglas Gilbert else if (2 == pcontrol) 1900c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 19011da177e4SLinus Torvalds return sizeof(iec_m_pg); 19021da177e4SLinus Torvalds } 19031da177e4SLinus Torvalds 1904c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1905c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1906c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1907c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1908c65b1445SDouglas Gilbert 1909c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1910c65b1445SDouglas Gilbert if (1 == pcontrol) 1911c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1912c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1913c65b1445SDouglas Gilbert } 1914c65b1445SDouglas Gilbert 1915c65b1445SDouglas Gilbert 1916c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1917c65b1445SDouglas Gilbert int target_dev_id) 1918c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1919c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1920c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1921773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1922773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1923c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1924c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1925c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1926c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1927773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1928773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1929c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1930c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1931c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1932c65b1445SDouglas Gilbert }; 1933c65b1445SDouglas Gilbert int port_a, port_b; 1934c65b1445SDouglas Gilbert 19351b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 19361b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 19371b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 19381b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 1939c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1940c65b1445SDouglas Gilbert port_b = port_a + 1; 1941c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1942773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 1943773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 1944c65b1445SDouglas Gilbert if (1 == pcontrol) 1945c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1946c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1947c65b1445SDouglas Gilbert } 1948c65b1445SDouglas Gilbert 1949c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1950c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1951c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1952c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1953c65b1445SDouglas Gilbert }; 1954c65b1445SDouglas Gilbert 1955c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1956c65b1445SDouglas Gilbert if (1 == pcontrol) 1957c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1958c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1959c65b1445SDouglas Gilbert } 1960c65b1445SDouglas Gilbert 19611da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 19621da177e4SLinus Torvalds 1963fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 1964fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 19651da177e4SLinus Torvalds { 196623183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 19671da177e4SLinus Torvalds unsigned char dev_spec; 1968760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 1969c2248fc9SDouglas Gilbert int target = scp->device->id; 19701da177e4SLinus Torvalds unsigned char * ap; 19711da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 197201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1973760f3b03SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, bad_pcode; 19741da177e4SLinus Torvalds 1975760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 19761da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 19771da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 19781da177e4SLinus Torvalds subpcode = cmd[3]; 19791da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 1980760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 1981760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1982760f3b03SDouglas Gilbert if (is_disk && !dbd) 198323183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 198423183910SDouglas Gilbert else 198523183910SDouglas Gilbert bd_len = 0; 1986773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 19871da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 19881da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 1989cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 19901da177e4SLinus Torvalds return check_condition_result; 19911da177e4SLinus Torvalds } 1992c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1993c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1994b01f6f83SDouglas Gilbert /* for disks set DPOFUA bit and clear write protect (WP) bit */ 1995760f3b03SDouglas Gilbert if (is_disk) 1996b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 199723183910SDouglas Gilbert else 199823183910SDouglas Gilbert dev_spec = 0x0; 19991da177e4SLinus Torvalds if (msense_6) { 20001da177e4SLinus Torvalds arr[2] = dev_spec; 200123183910SDouglas Gilbert arr[3] = bd_len; 20021da177e4SLinus Torvalds offset = 4; 20031da177e4SLinus Torvalds } else { 20041da177e4SLinus Torvalds arr[3] = dev_spec; 200523183910SDouglas Gilbert if (16 == bd_len) 200623183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 200723183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 20081da177e4SLinus Torvalds offset = 8; 20091da177e4SLinus Torvalds } 20101da177e4SLinus Torvalds ap = arr + offset; 201128898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 201228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 201328898873SFUJITA Tomonori 201423183910SDouglas Gilbert if (8 == bd_len) { 2015773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2016773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2017773642d9SDouglas Gilbert else 2018773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2019773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 202023183910SDouglas Gilbert offset += bd_len; 202123183910SDouglas Gilbert ap = arr + offset; 202223183910SDouglas Gilbert } else if (16 == bd_len) { 2023773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2024773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 202523183910SDouglas Gilbert offset += bd_len; 202623183910SDouglas Gilbert ap = arr + offset; 202723183910SDouglas Gilbert } 20281da177e4SLinus Torvalds 2029c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2030c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 203122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 20321da177e4SLinus Torvalds return check_condition_result; 20331da177e4SLinus Torvalds } 2034760f3b03SDouglas Gilbert bad_pcode = false; 2035760f3b03SDouglas Gilbert 20361da177e4SLinus Torvalds switch (pcode) { 20371da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 20381da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20391da177e4SLinus Torvalds offset += len; 20401da177e4SLinus Torvalds break; 20411da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 20421da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20431da177e4SLinus Torvalds offset += len; 20441da177e4SLinus Torvalds break; 20451da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2046760f3b03SDouglas Gilbert if (is_disk) { 20471da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20481da177e4SLinus Torvalds offset += len; 2049760f3b03SDouglas Gilbert } else 2050760f3b03SDouglas Gilbert bad_pcode = true; 20511da177e4SLinus Torvalds break; 20521da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2053760f3b03SDouglas Gilbert if (is_disk) { 20541da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 20551da177e4SLinus Torvalds offset += len; 2056760f3b03SDouglas Gilbert } else 2057760f3b03SDouglas Gilbert bad_pcode = true; 20581da177e4SLinus Torvalds break; 20591da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 20601da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 20611da177e4SLinus Torvalds offset += len; 20621da177e4SLinus Torvalds break; 2063c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2064c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 206522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2066c65b1445SDouglas Gilbert return check_condition_result; 2067c65b1445SDouglas Gilbert } 2068c65b1445SDouglas Gilbert len = 0; 2069c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2070c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2071c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2072c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2073c65b1445SDouglas Gilbert target_dev_id); 2074c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2075c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2076c65b1445SDouglas Gilbert offset += len; 2077c65b1445SDouglas Gilbert break; 20781da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 20791da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 20801da177e4SLinus Torvalds offset += len; 20811da177e4SLinus Torvalds break; 20821da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2083c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 20841da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20851da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2086760f3b03SDouglas Gilbert if (is_disk) { 2087760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2088760f3b03SDouglas Gilbert target); 2089760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2090760f3b03SDouglas Gilbert target); 2091760f3b03SDouglas Gilbert } 20921da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2093c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2094c65b1445SDouglas Gilbert if (0xff == subpcode) { 2095c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2096c65b1445SDouglas Gilbert target, target_dev_id); 2097c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2098c65b1445SDouglas Gilbert } 20991da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2100760f3b03SDouglas Gilbert offset += len; 2101c65b1445SDouglas Gilbert } else { 210222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2103c65b1445SDouglas Gilbert return check_condition_result; 2104c65b1445SDouglas Gilbert } 21051da177e4SLinus Torvalds break; 21061da177e4SLinus Torvalds default: 2107760f3b03SDouglas Gilbert bad_pcode = true; 2108760f3b03SDouglas Gilbert break; 2109760f3b03SDouglas Gilbert } 2110760f3b03SDouglas Gilbert if (bad_pcode) { 211122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 21121da177e4SLinus Torvalds return check_condition_result; 21131da177e4SLinus Torvalds } 21141da177e4SLinus Torvalds if (msense_6) 21151da177e4SLinus Torvalds arr[0] = offset - 1; 2116773642d9SDouglas Gilbert else 2117773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 21181da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 21191da177e4SLinus Torvalds } 21201da177e4SLinus Torvalds 2121c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2122c65b1445SDouglas Gilbert 2123fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2124fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2125c65b1445SDouglas Gilbert { 2126c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2127c2248fc9SDouglas Gilbert int param_len, res, mpage; 2128c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 212901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2130c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2131c65b1445SDouglas Gilbert 2132c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2133c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2134c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2135773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2136c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 213722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2138c65b1445SDouglas Gilbert return check_condition_result; 2139c65b1445SDouglas Gilbert } 2140c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2141c65b1445SDouglas Gilbert if (-1 == res) 2142773642d9SDouglas Gilbert return DID_ERROR << 16; 2143773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2144cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2145cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2146cbf67842SDouglas Gilbert __func__, param_len, res); 2147773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2148773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 214923183910SDouglas Gilbert if (md_len > 2) { 215022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2151c65b1445SDouglas Gilbert return check_condition_result; 2152c65b1445SDouglas Gilbert } 2153c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2154c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2155c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2156c65b1445SDouglas Gilbert if (ps) { 215722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2158c65b1445SDouglas Gilbert return check_condition_result; 2159c65b1445SDouglas Gilbert } 2160c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2161773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2162c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2163c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2164cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2165c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2166c65b1445SDouglas Gilbert return check_condition_result; 2167c65b1445SDouglas Gilbert } 2168c65b1445SDouglas Gilbert switch (mpage) { 2169cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2170cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2171cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2172cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2173cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2174cbf67842SDouglas Gilbert } 2175cbf67842SDouglas Gilbert break; 2176c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2177c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2178c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2179c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2180773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2181cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2182c65b1445SDouglas Gilbert } 2183c65b1445SDouglas Gilbert break; 2184c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2185c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2186c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2187c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2188cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2189c65b1445SDouglas Gilbert } 2190c65b1445SDouglas Gilbert break; 2191c65b1445SDouglas Gilbert default: 2192c65b1445SDouglas Gilbert break; 2193c65b1445SDouglas Gilbert } 219422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2195c65b1445SDouglas Gilbert return check_condition_result; 2196cbf67842SDouglas Gilbert set_mode_changed_ua: 2197cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2198cbf67842SDouglas Gilbert return 0; 2199c65b1445SDouglas Gilbert } 2200c65b1445SDouglas Gilbert 2201c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2202c65b1445SDouglas Gilbert { 2203c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2204c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2205c65b1445SDouglas Gilbert }; 2206c65b1445SDouglas Gilbert 2207c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2208c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2209c65b1445SDouglas Gilbert } 2210c65b1445SDouglas Gilbert 2211c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2212c65b1445SDouglas Gilbert { 2213c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2214c65b1445SDouglas Gilbert }; 2215c65b1445SDouglas Gilbert 2216c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2217c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2218c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2219c65b1445SDouglas Gilbert arr[5] = 0xff; 2220c65b1445SDouglas Gilbert } 2221c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2222c65b1445SDouglas Gilbert } 2223c65b1445SDouglas Gilbert 2224c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2225c65b1445SDouglas Gilbert 2226c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2227c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2228c65b1445SDouglas Gilbert { 2229c2248fc9SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n; 2230c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 223101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2232c65b1445SDouglas Gilbert 2233c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2234c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2235c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2236c65b1445SDouglas Gilbert if (ppc || sp) { 223722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2238c65b1445SDouglas Gilbert return check_condition_result; 2239c65b1445SDouglas Gilbert } 2240c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 2241c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 224223183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2243773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2244c65b1445SDouglas Gilbert arr[0] = pcode; 224523183910SDouglas Gilbert if (0 == subpcode) { 2246c65b1445SDouglas Gilbert switch (pcode) { 2247c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2248c65b1445SDouglas Gilbert n = 4; 2249c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2250c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2251c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2252c65b1445SDouglas Gilbert arr[3] = n - 4; 2253c65b1445SDouglas Gilbert break; 2254c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2255c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2256c65b1445SDouglas Gilbert break; 2257c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2258c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2259c65b1445SDouglas Gilbert break; 2260c65b1445SDouglas Gilbert default: 226122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2262c65b1445SDouglas Gilbert return check_condition_result; 2263c65b1445SDouglas Gilbert } 226423183910SDouglas Gilbert } else if (0xff == subpcode) { 226523183910SDouglas Gilbert arr[0] |= 0x40; 226623183910SDouglas Gilbert arr[1] = subpcode; 226723183910SDouglas Gilbert switch (pcode) { 226823183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 226923183910SDouglas Gilbert n = 4; 227023183910SDouglas Gilbert arr[n++] = 0x0; 227123183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 227223183910SDouglas Gilbert arr[n++] = 0x0; 227323183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 227423183910SDouglas Gilbert arr[n++] = 0xd; 227523183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 227623183910SDouglas Gilbert arr[n++] = 0x2f; 227723183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 227823183910SDouglas Gilbert arr[3] = n - 4; 227923183910SDouglas Gilbert break; 228023183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 228123183910SDouglas Gilbert n = 4; 228223183910SDouglas Gilbert arr[n++] = 0xd; 228323183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 228423183910SDouglas Gilbert arr[3] = n - 4; 228523183910SDouglas Gilbert break; 228623183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 228723183910SDouglas Gilbert n = 4; 228823183910SDouglas Gilbert arr[n++] = 0x2f; 228923183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 229023183910SDouglas Gilbert arr[3] = n - 4; 229123183910SDouglas Gilbert break; 229223183910SDouglas Gilbert default: 229322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 229423183910SDouglas Gilbert return check_condition_result; 229523183910SDouglas Gilbert } 229623183910SDouglas Gilbert } else { 229722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 229823183910SDouglas Gilbert return check_condition_result; 229923183910SDouglas Gilbert } 2300773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 2301c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2302c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2303c65b1445SDouglas Gilbert } 2304c65b1445SDouglas Gilbert 2305cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 230619789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 23071da177e4SLinus Torvalds { 2308c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 230922017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 23101da177e4SLinus Torvalds return check_condition_result; 23111da177e4SLinus Torvalds } 2312c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2313c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 231422017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2315cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2316c65b1445SDouglas Gilbert return check_condition_result; 2317c65b1445SDouglas Gilbert } 231819789100SFUJITA Tomonori return 0; 231919789100SFUJITA Tomonori } 232019789100SFUJITA Tomonori 2321a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2322fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, 2323fd32119bSDouglas Gilbert bool do_write) 232419789100SFUJITA Tomonori { 232519789100SFUJITA Tomonori int ret; 2326c2248fc9SDouglas Gilbert u64 block, rest = 0; 2327a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2328a4517511SAkinobu Mita enum dma_data_direction dir; 232919789100SFUJITA Tomonori 2330c2248fc9SDouglas Gilbert if (do_write) { 2331a4517511SAkinobu Mita sdb = scsi_out(scmd); 2332a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2333a4517511SAkinobu Mita } else { 2334a4517511SAkinobu Mita sdb = scsi_in(scmd); 2335a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2336a4517511SAkinobu Mita } 2337a4517511SAkinobu Mita 2338a4517511SAkinobu Mita if (!sdb->length) 2339a4517511SAkinobu Mita return 0; 2340a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2341a4517511SAkinobu Mita return -1; 234219789100SFUJITA Tomonori 234319789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 234419789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 234519789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 234619789100SFUJITA Tomonori 2347386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2348773642d9SDouglas Gilbert fake_storep + (block * sdebug_sector_size), 2349773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, 0, do_write); 2350773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2351a4517511SAkinobu Mita return ret; 2352a4517511SAkinobu Mita 2353a4517511SAkinobu Mita if (rest) { 2354386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2355773642d9SDouglas Gilbert fake_storep, rest * sdebug_sector_size, 2356773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, do_write); 2357a4517511SAkinobu Mita } 235819789100SFUJITA Tomonori 235919789100SFUJITA Tomonori return ret; 236019789100SFUJITA Tomonori } 236119789100SFUJITA Tomonori 236238d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 236338d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 236438d5c833SDouglas Gilbert * return false. */ 2365fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr) 236638d5c833SDouglas Gilbert { 236738d5c833SDouglas Gilbert bool res; 236838d5c833SDouglas Gilbert u64 block, rest = 0; 236938d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2370773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 237138d5c833SDouglas Gilbert 237238d5c833SDouglas Gilbert block = do_div(lba, store_blks); 237338d5c833SDouglas Gilbert if (block + num > store_blks) 237438d5c833SDouglas Gilbert rest = block + num - store_blks; 237538d5c833SDouglas Gilbert 237638d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 237738d5c833SDouglas Gilbert (num - rest) * lb_size); 237838d5c833SDouglas Gilbert if (!res) 237938d5c833SDouglas Gilbert return res; 238038d5c833SDouglas Gilbert if (rest) 238138d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 238238d5c833SDouglas Gilbert rest * lb_size); 238338d5c833SDouglas Gilbert if (!res) 238438d5c833SDouglas Gilbert return res; 238538d5c833SDouglas Gilbert arr += num * lb_size; 238638d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 238738d5c833SDouglas Gilbert if (rest) 238838d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 238938d5c833SDouglas Gilbert rest * lb_size); 239038d5c833SDouglas Gilbert return res; 239138d5c833SDouglas Gilbert } 239238d5c833SDouglas Gilbert 239351d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2394beb40ea4SAkinobu Mita { 239551d648afSAkinobu Mita __be16 csum; 2396beb40ea4SAkinobu Mita 2397773642d9SDouglas Gilbert if (sdebug_guard) 239851d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 239951d648afSAkinobu Mita else 2400beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 240151d648afSAkinobu Mita 2402beb40ea4SAkinobu Mita return csum; 2403beb40ea4SAkinobu Mita } 2404beb40ea4SAkinobu Mita 2405beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 2406beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2407beb40ea4SAkinobu Mita { 2408773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2409beb40ea4SAkinobu Mita 2410beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2411c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2412beb40ea4SAkinobu Mita (unsigned long)sector, 2413beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2414beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2415beb40ea4SAkinobu Mita return 0x01; 2416beb40ea4SAkinobu Mita } 2417773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE1_PROTECTION && 2418beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2419c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2420c1287970STomas Winkler (unsigned long)sector); 2421beb40ea4SAkinobu Mita return 0x03; 2422beb40ea4SAkinobu Mita } 2423773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2424beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2425c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2426c1287970STomas Winkler (unsigned long)sector); 2427beb40ea4SAkinobu Mita return 0x03; 2428beb40ea4SAkinobu Mita } 2429beb40ea4SAkinobu Mita return 0; 2430beb40ea4SAkinobu Mita } 2431beb40ea4SAkinobu Mita 2432bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 243365f72f2aSAkinobu Mita unsigned int sectors, bool read) 2434c6a44287SMartin K. Petersen { 2435be4e11beSAkinobu Mita size_t resid; 2436c6a44287SMartin K. Petersen void *paddr; 243714faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2438be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2439c6a44287SMartin K. Petersen 2440e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2441e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2442c6a44287SMartin K. Petersen 2443be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2444be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2445be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2446be4e11beSAkinobu Mita 2447be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2448be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 244914faa944SAkinobu Mita void *start = dif_store(sector); 2450be4e11beSAkinobu Mita size_t rest = 0; 245114faa944SAkinobu Mita 245214faa944SAkinobu Mita if (dif_store_end < start + len) 245314faa944SAkinobu Mita rest = start + len - dif_store_end; 2454c6a44287SMartin K. Petersen 2455be4e11beSAkinobu Mita paddr = miter.addr; 245614faa944SAkinobu Mita 245765f72f2aSAkinobu Mita if (read) 245865f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 245965f72f2aSAkinobu Mita else 246065f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 246165f72f2aSAkinobu Mita 246265f72f2aSAkinobu Mita if (rest) { 246365f72f2aSAkinobu Mita if (read) 246414faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 246565f72f2aSAkinobu Mita else 246665f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 246765f72f2aSAkinobu Mita } 2468c6a44287SMartin K. Petersen 2469e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2470c6a44287SMartin K. Petersen resid -= len; 2471c6a44287SMartin K. Petersen } 2472be4e11beSAkinobu Mita sg_miter_stop(&miter); 2473bb8c063cSAkinobu Mita } 2474c6a44287SMartin K. Petersen 2475bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2476bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2477bb8c063cSAkinobu Mita { 2478bb8c063cSAkinobu Mita unsigned int i; 2479bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 2480bb8c063cSAkinobu Mita sector_t sector; 2481bb8c063cSAkinobu Mita 2482c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2483bb8c063cSAkinobu Mita int ret; 2484bb8c063cSAkinobu Mita 2485bb8c063cSAkinobu Mita sector = start_sec + i; 2486bb8c063cSAkinobu Mita sdt = dif_store(sector); 2487bb8c063cSAkinobu Mita 248851d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2489bb8c063cSAkinobu Mita continue; 2490bb8c063cSAkinobu Mita 2491bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2492bb8c063cSAkinobu Mita if (ret) { 2493bb8c063cSAkinobu Mita dif_errors++; 2494bb8c063cSAkinobu Mita return ret; 2495bb8c063cSAkinobu Mita } 2496bb8c063cSAkinobu Mita } 2497bb8c063cSAkinobu Mita 249865f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2499c6a44287SMartin K. Petersen dix_reads++; 2500c6a44287SMartin K. Petersen 2501c6a44287SMartin K. Petersen return 0; 2502c6a44287SMartin K. Petersen } 2503c6a44287SMartin K. Petersen 2504fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 250519789100SFUJITA Tomonori { 2506c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2507c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 2508c2248fc9SDouglas Gilbert u64 lba; 2509c2248fc9SDouglas Gilbert u32 num; 2510c2248fc9SDouglas Gilbert u32 ei_lba; 251119789100SFUJITA Tomonori unsigned long iflags; 251219789100SFUJITA Tomonori int ret; 2513c2248fc9SDouglas Gilbert bool check_prot; 251419789100SFUJITA Tomonori 2515c2248fc9SDouglas Gilbert switch (cmd[0]) { 2516c2248fc9SDouglas Gilbert case READ_16: 2517c2248fc9SDouglas Gilbert ei_lba = 0; 2518c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2519c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2520c2248fc9SDouglas Gilbert check_prot = true; 2521c2248fc9SDouglas Gilbert break; 2522c2248fc9SDouglas Gilbert case READ_10: 2523c2248fc9SDouglas Gilbert ei_lba = 0; 2524c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2525c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2526c2248fc9SDouglas Gilbert check_prot = true; 2527c2248fc9SDouglas Gilbert break; 2528c2248fc9SDouglas Gilbert case READ_6: 2529c2248fc9SDouglas Gilbert ei_lba = 0; 2530c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2531c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2532c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2533c2248fc9SDouglas Gilbert check_prot = true; 2534c2248fc9SDouglas Gilbert break; 2535c2248fc9SDouglas Gilbert case READ_12: 2536c2248fc9SDouglas Gilbert ei_lba = 0; 2537c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2538c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2539c2248fc9SDouglas Gilbert check_prot = true; 2540c2248fc9SDouglas Gilbert break; 2541c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2542c2248fc9SDouglas Gilbert ei_lba = 0; 2543c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2544c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2545c2248fc9SDouglas Gilbert check_prot = false; 2546c2248fc9SDouglas Gilbert break; 2547c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2548c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2549c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2550c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2551c2248fc9SDouglas Gilbert check_prot = false; 2552c2248fc9SDouglas Gilbert break; 2553c2248fc9SDouglas Gilbert } 2554f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2555773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2556c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2557c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2558c2248fc9SDouglas Gilbert return check_condition_result; 2559c2248fc9SDouglas Gilbert } 2560773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2561773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2562c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2563c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2564c2248fc9SDouglas Gilbert "to DIF device\n"); 2565c2248fc9SDouglas Gilbert } 2566f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2567c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 2568c2248fc9SDouglas Gilbert 2569c4837394SDouglas Gilbert if (sqcp) { 2570c4837394SDouglas Gilbert if (sqcp->inj_short) 2571c2248fc9SDouglas Gilbert num /= 2; 2572c2248fc9SDouglas Gilbert } 2573c4837394SDouglas Gilbert } else 2574c4837394SDouglas Gilbert sqcp = NULL; 2575c2248fc9SDouglas Gilbert 2576c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2577f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2578c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2579c2248fc9SDouglas Gilbert return check_condition_result; 2580c2248fc9SDouglas Gilbert } 2581c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2582f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2583c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2584c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2585c2248fc9SDouglas Gilbert return check_condition_result; 2586c2248fc9SDouglas Gilbert } 258719789100SFUJITA Tomonori 2588f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 258932f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2590f46eb0e9SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { 2591c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2592c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2593c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2594c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2595c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 259632f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 259732f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2598c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2599c65b1445SDouglas Gilbert } 2600c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 26011da177e4SLinus Torvalds return check_condition_result; 26021da177e4SLinus Torvalds } 2603c6a44287SMartin K. Petersen 26046c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 26056c78cc06SAkinobu Mita 2606c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2607f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2608c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2609c6a44287SMartin K. Petersen 2610c6a44287SMartin K. Petersen if (prot_ret) { 26116c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2612c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2613c6a44287SMartin K. Petersen return illegal_condition_result; 2614c6a44287SMartin K. Petersen } 2615c6a44287SMartin K. Petersen } 2616c6a44287SMartin K. Petersen 2617c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 26181da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2619f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2620a4517511SAkinobu Mita return DID_ERROR << 16; 2621a4517511SAkinobu Mita 2622c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2623a4517511SAkinobu Mita 2624c4837394SDouglas Gilbert if (unlikely(sqcp)) { 2625c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2626c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2627c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2628c2248fc9SDouglas Gilbert return check_condition_result; 2629c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 2630c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2631c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2632c2248fc9SDouglas Gilbert return check_condition_result; 2633c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2634c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2635c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2636c2248fc9SDouglas Gilbert return illegal_condition_result; 2637c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2638c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2639c2248fc9SDouglas Gilbert return illegal_condition_result; 2640c2248fc9SDouglas Gilbert } 2641c2248fc9SDouglas Gilbert } 2642a4517511SAkinobu Mita return 0; 26431da177e4SLinus Torvalds } 26441da177e4SLinus Torvalds 264558a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2646c6a44287SMartin K. Petersen { 2647cbf67842SDouglas Gilbert int i, j, n; 2648c6a44287SMartin K. Petersen 2649cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2650c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2651cbf67842SDouglas Gilbert char b[128]; 2652c6a44287SMartin K. Petersen 2653cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2654c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2655c6a44287SMartin K. Petersen 2656cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2657cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2658cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2659cbf67842SDouglas Gilbert else 2660cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2661cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2662cbf67842SDouglas Gilbert } 2663cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2664c6a44287SMartin K. Petersen } 2665c6a44287SMartin K. Petersen } 2666c6a44287SMartin K. Petersen 2667c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2668395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2669c6a44287SMartin K. Petersen { 2670be4e11beSAkinobu Mita int ret; 2671c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 2672be4e11beSAkinobu Mita void *daddr; 267365f72f2aSAkinobu Mita sector_t sector = start_sec; 2674c6a44287SMartin K. Petersen int ppage_offset; 2675be4e11beSAkinobu Mita int dpage_offset; 2676be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2677be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2678c6a44287SMartin K. Petersen 2679c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2680c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2681c6a44287SMartin K. Petersen 2682be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2683be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2684be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2685be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2686be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2687c6a44287SMartin K. Petersen 2688be4e11beSAkinobu Mita /* For each protection page */ 2689be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2690be4e11beSAkinobu Mita dpage_offset = 0; 2691be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2692be4e11beSAkinobu Mita ret = 0x01; 2693be4e11beSAkinobu Mita goto out; 2694c6a44287SMartin K. Petersen } 2695c6a44287SMartin K. Petersen 2696be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 2697be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 2698be4e11beSAkinobu Mita /* If we're at the end of the current 2699be4e11beSAkinobu Mita * data page advance to the next one 2700be4e11beSAkinobu Mita */ 2701be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2702be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2703be4e11beSAkinobu Mita ret = 0x01; 2704be4e11beSAkinobu Mita goto out; 2705be4e11beSAkinobu Mita } 2706be4e11beSAkinobu Mita dpage_offset = 0; 2707be4e11beSAkinobu Mita } 2708c6a44287SMartin K. Petersen 2709be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2710be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2711be4e11beSAkinobu Mita 2712be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2713beb40ea4SAkinobu Mita if (ret) { 2714773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2715395cef03SMartin K. Petersen goto out; 2716395cef03SMartin K. Petersen } 2717395cef03SMartin K. Petersen 2718c6a44287SMartin K. Petersen sector++; 2719395cef03SMartin K. Petersen ei_lba++; 2720773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2721c6a44287SMartin K. Petersen } 2722be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2723be4e11beSAkinobu Mita sg_miter_stop(&diter); 2724c6a44287SMartin K. Petersen } 2725be4e11beSAkinobu Mita sg_miter_stop(&piter); 2726c6a44287SMartin K. Petersen 272765f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2728c6a44287SMartin K. Petersen dix_writes++; 2729c6a44287SMartin K. Petersen 2730c6a44287SMartin K. Petersen return 0; 2731c6a44287SMartin K. Petersen 2732c6a44287SMartin K. Petersen out: 2733c6a44287SMartin K. Petersen dif_errors++; 2734be4e11beSAkinobu Mita sg_miter_stop(&diter); 2735be4e11beSAkinobu Mita sg_miter_stop(&piter); 2736c6a44287SMartin K. Petersen return ret; 2737c6a44287SMartin K. Petersen } 2738c6a44287SMartin K. Petersen 2739b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2740b90ebc3dSAkinobu Mita { 2741773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2742773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2743773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2744b90ebc3dSAkinobu Mita return lba; 2745b90ebc3dSAkinobu Mita } 2746b90ebc3dSAkinobu Mita 2747b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2748b90ebc3dSAkinobu Mita { 2749773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2750a027b5b9SAkinobu Mita 2751773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2752773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2753a027b5b9SAkinobu Mita return lba; 2754a027b5b9SAkinobu Mita } 2755a027b5b9SAkinobu Mita 275644d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 275744d92694SMartin K. Petersen { 2758b90ebc3dSAkinobu Mita sector_t end; 2759b90ebc3dSAkinobu Mita unsigned int mapped; 2760b90ebc3dSAkinobu Mita unsigned long index; 2761b90ebc3dSAkinobu Mita unsigned long next; 276244d92694SMartin K. Petersen 2763b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2764b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 276544d92694SMartin K. Petersen 276644d92694SMartin K. Petersen if (mapped) 2767b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 276844d92694SMartin K. Petersen else 2769b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 277044d92694SMartin K. Petersen 2771b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 277244d92694SMartin K. Petersen *num = end - lba; 277344d92694SMartin K. Petersen return mapped; 277444d92694SMartin K. Petersen } 277544d92694SMartin K. Petersen 277644d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 277744d92694SMartin K. Petersen { 277844d92694SMartin K. Petersen sector_t end = lba + len; 277944d92694SMartin K. Petersen 278044d92694SMartin K. Petersen while (lba < end) { 2781b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 278244d92694SMartin K. Petersen 2783b90ebc3dSAkinobu Mita if (index < map_size) 2784b90ebc3dSAkinobu Mita set_bit(index, map_storep); 278544d92694SMartin K. Petersen 2786b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 278744d92694SMartin K. Petersen } 278844d92694SMartin K. Petersen } 278944d92694SMartin K. Petersen 279044d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 279144d92694SMartin K. Petersen { 279244d92694SMartin K. Petersen sector_t end = lba + len; 279344d92694SMartin K. Petersen 279444d92694SMartin K. Petersen while (lba < end) { 2795b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 279644d92694SMartin K. Petersen 2797b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2798773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 2799b90ebc3dSAkinobu Mita index < map_size) { 2800b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2801760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 2802be1dd78dSEric Sandeen memset(fake_storep + 2803760f3b03SDouglas Gilbert lba * sdebug_sector_size, 2804760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 2805773642d9SDouglas Gilbert sdebug_sector_size * 2806773642d9SDouglas Gilbert sdebug_unmap_granularity); 2807be1dd78dSEric Sandeen } 2808e9926b43SAkinobu Mita if (dif_storep) { 2809e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2810e9926b43SAkinobu Mita sizeof(*dif_storep) * 2811773642d9SDouglas Gilbert sdebug_unmap_granularity); 2812e9926b43SAkinobu Mita } 2813b90ebc3dSAkinobu Mita } 2814b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 281544d92694SMartin K. Petersen } 281644d92694SMartin K. Petersen } 281744d92694SMartin K. Petersen 2818fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 28191da177e4SLinus Torvalds { 2820c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2821c2248fc9SDouglas Gilbert u64 lba; 2822c2248fc9SDouglas Gilbert u32 num; 2823c2248fc9SDouglas Gilbert u32 ei_lba; 28241da177e4SLinus Torvalds unsigned long iflags; 282519789100SFUJITA Tomonori int ret; 2826c2248fc9SDouglas Gilbert bool check_prot; 28271da177e4SLinus Torvalds 2828c2248fc9SDouglas Gilbert switch (cmd[0]) { 2829c2248fc9SDouglas Gilbert case WRITE_16: 2830c2248fc9SDouglas Gilbert ei_lba = 0; 2831c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2832c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2833c2248fc9SDouglas Gilbert check_prot = true; 2834c2248fc9SDouglas Gilbert break; 2835c2248fc9SDouglas Gilbert case WRITE_10: 2836c2248fc9SDouglas Gilbert ei_lba = 0; 2837c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2838c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2839c2248fc9SDouglas Gilbert check_prot = true; 2840c2248fc9SDouglas Gilbert break; 2841c2248fc9SDouglas Gilbert case WRITE_6: 2842c2248fc9SDouglas Gilbert ei_lba = 0; 2843c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2844c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2845c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2846c2248fc9SDouglas Gilbert check_prot = true; 2847c2248fc9SDouglas Gilbert break; 2848c2248fc9SDouglas Gilbert case WRITE_12: 2849c2248fc9SDouglas Gilbert ei_lba = 0; 2850c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2851c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2852c2248fc9SDouglas Gilbert check_prot = true; 2853c2248fc9SDouglas Gilbert break; 2854c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2855c2248fc9SDouglas Gilbert ei_lba = 0; 2856c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2857c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2858c2248fc9SDouglas Gilbert check_prot = false; 2859c2248fc9SDouglas Gilbert break; 2860c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2861c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2862c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2863c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2864c2248fc9SDouglas Gilbert check_prot = false; 2865c2248fc9SDouglas Gilbert break; 2866c2248fc9SDouglas Gilbert } 2867f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2868773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2869c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2870c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2871c2248fc9SDouglas Gilbert return check_condition_result; 2872c2248fc9SDouglas Gilbert } 2873773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2874773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2875c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2876c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2877c2248fc9SDouglas Gilbert "to DIF device\n"); 2878c2248fc9SDouglas Gilbert } 2879c2248fc9SDouglas Gilbert 2880c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2881f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2882c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2883c2248fc9SDouglas Gilbert return check_condition_result; 2884c2248fc9SDouglas Gilbert } 2885c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2886f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2887c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2888c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2889c2248fc9SDouglas Gilbert return check_condition_result; 2890c2248fc9SDouglas Gilbert } 28911da177e4SLinus Torvalds 28926c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 28936c78cc06SAkinobu Mita 2894c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2895f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2896c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2897c6a44287SMartin K. Petersen 2898c6a44287SMartin K. Petersen if (prot_ret) { 28996c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2900c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2901c6a44287SMartin K. Petersen return illegal_condition_result; 2902c6a44287SMartin K. Petersen } 2903c6a44287SMartin K. Petersen } 2904c6a44287SMartin K. Petersen 2905c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 2906f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 290744d92694SMartin K. Petersen map_region(lba, num); 29081da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 2909f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 2910773642d9SDouglas Gilbert return DID_ERROR << 16; 2911c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 2912c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 2913c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2914cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2915773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 291644d92694SMartin K. Petersen 2917f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2918c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 2919c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 2920c2248fc9SDouglas Gilbert 2921c4837394SDouglas Gilbert if (sqcp) { 2922c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2923c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2924c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2925c2248fc9SDouglas Gilbert return check_condition_result; 2926c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2927c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2928c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2929c2248fc9SDouglas Gilbert return illegal_condition_result; 2930c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2931c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2932c2248fc9SDouglas Gilbert return illegal_condition_result; 2933c2248fc9SDouglas Gilbert } 2934c2248fc9SDouglas Gilbert } 2935c4837394SDouglas Gilbert } 29361da177e4SLinus Torvalds return 0; 29371da177e4SLinus Torvalds } 29381da177e4SLinus Torvalds 2939fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 2940fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 294144d92694SMartin K. Petersen { 294244d92694SMartin K. Petersen unsigned long iflags; 294344d92694SMartin K. Petersen unsigned long long i; 294444d92694SMartin K. Petersen int ret; 2945773642d9SDouglas Gilbert u64 lba_off; 294644d92694SMartin K. Petersen 2947c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 294844d92694SMartin K. Petersen if (ret) 294944d92694SMartin K. Petersen return ret; 295044d92694SMartin K. Petersen 295144d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 295244d92694SMartin K. Petersen 29539ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 295444d92694SMartin K. Petersen unmap_region(lba, num); 295544d92694SMartin K. Petersen goto out; 295644d92694SMartin K. Petersen } 295744d92694SMartin K. Petersen 2958773642d9SDouglas Gilbert lba_off = lba * sdebug_sector_size; 2959c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 2960c2248fc9SDouglas Gilbert if (ndob) { 2961773642d9SDouglas Gilbert memset(fake_storep + lba_off, 0, sdebug_sector_size); 2962c2248fc9SDouglas Gilbert ret = 0; 2963c2248fc9SDouglas Gilbert } else 2964773642d9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + lba_off, 2965773642d9SDouglas Gilbert sdebug_sector_size); 296644d92694SMartin K. Petersen 296744d92694SMartin K. Petersen if (-1 == ret) { 296844d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 2969773642d9SDouglas Gilbert return DID_ERROR << 16; 2970773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) 2971c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2972cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 2973cbf67842SDouglas Gilbert my_name, "write same", 2974773642d9SDouglas Gilbert num * sdebug_sector_size, ret); 297544d92694SMartin K. Petersen 297644d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 297744d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 2978773642d9SDouglas Gilbert memcpy(fake_storep + ((lba + i) * sdebug_sector_size), 2979773642d9SDouglas Gilbert fake_storep + lba_off, 2980773642d9SDouglas Gilbert sdebug_sector_size); 298144d92694SMartin K. Petersen 29829ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 298344d92694SMartin K. Petersen map_region(lba, num); 298444d92694SMartin K. Petersen out: 298544d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 298644d92694SMartin K. Petersen 298744d92694SMartin K. Petersen return 0; 298844d92694SMartin K. Petersen } 298944d92694SMartin K. Petersen 2990fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 2991fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2992c2248fc9SDouglas Gilbert { 2993c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2994c2248fc9SDouglas Gilbert u32 lba; 2995c2248fc9SDouglas Gilbert u16 num; 2996c2248fc9SDouglas Gilbert u32 ei_lba = 0; 2997c2248fc9SDouglas Gilbert bool unmap = false; 2998c2248fc9SDouglas Gilbert 2999c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3000773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3001c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3002c2248fc9SDouglas Gilbert return check_condition_result; 3003c2248fc9SDouglas Gilbert } else 3004c2248fc9SDouglas Gilbert unmap = true; 3005c2248fc9SDouglas Gilbert } 3006c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3007c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3008773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3009c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3010c2248fc9SDouglas Gilbert return check_condition_result; 3011c2248fc9SDouglas Gilbert } 3012c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3013c2248fc9SDouglas Gilbert } 3014c2248fc9SDouglas Gilbert 3015fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3016fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3017c2248fc9SDouglas Gilbert { 3018c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3019c2248fc9SDouglas Gilbert u64 lba; 3020c2248fc9SDouglas Gilbert u32 num; 3021c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3022c2248fc9SDouglas Gilbert bool unmap = false; 3023c2248fc9SDouglas Gilbert bool ndob = false; 3024c2248fc9SDouglas Gilbert 3025c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3026773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3027c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3028c2248fc9SDouglas Gilbert return check_condition_result; 3029c2248fc9SDouglas Gilbert } else 3030c2248fc9SDouglas Gilbert unmap = true; 3031c2248fc9SDouglas Gilbert } 3032c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3033c2248fc9SDouglas Gilbert ndob = true; 3034c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3035c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3036773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3037c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3038c2248fc9SDouglas Gilbert return check_condition_result; 3039c2248fc9SDouglas Gilbert } 3040c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3041c2248fc9SDouglas Gilbert } 3042c2248fc9SDouglas Gilbert 3043acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3044acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3045acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3046fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3047fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3048acafd0b9SEwan D. Milne { 3049acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3050acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3051acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3052acafd0b9SEwan D. Milne u8 mode; 3053acafd0b9SEwan D. Milne 3054acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3055acafd0b9SEwan D. Milne switch (mode) { 3056acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3057acafd0b9SEwan D. Milne /* set UAs on this device only */ 3058acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3059acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3060acafd0b9SEwan D. Milne break; 3061acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3062acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3063acafd0b9SEwan D. Milne break; 3064acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3065acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3066acafd0b9SEwan D. Milne list_for_each_entry(dp, 3067acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3068acafd0b9SEwan D. Milne dev_list) 3069acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3070acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3071acafd0b9SEwan D. Milne if (devip != dp) 3072acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3073acafd0b9SEwan D. Milne dp->uas_bm); 3074acafd0b9SEwan D. Milne } 3075acafd0b9SEwan D. Milne break; 3076acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3077acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3078acafd0b9SEwan D. Milne list_for_each_entry(dp, 3079acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3080acafd0b9SEwan D. Milne dev_list) 3081acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3082acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3083acafd0b9SEwan D. Milne dp->uas_bm); 3084acafd0b9SEwan D. Milne break; 3085acafd0b9SEwan D. Milne default: 3086acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3087acafd0b9SEwan D. Milne break; 3088acafd0b9SEwan D. Milne } 3089acafd0b9SEwan D. Milne return 0; 3090acafd0b9SEwan D. Milne } 3091acafd0b9SEwan D. Milne 3092fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3093fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 309438d5c833SDouglas Gilbert { 309538d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 309638d5c833SDouglas Gilbert u8 *arr; 309738d5c833SDouglas Gilbert u8 *fake_storep_hold; 309838d5c833SDouglas Gilbert u64 lba; 309938d5c833SDouglas Gilbert u32 dnum; 3100773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 310138d5c833SDouglas Gilbert u8 num; 310238d5c833SDouglas Gilbert unsigned long iflags; 310338d5c833SDouglas Gilbert int ret; 3104d467d31fSDouglas Gilbert int retval = 0; 310538d5c833SDouglas Gilbert 3106d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 310738d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 310838d5c833SDouglas Gilbert if (0 == num) 310938d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 3110773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 311138d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 311238d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 311338d5c833SDouglas Gilbert return check_condition_result; 311438d5c833SDouglas Gilbert } 3115773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 3116773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 311738d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 311838d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 311938d5c833SDouglas Gilbert "to DIF device\n"); 312038d5c833SDouglas Gilbert 312138d5c833SDouglas Gilbert /* inline check_device_access_params() */ 312238d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 312338d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 312438d5c833SDouglas Gilbert return check_condition_result; 312538d5c833SDouglas Gilbert } 312638d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 312738d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 312838d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 312938d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 313038d5c833SDouglas Gilbert return check_condition_result; 313138d5c833SDouglas Gilbert } 3132d467d31fSDouglas Gilbert dnum = 2 * num; 3133d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3134d467d31fSDouglas Gilbert if (NULL == arr) { 3135d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3136d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3137d467d31fSDouglas Gilbert return check_condition_result; 3138d467d31fSDouglas Gilbert } 313938d5c833SDouglas Gilbert 314038d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 314138d5c833SDouglas Gilbert 314238d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 314338d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 314438d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 314538d5c833SDouglas Gilbert fake_storep = arr; 314638d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 314738d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 314838d5c833SDouglas Gilbert if (ret == -1) { 3149d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3150d467d31fSDouglas Gilbert goto cleanup; 3151773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 315238d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 315338d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 315438d5c833SDouglas Gilbert dnum * lb_size, ret); 315538d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 315638d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3157d467d31fSDouglas Gilbert retval = check_condition_result; 3158d467d31fSDouglas Gilbert goto cleanup; 315938d5c833SDouglas Gilbert } 316038d5c833SDouglas Gilbert if (scsi_debug_lbp()) 316138d5c833SDouglas Gilbert map_region(lba, num); 3162d467d31fSDouglas Gilbert cleanup: 316338d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3164d467d31fSDouglas Gilbert kfree(arr); 3165d467d31fSDouglas Gilbert return retval; 316638d5c833SDouglas Gilbert } 316738d5c833SDouglas Gilbert 316844d92694SMartin K. Petersen struct unmap_block_desc { 316944d92694SMartin K. Petersen __be64 lba; 317044d92694SMartin K. Petersen __be32 blocks; 317144d92694SMartin K. Petersen __be32 __reserved; 317244d92694SMartin K. Petersen }; 317344d92694SMartin K. Petersen 3174fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 317544d92694SMartin K. Petersen { 317644d92694SMartin K. Petersen unsigned char *buf; 317744d92694SMartin K. Petersen struct unmap_block_desc *desc; 317844d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 317944d92694SMartin K. Petersen int ret; 31806c78cc06SAkinobu Mita unsigned long iflags; 318144d92694SMartin K. Petersen 318244d92694SMartin K. Petersen 3183c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3184c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3185c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3186c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 318744d92694SMartin K. Petersen 318844d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3189773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3190c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 319144d92694SMartin K. Petersen return check_condition_result; 3192c2248fc9SDouglas Gilbert } 319344d92694SMartin K. Petersen 3194b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3195c2248fc9SDouglas Gilbert if (!buf) { 3196c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3197c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3198c2248fc9SDouglas Gilbert return check_condition_result; 3199c2248fc9SDouglas Gilbert } 3200c2248fc9SDouglas Gilbert 3201c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 320244d92694SMartin K. Petersen 320344d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 320444d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 320544d92694SMartin K. Petersen 320644d92694SMartin K. Petersen desc = (void *)&buf[8]; 320744d92694SMartin K. Petersen 32086c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 32096c78cc06SAkinobu Mita 321044d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 321144d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 321244d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 321344d92694SMartin K. Petersen 3214c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 321544d92694SMartin K. Petersen if (ret) 321644d92694SMartin K. Petersen goto out; 321744d92694SMartin K. Petersen 321844d92694SMartin K. Petersen unmap_region(lba, num); 321944d92694SMartin K. Petersen } 322044d92694SMartin K. Petersen 322144d92694SMartin K. Petersen ret = 0; 322244d92694SMartin K. Petersen 322344d92694SMartin K. Petersen out: 32246c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 322544d92694SMartin K. Petersen kfree(buf); 322644d92694SMartin K. Petersen 322744d92694SMartin K. Petersen return ret; 322844d92694SMartin K. Petersen } 322944d92694SMartin K. Petersen 323044d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 323144d92694SMartin K. Petersen 3232fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3233fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 323444d92694SMartin K. Petersen { 3235c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3236c2248fc9SDouglas Gilbert u64 lba; 3237c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3238c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 323944d92694SMartin K. Petersen int ret; 324044d92694SMartin K. Petersen 3241c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3242c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 324344d92694SMartin K. Petersen 324444d92694SMartin K. Petersen if (alloc_len < 24) 324544d92694SMartin K. Petersen return 0; 324644d92694SMartin K. Petersen 3247c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 324844d92694SMartin K. Petersen if (ret) 324944d92694SMartin K. Petersen return ret; 325044d92694SMartin K. Petersen 3251c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 325244d92694SMartin K. Petersen mapped = map_state(lba, &num); 3253c2248fc9SDouglas Gilbert else { 3254c2248fc9SDouglas Gilbert mapped = 1; 3255c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3256c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3257c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3258c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3259c2248fc9SDouglas Gilbert else 3260c2248fc9SDouglas Gilbert num = 0xffffffff; 3261c2248fc9SDouglas Gilbert } 326244d92694SMartin K. Petersen 326344d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3264c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3265c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3266c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3267c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 326844d92694SMartin K. Petersen 3269c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 327044d92694SMartin K. Petersen } 327144d92694SMartin K. Petersen 32728d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 32738d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 32748d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 32758d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 32768d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 32778d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 32788d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 32798d039e22SDouglas Gilbert */ 32801da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 32811da177e4SLinus Torvalds struct sdebug_dev_info *devip) 32821da177e4SLinus Torvalds { 328301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 32848d039e22SDouglas Gilbert unsigned int alloc_len; 32858d039e22SDouglas Gilbert unsigned char select_report; 32868d039e22SDouglas Gilbert u64 lun; 32878d039e22SDouglas Gilbert struct scsi_lun *lun_p; 32888d039e22SDouglas Gilbert u8 *arr; 32898d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 32908d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 32918d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 32928d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 32938d039e22SDouglas Gilbert int i, res; 32941da177e4SLinus Torvalds 329519c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 32968d039e22SDouglas Gilbert 32978d039e22SDouglas Gilbert select_report = cmd[2]; 32988d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 32998d039e22SDouglas Gilbert 33008d039e22SDouglas Gilbert if (alloc_len < 4) { 33018d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 33028d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 33031da177e4SLinus Torvalds return check_condition_result; 33041da177e4SLinus Torvalds } 33058d039e22SDouglas Gilbert 33068d039e22SDouglas Gilbert switch (select_report) { 33078d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 3308773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 33098d039e22SDouglas Gilbert wlun_cnt = 0; 33108d039e22SDouglas Gilbert break; 33118d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 3312c65b1445SDouglas Gilbert lun_cnt = 0; 33138d039e22SDouglas Gilbert wlun_cnt = 1; 33148d039e22SDouglas Gilbert break; 33158d039e22SDouglas Gilbert case 2: /* all LUNs */ 33168d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 33178d039e22SDouglas Gilbert wlun_cnt = 1; 33188d039e22SDouglas Gilbert break; 33198d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 33208d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 33218d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 33228d039e22SDouglas Gilbert default: 33238d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 33248d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 33258d039e22SDouglas Gilbert return check_condition_result; 33268d039e22SDouglas Gilbert } 33278d039e22SDouglas Gilbert 33288d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 3329c65b1445SDouglas Gilbert --lun_cnt; 33308d039e22SDouglas Gilbert 33318d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 33328d039e22SDouglas Gilbert 33338d039e22SDouglas Gilbert rlen = (tlun_cnt * sizeof(struct scsi_lun)) + 8; 33348d039e22SDouglas Gilbert arr = vmalloc(rlen); 33358d039e22SDouglas Gilbert if (!arr) { 33368d039e22SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 33378d039e22SDouglas Gilbert INSUFF_RES_ASCQ); 33388d039e22SDouglas Gilbert return check_condition_result; 3339c65b1445SDouglas Gilbert } 33408d039e22SDouglas Gilbert memset(arr, 0, rlen); 33418d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 33428d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 33438d039e22SDouglas Gilbert 33448d039e22SDouglas Gilbert /* luns start at byte 8 in response following the header */ 33458d039e22SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[8]; 33468d039e22SDouglas Gilbert 33478d039e22SDouglas Gilbert /* LUNs use single level peripheral device addressing method */ 33488d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 33498d039e22SDouglas Gilbert for (i = 0; i < lun_cnt; i++) 33508d039e22SDouglas Gilbert int_to_scsilun(lun++, lun_p++); 33518d039e22SDouglas Gilbert 33528d039e22SDouglas Gilbert if (wlun_cnt) 33538d039e22SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p++); 33548d039e22SDouglas Gilbert 33558d039e22SDouglas Gilbert put_unaligned_be32(rlen - 8, &arr[0]); 33568d039e22SDouglas Gilbert 33578d039e22SDouglas Gilbert res = fill_from_dev_buffer(scp, arr, rlen); 33588d039e22SDouglas Gilbert vfree(arr); 33598d039e22SDouglas Gilbert return res; 33601da177e4SLinus Torvalds } 33611da177e4SLinus Torvalds 3362c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3363c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3364c639d14eSFUJITA Tomonori { 3365be4e11beSAkinobu Mita int j; 3366c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3367c639d14eSFUJITA Tomonori unsigned int offset; 3368c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3369be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3370c639d14eSFUJITA Tomonori 3371c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3372b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3373c5af0db9SAkinobu Mita if (!buf) { 337422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 337522017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3376c5af0db9SAkinobu Mita return check_condition_result; 3377c5af0db9SAkinobu Mita } 3378c639d14eSFUJITA Tomonori 337921a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3380c639d14eSFUJITA Tomonori 3381c639d14eSFUJITA Tomonori offset = 0; 3382be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3383be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3384c639d14eSFUJITA Tomonori 3385be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3386be4e11beSAkinobu Mita kaddr = miter.addr; 3387be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3388be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3389c639d14eSFUJITA Tomonori 3390be4e11beSAkinobu Mita offset += miter.length; 3391c639d14eSFUJITA Tomonori } 3392be4e11beSAkinobu Mita sg_miter_stop(&miter); 3393c639d14eSFUJITA Tomonori kfree(buf); 3394c639d14eSFUJITA Tomonori 3395be4e11beSAkinobu Mita return 0; 3396c639d14eSFUJITA Tomonori } 3397c639d14eSFUJITA Tomonori 3398fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp, 3399fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3400c2248fc9SDouglas Gilbert { 3401c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3402c2248fc9SDouglas Gilbert u64 lba; 3403c2248fc9SDouglas Gilbert u32 num; 3404c2248fc9SDouglas Gilbert int errsts; 3405c2248fc9SDouglas Gilbert 3406c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3407c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3408c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3409c2248fc9SDouglas Gilbert return check_condition_result; 3410c2248fc9SDouglas Gilbert } 3411c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3412c2248fc9SDouglas Gilbert if (errsts) 3413c2248fc9SDouglas Gilbert return errsts; 3414c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3415c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3416c2248fc9SDouglas Gilbert if (errsts) 3417c2248fc9SDouglas Gilbert return errsts; 3418c2248fc9SDouglas Gilbert } 3419c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3420c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3421c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3422c2248fc9SDouglas Gilbert } 3423c2248fc9SDouglas Gilbert 3424c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 3425c4837394SDouglas Gilbert { 3426c4837394SDouglas Gilbert struct sdebug_queue *sqp = sdebug_q_arr; 3427c4837394SDouglas Gilbert 3428c4837394SDouglas Gilbert if (sdebug_mq_active) { 3429c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 3430c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 3431c4837394SDouglas Gilbert 3432c4837394SDouglas Gilbert if (unlikely(hwq >= submit_queues)) { 3433c4837394SDouglas Gilbert pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); 3434c4837394SDouglas Gilbert hwq %= submit_queues; 3435c4837394SDouglas Gilbert } 3436c4837394SDouglas Gilbert pr_debug("tag=%u, hwq=%d\n", tag, hwq); 3437c4837394SDouglas Gilbert return sqp + hwq; 3438c4837394SDouglas Gilbert } else 3439c4837394SDouglas Gilbert return sqp; 3440c4837394SDouglas Gilbert } 3441c4837394SDouglas Gilbert 3442c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 3443fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 34441da177e4SLinus Torvalds { 3445c4837394SDouglas Gilbert int qc_idx; 3446cbf67842SDouglas Gilbert int retiring = 0; 34471da177e4SLinus Torvalds unsigned long iflags; 3448c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3449cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3450cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3451cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 34521da177e4SLinus Torvalds 3453c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 3454c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 3455c4837394SDouglas Gilbert if (sdebug_statistics) { 3456cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3457c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 3458c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 3459c4837394SDouglas Gilbert } 3460c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 3461c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 34621da177e4SLinus Torvalds return; 34631da177e4SLinus Torvalds } 3464c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3465c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 3466cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3467b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 3468c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3469c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 3470c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 34711da177e4SLinus Torvalds return; 34721da177e4SLinus Torvalds } 3473cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3474f46eb0e9SDouglas Gilbert if (likely(devip)) 3475cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3476cbf67842SDouglas Gilbert else 3477c1287970STomas Winkler pr_err("devip=NULL\n"); 3478f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3479cbf67842SDouglas Gilbert retiring = 1; 3480cbf67842SDouglas Gilbert 3481cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3482c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 3483c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3484c1287970STomas Winkler pr_err("Unexpected completion\n"); 3485cbf67842SDouglas Gilbert return; 34861da177e4SLinus Torvalds } 34871da177e4SLinus Torvalds 3488cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3489cbf67842SDouglas Gilbert int k, retval; 3490cbf67842SDouglas Gilbert 3491cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3492c4837394SDouglas Gilbert if (qc_idx >= retval) { 3493c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3494c1287970STomas Winkler pr_err("index %d too large\n", retval); 3495cbf67842SDouglas Gilbert return; 3496cbf67842SDouglas Gilbert } 3497c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 3498773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3499cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3500cbf67842SDouglas Gilbert else 3501cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3502cbf67842SDouglas Gilbert } 3503c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3504cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3505cbf67842SDouglas Gilbert } 3506cbf67842SDouglas Gilbert 3507cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3508fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3509cbf67842SDouglas Gilbert { 3510a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 3511a10bc12aSDouglas Gilbert hrt); 3512a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3513cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3514cbf67842SDouglas Gilbert } 35151da177e4SLinus Torvalds 3516a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 3517fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 3518a10bc12aSDouglas Gilbert { 3519a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 3520a10bc12aSDouglas Gilbert ew.work); 3521a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3522a10bc12aSDouglas Gilbert } 3523a10bc12aSDouglas Gilbert 352409ba24c1SDouglas Gilbert static bool got_shared_uuid; 352509ba24c1SDouglas Gilbert static uuid_be shared_uuid; 352609ba24c1SDouglas Gilbert 3527fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 3528fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 35295cb2fc06SFUJITA Tomonori { 35305cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 35315cb2fc06SFUJITA Tomonori 35325cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 35335cb2fc06SFUJITA Tomonori if (devip) { 353409ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 353509ba24c1SDouglas Gilbert uuid_be_gen(&devip->lu_name); 353609ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 353709ba24c1SDouglas Gilbert if (got_shared_uuid) 353809ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 353909ba24c1SDouglas Gilbert else { 354009ba24c1SDouglas Gilbert uuid_be_gen(&shared_uuid); 354109ba24c1SDouglas Gilbert got_shared_uuid = true; 354209ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 354309ba24c1SDouglas Gilbert } 354409ba24c1SDouglas Gilbert } 35455cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 35465cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 35475cb2fc06SFUJITA Tomonori } 35485cb2fc06SFUJITA Tomonori return devip; 35495cb2fc06SFUJITA Tomonori } 35505cb2fc06SFUJITA Tomonori 3551f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 35521da177e4SLinus Torvalds { 35531da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 35541da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 3555f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 35561da177e4SLinus Torvalds 3557d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 35581da177e4SLinus Torvalds if (!sdbg_host) { 3559c1287970STomas Winkler pr_err("Host info NULL\n"); 35601da177e4SLinus Torvalds return NULL; 35611da177e4SLinus Torvalds } 35621da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 35631da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 35641da177e4SLinus Torvalds (devip->target == sdev->id) && 35651da177e4SLinus Torvalds (devip->lun == sdev->lun)) 35661da177e4SLinus Torvalds return devip; 35671da177e4SLinus Torvalds else { 35681da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 35691da177e4SLinus Torvalds open_devip = devip; 35701da177e4SLinus Torvalds } 35711da177e4SLinus Torvalds } 35725cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 35735cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 35745cb2fc06SFUJITA Tomonori if (!open_devip) { 3575c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 35761da177e4SLinus Torvalds return NULL; 35771da177e4SLinus Torvalds } 35781da177e4SLinus Torvalds } 3579a75869d1SFUJITA Tomonori 35801da177e4SLinus Torvalds open_devip->channel = sdev->channel; 35811da177e4SLinus Torvalds open_devip->target = sdev->id; 35821da177e4SLinus Torvalds open_devip->lun = sdev->lun; 35831da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3584cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3585cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3586c2248fc9SDouglas Gilbert open_devip->used = true; 35871da177e4SLinus Torvalds return open_devip; 35881da177e4SLinus Torvalds } 35891da177e4SLinus Torvalds 35908dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 35911da177e4SLinus Torvalds { 3592773642d9SDouglas Gilbert if (sdebug_verbose) 3593c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 35948dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 359575ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 35968dea0d02SFUJITA Tomonori return 0; 35978dea0d02SFUJITA Tomonori } 35981da177e4SLinus Torvalds 35998dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 36008dea0d02SFUJITA Tomonori { 3601f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3602f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3603a34c4e98SFUJITA Tomonori 3604773642d9SDouglas Gilbert if (sdebug_verbose) 3605c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 36068dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 3607b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 3608b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 3609b01f6f83SDouglas Gilbert if (devip == NULL) { 3610f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 3611b01f6f83SDouglas Gilbert if (devip == NULL) 36128dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3613f46eb0e9SDouglas Gilbert } 3614c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 36156bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 3616773642d9SDouglas Gilbert if (sdebug_no_uld) 361778d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 36188dea0d02SFUJITA Tomonori return 0; 36198dea0d02SFUJITA Tomonori } 36208dea0d02SFUJITA Tomonori 36218dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 36228dea0d02SFUJITA Tomonori { 36238dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 36248dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 36258dea0d02SFUJITA Tomonori 3626773642d9SDouglas Gilbert if (sdebug_verbose) 3627c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 36288dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 36298dea0d02SFUJITA Tomonori if (devip) { 363025985edcSLucas De Marchi /* make this slot available for re-use */ 3631c2248fc9SDouglas Gilbert devip->used = false; 36328dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 36338dea0d02SFUJITA Tomonori } 36348dea0d02SFUJITA Tomonori } 36358dea0d02SFUJITA Tomonori 3636c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp) 3637c4837394SDouglas Gilbert { 3638c4837394SDouglas Gilbert if (!sd_dp) 3639c4837394SDouglas Gilbert return; 3640c4837394SDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) 3641c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3642c4837394SDouglas Gilbert else if (sdebug_jdelay < 0) 3643c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3644c4837394SDouglas Gilbert } 3645c4837394SDouglas Gilbert 3646a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 3647a10bc12aSDouglas Gilbert returns false */ 3648a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 36498dea0d02SFUJITA Tomonori { 36508dea0d02SFUJITA Tomonori unsigned long iflags; 3651c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 3652c4837394SDouglas Gilbert struct sdebug_queue *sqp; 36538dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3654cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3655a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 36568dea0d02SFUJITA Tomonori 3657c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3658c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3659773642d9SDouglas Gilbert qmax = sdebug_max_queue; 3660cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3661cbf67842SDouglas Gilbert if (r_qmax > qmax) 3662cbf67842SDouglas Gilbert qmax = r_qmax; 3663cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3664c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3665c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3666a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 3667a10bc12aSDouglas Gilbert continue; 3668c4837394SDouglas Gilbert /* found */ 3669db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3670db525fceSDouglas Gilbert cmnd->device->hostdata; 3671db525fceSDouglas Gilbert if (devip) 3672db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3673db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3674a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3675c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3676c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3677c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3678a10bc12aSDouglas Gilbert return true; 36798dea0d02SFUJITA Tomonori } 3680cbf67842SDouglas Gilbert } 3681c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3682c4837394SDouglas Gilbert } 3683a10bc12aSDouglas Gilbert return false; 36848dea0d02SFUJITA Tomonori } 36858dea0d02SFUJITA Tomonori 3686a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 36878dea0d02SFUJITA Tomonori static void stop_all_queued(void) 36888dea0d02SFUJITA Tomonori { 36898dea0d02SFUJITA Tomonori unsigned long iflags; 3690c4837394SDouglas Gilbert int j, k; 3691c4837394SDouglas Gilbert struct sdebug_queue *sqp; 36928dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3693cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3694a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 36958dea0d02SFUJITA Tomonori 3696c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3697c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3698c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3699c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3700c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3701c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 3702a10bc12aSDouglas Gilbert continue; 3703db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3704db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3705db525fceSDouglas Gilbert if (devip) 3706db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3707db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3708a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3709c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3710c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3711c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3712c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 37138dea0d02SFUJITA Tomonori } 37148dea0d02SFUJITA Tomonori } 3715c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3716c4837394SDouglas Gilbert } 3717cbf67842SDouglas Gilbert } 3718cbf67842SDouglas Gilbert 3719cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3720cbf67842SDouglas Gilbert static void free_all_queued(void) 3721cbf67842SDouglas Gilbert { 3722c4837394SDouglas Gilbert int j, k; 3723c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3724cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3725cbf67842SDouglas Gilbert 3726c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3727c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3728c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3729a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 3730a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 3731cbf67842SDouglas Gilbert } 37321da177e4SLinus Torvalds } 3733c4837394SDouglas Gilbert } 37341da177e4SLinus Torvalds 37351da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 37361da177e4SLinus Torvalds { 3737a10bc12aSDouglas Gilbert bool ok; 3738a10bc12aSDouglas Gilbert 37391da177e4SLinus Torvalds ++num_aborts; 3740cbf67842SDouglas Gilbert if (SCpnt) { 3741a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 3742a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3743a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3744a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 3745a10bc12aSDouglas Gilbert ok ? "" : " not"); 3746cbf67842SDouglas Gilbert } 37471da177e4SLinus Torvalds return SUCCESS; 37481da177e4SLinus Torvalds } 37491da177e4SLinus Torvalds 37501da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 37511da177e4SLinus Torvalds { 37521da177e4SLinus Torvalds ++num_dev_resets; 3753cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3754cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3755f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3756f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3757cbf67842SDouglas Gilbert 3758773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3759cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 37601da177e4SLinus Torvalds if (devip) 3761cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 37621da177e4SLinus Torvalds } 37631da177e4SLinus Torvalds return SUCCESS; 37641da177e4SLinus Torvalds } 37651da177e4SLinus Torvalds 3766cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3767cbf67842SDouglas Gilbert { 3768cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3769cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3770cbf67842SDouglas Gilbert struct scsi_device *sdp; 3771cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3772cbf67842SDouglas Gilbert int k = 0; 3773cbf67842SDouglas Gilbert 3774cbf67842SDouglas Gilbert ++num_target_resets; 3775cbf67842SDouglas Gilbert if (!SCpnt) 3776cbf67842SDouglas Gilbert goto lie; 3777cbf67842SDouglas Gilbert sdp = SCpnt->device; 3778cbf67842SDouglas Gilbert if (!sdp) 3779cbf67842SDouglas Gilbert goto lie; 3780773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3781cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3782cbf67842SDouglas Gilbert hp = sdp->host; 3783cbf67842SDouglas Gilbert if (!hp) 3784cbf67842SDouglas Gilbert goto lie; 3785cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3786cbf67842SDouglas Gilbert if (sdbg_host) { 3787cbf67842SDouglas Gilbert list_for_each_entry(devip, 3788cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3789cbf67842SDouglas Gilbert dev_list) 3790cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3791cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3792cbf67842SDouglas Gilbert ++k; 3793cbf67842SDouglas Gilbert } 3794cbf67842SDouglas Gilbert } 3795773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3796cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3797cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3798cbf67842SDouglas Gilbert lie: 3799cbf67842SDouglas Gilbert return SUCCESS; 3800cbf67842SDouglas Gilbert } 3801cbf67842SDouglas Gilbert 38021da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 38031da177e4SLinus Torvalds { 38041da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3805cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 38061da177e4SLinus Torvalds struct scsi_device * sdp; 38071da177e4SLinus Torvalds struct Scsi_Host * hp; 3808cbf67842SDouglas Gilbert int k = 0; 38091da177e4SLinus Torvalds 38101da177e4SLinus Torvalds ++num_bus_resets; 3811cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3812cbf67842SDouglas Gilbert goto lie; 3813cbf67842SDouglas Gilbert sdp = SCpnt->device; 3814773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3815cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3816cbf67842SDouglas Gilbert hp = sdp->host; 3817cbf67842SDouglas Gilbert if (hp) { 3818d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 38191da177e4SLinus Torvalds if (sdbg_host) { 3820cbf67842SDouglas Gilbert list_for_each_entry(devip, 38211da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3822cbf67842SDouglas Gilbert dev_list) { 3823cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3824cbf67842SDouglas Gilbert ++k; 38251da177e4SLinus Torvalds } 38261da177e4SLinus Torvalds } 3827cbf67842SDouglas Gilbert } 3828773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3829cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3830cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3831cbf67842SDouglas Gilbert lie: 38321da177e4SLinus Torvalds return SUCCESS; 38331da177e4SLinus Torvalds } 38341da177e4SLinus Torvalds 38351da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 38361da177e4SLinus Torvalds { 38371da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3838cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3839cbf67842SDouglas Gilbert int k = 0; 38401da177e4SLinus Torvalds 38411da177e4SLinus Torvalds ++num_host_resets; 3842773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3843cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 38441da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 38451da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3846cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3847cbf67842SDouglas Gilbert dev_list) { 3848cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3849cbf67842SDouglas Gilbert ++k; 3850cbf67842SDouglas Gilbert } 38511da177e4SLinus Torvalds } 38521da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 38531da177e4SLinus Torvalds stop_all_queued(); 3854773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3855cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3856cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 38571da177e4SLinus Torvalds return SUCCESS; 38581da177e4SLinus Torvalds } 38591da177e4SLinus Torvalds 3860f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 38615f2578e5SFUJITA Tomonori unsigned long store_size) 38621da177e4SLinus Torvalds { 38631da177e4SLinus Torvalds struct partition * pp; 38641da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 38651da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 38661da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 38671da177e4SLinus Torvalds 38681da177e4SLinus Torvalds /* assume partition table already zeroed */ 3869773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 38701da177e4SLinus Torvalds return; 3871773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 3872773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 3873c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 38741da177e4SLinus Torvalds } 3875c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 38761da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 3877773642d9SDouglas Gilbert / sdebug_num_parts; 38781da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 38791da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 3880773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 38811da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 38821da177e4SLinus Torvalds * heads_by_sects; 3883773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 3884773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 38851da177e4SLinus Torvalds 38861da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 38871da177e4SLinus Torvalds ramp[511] = 0xAA; 38881da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 38891da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 38901da177e4SLinus Torvalds start_sec = starts[k]; 38911da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 38921da177e4SLinus Torvalds pp->boot_ind = 0; 38931da177e4SLinus Torvalds 38941da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 38951da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 38961da177e4SLinus Torvalds / sdebug_sectors_per; 38971da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 38981da177e4SLinus Torvalds 38991da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 39001da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 39011da177e4SLinus Torvalds / sdebug_sectors_per; 39021da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 39031da177e4SLinus Torvalds 3904150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3905150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 39061da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 39071da177e4SLinus Torvalds } 39081da177e4SLinus Torvalds } 39091da177e4SLinus Torvalds 3910c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 3911c4837394SDouglas Gilbert { 3912c4837394SDouglas Gilbert int j; 3913c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3914c4837394SDouglas Gilbert 3915c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 3916c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 3917c4837394SDouglas Gilbert } 3918c4837394SDouglas Gilbert 3919c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 3920c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 3921c4837394SDouglas Gilbert */ 3922c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 3923c4837394SDouglas Gilbert { 3924c4837394SDouglas Gilbert int count, modulo; 3925c4837394SDouglas Gilbert 3926c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 3927c4837394SDouglas Gilbert if (modulo < 2) 3928c4837394SDouglas Gilbert return; 3929c4837394SDouglas Gilbert block_unblock_all_queues(true); 3930c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 3931c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 3932c4837394SDouglas Gilbert block_unblock_all_queues(false); 3933c4837394SDouglas Gilbert } 3934c4837394SDouglas Gilbert 3935c4837394SDouglas Gilbert static void clear_queue_stats(void) 3936c4837394SDouglas Gilbert { 3937c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 3938c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 3939c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 3940c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3941c4837394SDouglas Gilbert } 3942c4837394SDouglas Gilbert 3943c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 3944c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 3945c4837394SDouglas Gilbert { 3946c4837394SDouglas Gilbert if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) 3947c4837394SDouglas Gilbert return; 3948c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 3949c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 3950c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 3951c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 3952c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 3953c4837394SDouglas Gilbert } 3954c4837394SDouglas Gilbert 3955c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 3956c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 3957c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 3958c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 3959c4837394SDouglas Gilbert */ 3960fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 3961cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 39621da177e4SLinus Torvalds { 3963cbf67842SDouglas Gilbert unsigned long iflags; 3964cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 3965c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3966c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3967299b6c07STomas Winkler struct scsi_device *sdp; 3968a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 39691da177e4SLinus Torvalds 3970b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 3971b01f6f83SDouglas Gilbert if (scsi_result == 0) 3972f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 3973f46eb0e9SDouglas Gilbert goto respond_in_thread; 39741da177e4SLinus Torvalds } 3975299b6c07STomas Winkler sdp = cmnd->device; 3976299b6c07STomas Winkler 3977f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && scsi_result)) 3978cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 3979cbf67842SDouglas Gilbert __func__, scsi_result); 3980cd62b7daSDouglas Gilbert if (delta_jiff == 0) 3981cd62b7daSDouglas Gilbert goto respond_in_thread; 39821da177e4SLinus Torvalds 3983cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 3984c4837394SDouglas Gilbert sqp = get_queue(cmnd); 3985c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3986c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 3987c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3988c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3989c4837394SDouglas Gilbert } 3990cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 3991cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 3992cbf67842SDouglas Gilbert inject = 0; 3993f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 3994cd62b7daSDouglas Gilbert if (scsi_result) { 3995c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3996cd62b7daSDouglas Gilbert goto respond_in_thread; 3997cd62b7daSDouglas Gilbert } else 3998cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3999c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 4000773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 4001f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 4002cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 4003cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 4004773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 4005cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4006cbf67842SDouglas Gilbert inject = 1; 4007cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 40081da177e4SLinus Torvalds } 4009cbf67842SDouglas Gilbert } 4010cbf67842SDouglas Gilbert 4011c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 4012f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 4013c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4014cd62b7daSDouglas Gilbert if (scsi_result) 4015cd62b7daSDouglas Gilbert goto respond_in_thread; 4016773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 4017cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4018773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 4019cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4020cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 4021773642d9SDouglas Gilbert __func__, sdebug_max_queue, 4022cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 4023cbf67842SDouglas Gilbert "report: host busy")); 4024cd62b7daSDouglas Gilbert if (scsi_result) 4025cd62b7daSDouglas Gilbert goto respond_in_thread; 4026cd62b7daSDouglas Gilbert else 4027cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 40281da177e4SLinus Torvalds } 4029c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 4030cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4031c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 40321da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4033c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 4034cbf67842SDouglas Gilbert cmnd->result = scsi_result; 4035a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 4036c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4037c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 4038c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 4039b01f6f83SDouglas Gilbert if (delta_jiff > 0 || sdebug_ndelay > 0) { 4040b333a819SDouglas Gilbert ktime_t kt; 4041cbf67842SDouglas Gilbert 4042b333a819SDouglas Gilbert if (delta_jiff > 0) { 4043b333a819SDouglas Gilbert struct timespec ts; 4044b333a819SDouglas Gilbert 4045b333a819SDouglas Gilbert jiffies_to_timespec(delta_jiff, &ts); 4046b333a819SDouglas Gilbert kt = ktime_set(ts.tv_sec, ts.tv_nsec); 4047b333a819SDouglas Gilbert } else 4048b333a819SDouglas Gilbert kt = ktime_set(0, sdebug_ndelay); 4049a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4050a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 4051a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4052cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4053a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4054a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 4055c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 4056a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 4057c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4058c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4059cbf67842SDouglas Gilbert } 4060c4837394SDouglas Gilbert if (sdebug_statistics) 4061c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4062c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 4063c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 4064a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4065a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); 4066a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4067cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4068a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4069c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4070c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4071a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 4072cbf67842SDouglas Gilbert } 4073c4837394SDouglas Gilbert if (sdebug_statistics) 4074c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4075a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 4076cbf67842SDouglas Gilbert } 4077f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 4078f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 4079cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4080cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4081cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4082cbf67842SDouglas Gilbert "status: TASK SET FULL"); 40831da177e4SLinus Torvalds return 0; 4084cd62b7daSDouglas Gilbert 4085cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4086cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4087cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4088cd62b7daSDouglas Gilbert return 0; 40891da177e4SLinus Torvalds } 4090cbf67842SDouglas Gilbert 409123183910SDouglas Gilbert /* Note: The following macros create attribute files in the 409223183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 409323183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 409423183910SDouglas Gilbert as it can when the corresponding attribute in the 409523183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 409623183910SDouglas Gilbert */ 4097773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 4098773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 4099773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 4100c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 4101773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 4102773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 4103773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 4104773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 4105773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 4106773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 4107773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 4108773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 4109773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 4110773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 4111773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 4112773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 4113773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 4114773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 4115773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 4116773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 4117773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 4118773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 4119773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 4120773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 4121773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 4122773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 4123773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 4124773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 4125773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 4126773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 4127773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 4128c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 4129773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 4130c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 4131773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 4132773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 4133773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 4134773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 4135773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 413609ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 4137773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 413823183910SDouglas Gilbert S_IRUGO | S_IWUSR); 4139773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 41405b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 41411da177e4SLinus Torvalds 41421da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 41431da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 41441da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4145b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 41461da177e4SLinus Torvalds 41471da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 41485b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 41490759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4150cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4151c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 41525b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 41535b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4154c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4155beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 415623183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 41575b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4158185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 41595b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 41605b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 41615b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4162760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz, 4163760f3b03SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 41645b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4165c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4166cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4167cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4168c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 416978d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 41701da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4171c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 417232c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 41736f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 41745b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 41751da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4176d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4177760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 4178ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4179c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 4180c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 4181c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 41825b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 41835b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 41846014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 41856014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 418609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 418709ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 4188c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 41895b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 41905b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 41911da177e4SLinus Torvalds 4192760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 4193760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 41941da177e4SLinus Torvalds 41951da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 41961da177e4SLinus Torvalds { 4197c4837394SDouglas Gilbert int k; 4198c4837394SDouglas Gilbert 4199760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 4200760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 4201760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 4202c4837394SDouglas Gilbert return sdebug_info; 4203760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 4204760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 4205760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 4206760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 42071da177e4SLinus Torvalds return sdebug_info; 42081da177e4SLinus Torvalds } 42091da177e4SLinus Torvalds 4210cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4211fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 4212fd32119bSDouglas Gilbert int length) 42131da177e4SLinus Torvalds { 42141da177e4SLinus Torvalds char arr[16]; 4215c8ed555aSAl Viro int opts; 42161da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 42171da177e4SLinus Torvalds 42181da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 42191da177e4SLinus Torvalds return -EACCES; 42201da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 42211da177e4SLinus Torvalds arr[minLen] = '\0'; 4222c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 42231da177e4SLinus Torvalds return -EINVAL; 4224773642d9SDouglas Gilbert sdebug_opts = opts; 4225773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4226773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4227773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4228c4837394SDouglas Gilbert tweak_cmnd_count(); 42291da177e4SLinus Torvalds return length; 42301da177e4SLinus Torvalds } 4231c8ed555aSAl Viro 4232cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4233cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4234cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4235c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4236c8ed555aSAl Viro { 4237c4837394SDouglas Gilbert int f, j, l; 4238c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4239cbf67842SDouglas Gilbert 4240c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 4241c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 4242c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 4243c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 4244c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 4245c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 4246c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 4247c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 4248c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 4249c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 4250c4837394SDouglas Gilbert num_aborts); 4251c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 4252c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 4253c4837394SDouglas Gilbert num_host_resets); 4254c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 4255c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 4256c4837394SDouglas Gilbert seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", 4257c4837394SDouglas Gilbert TICK_NSEC / 1000, "statistics", sdebug_statistics, 4258c4837394SDouglas Gilbert sdebug_mq_active); 4259c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 4260c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 4261c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 4262c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 4263c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 4264cbf67842SDouglas Gilbert 4265c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 4266c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4267c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 4268c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 4269773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4270c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 4271c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 4272c4837394SDouglas Gilbert "first,last bits", f, l); 4273c4837394SDouglas Gilbert } 4274cbf67842SDouglas Gilbert } 4275c8ed555aSAl Viro return 0; 42761da177e4SLinus Torvalds } 42771da177e4SLinus Torvalds 427882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 42791da177e4SLinus Torvalds { 4280c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 42811da177e4SLinus Torvalds } 4282c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 4283c4837394SDouglas Gilbert * of delay is jiffies. 4284c4837394SDouglas Gilbert */ 428582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 428682069379SAkinobu Mita size_t count) 42871da177e4SLinus Torvalds { 4288c2206098SDouglas Gilbert int jdelay, res; 42891da177e4SLinus Torvalds 4290b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 4291cbf67842SDouglas Gilbert res = count; 4292c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4293c4837394SDouglas Gilbert int j, k; 4294c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4295cbf67842SDouglas Gilbert 4296c4837394SDouglas Gilbert block_unblock_all_queues(true); 4297c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4298c4837394SDouglas Gilbert ++j, ++sqp) { 4299c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4300c4837394SDouglas Gilbert sdebug_max_queue); 4301c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4302c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4303c4837394SDouglas Gilbert break; 4304c4837394SDouglas Gilbert } 4305c4837394SDouglas Gilbert } 4306c4837394SDouglas Gilbert if (res > 0) { 4307a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4308a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4309a10bc12aSDouglas Gilbert free_all_queued(); 4310c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4311773642d9SDouglas Gilbert sdebug_ndelay = 0; 43121da177e4SLinus Torvalds } 4313c4837394SDouglas Gilbert block_unblock_all_queues(false); 4314cbf67842SDouglas Gilbert } 4315cbf67842SDouglas Gilbert return res; 43161da177e4SLinus Torvalds } 43171da177e4SLinus Torvalds return -EINVAL; 43181da177e4SLinus Torvalds } 431982069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 43201da177e4SLinus Torvalds 4321cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4322cbf67842SDouglas Gilbert { 4323773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4324cbf67842SDouglas Gilbert } 4325cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4326c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4327cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4328cbf67842SDouglas Gilbert size_t count) 4329cbf67842SDouglas Gilbert { 4330c4837394SDouglas Gilbert int ndelay, res; 4331cbf67842SDouglas Gilbert 4332cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4333c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 4334cbf67842SDouglas Gilbert res = count; 4335773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4336c4837394SDouglas Gilbert int j, k; 4337c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4338c4837394SDouglas Gilbert 4339c4837394SDouglas Gilbert block_unblock_all_queues(true); 4340c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4341c4837394SDouglas Gilbert ++j, ++sqp) { 4342c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4343c4837394SDouglas Gilbert sdebug_max_queue); 4344c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4345c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4346c4837394SDouglas Gilbert break; 4347c4837394SDouglas Gilbert } 4348c4837394SDouglas Gilbert } 4349c4837394SDouglas Gilbert if (res > 0) { 4350a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4351a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4352a10bc12aSDouglas Gilbert free_all_queued(); 4353773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4354c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4355c2206098SDouglas Gilbert : DEF_JDELAY; 4356cbf67842SDouglas Gilbert } 4357c4837394SDouglas Gilbert block_unblock_all_queues(false); 4358cbf67842SDouglas Gilbert } 4359cbf67842SDouglas Gilbert return res; 4360cbf67842SDouglas Gilbert } 4361cbf67842SDouglas Gilbert return -EINVAL; 4362cbf67842SDouglas Gilbert } 4363cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4364cbf67842SDouglas Gilbert 436582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 43661da177e4SLinus Torvalds { 4367773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 43681da177e4SLinus Torvalds } 43691da177e4SLinus Torvalds 437082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 437182069379SAkinobu Mita size_t count) 43721da177e4SLinus Torvalds { 43731da177e4SLinus Torvalds int opts; 43741da177e4SLinus Torvalds char work[20]; 43751da177e4SLinus Torvalds 43761da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 437748a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 43781da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 43791da177e4SLinus Torvalds goto opts_done; 43801da177e4SLinus Torvalds } else { 43811da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 43821da177e4SLinus Torvalds goto opts_done; 43831da177e4SLinus Torvalds } 43841da177e4SLinus Torvalds } 43851da177e4SLinus Torvalds return -EINVAL; 43861da177e4SLinus Torvalds opts_done: 4387773642d9SDouglas Gilbert sdebug_opts = opts; 4388773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4389773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4390c4837394SDouglas Gilbert tweak_cmnd_count(); 43911da177e4SLinus Torvalds return count; 43921da177e4SLinus Torvalds } 439382069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 43941da177e4SLinus Torvalds 439582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 43961da177e4SLinus Torvalds { 4397773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 43981da177e4SLinus Torvalds } 439982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 440082069379SAkinobu Mita size_t count) 44011da177e4SLinus Torvalds { 44021da177e4SLinus Torvalds int n; 44031da177e4SLinus Torvalds 44041da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4405773642d9SDouglas Gilbert sdebug_ptype = n; 44061da177e4SLinus Torvalds return count; 44071da177e4SLinus Torvalds } 44081da177e4SLinus Torvalds return -EINVAL; 44091da177e4SLinus Torvalds } 441082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 44111da177e4SLinus Torvalds 441282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 44131da177e4SLinus Torvalds { 4414773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 44151da177e4SLinus Torvalds } 441682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 441782069379SAkinobu Mita size_t count) 44181da177e4SLinus Torvalds { 44191da177e4SLinus Torvalds int n; 44201da177e4SLinus Torvalds 44211da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4422773642d9SDouglas Gilbert sdebug_dsense = n; 44231da177e4SLinus Torvalds return count; 44241da177e4SLinus Torvalds } 44251da177e4SLinus Torvalds return -EINVAL; 44261da177e4SLinus Torvalds } 442782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 44281da177e4SLinus Torvalds 442982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 443023183910SDouglas Gilbert { 4431773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 443223183910SDouglas Gilbert } 443382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 443482069379SAkinobu Mita size_t count) 443523183910SDouglas Gilbert { 443623183910SDouglas Gilbert int n; 443723183910SDouglas Gilbert 443823183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4439cbf67842SDouglas Gilbert n = (n > 0); 4440773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 4441773642d9SDouglas Gilbert if (sdebug_fake_rw != n) { 4442cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4443cbf67842SDouglas Gilbert unsigned long sz = 4444773642d9SDouglas Gilbert (unsigned long)sdebug_dev_size_mb * 4445cbf67842SDouglas Gilbert 1048576; 4446cbf67842SDouglas Gilbert 4447cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4448cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4449c1287970STomas Winkler pr_err("out of memory, 9\n"); 4450cbf67842SDouglas Gilbert return -ENOMEM; 4451cbf67842SDouglas Gilbert } 4452cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4453cbf67842SDouglas Gilbert } 4454773642d9SDouglas Gilbert sdebug_fake_rw = n; 4455cbf67842SDouglas Gilbert } 445623183910SDouglas Gilbert return count; 445723183910SDouglas Gilbert } 445823183910SDouglas Gilbert return -EINVAL; 445923183910SDouglas Gilbert } 446082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 446123183910SDouglas Gilbert 446282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4463c65b1445SDouglas Gilbert { 4464773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 4465c65b1445SDouglas Gilbert } 446682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 446782069379SAkinobu Mita size_t count) 4468c65b1445SDouglas Gilbert { 4469c65b1445SDouglas Gilbert int n; 4470c65b1445SDouglas Gilbert 4471c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4472773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 4473c65b1445SDouglas Gilbert return count; 4474c65b1445SDouglas Gilbert } 4475c65b1445SDouglas Gilbert return -EINVAL; 4476c65b1445SDouglas Gilbert } 447782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4478c65b1445SDouglas Gilbert 447982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 44801da177e4SLinus Torvalds { 4481773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 44821da177e4SLinus Torvalds } 448382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 448482069379SAkinobu Mita size_t count) 44851da177e4SLinus Torvalds { 44861da177e4SLinus Torvalds int n; 44871da177e4SLinus Torvalds 44881da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4489773642d9SDouglas Gilbert sdebug_num_tgts = n; 44901da177e4SLinus Torvalds sdebug_max_tgts_luns(); 44911da177e4SLinus Torvalds return count; 44921da177e4SLinus Torvalds } 44931da177e4SLinus Torvalds return -EINVAL; 44941da177e4SLinus Torvalds } 449582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 44961da177e4SLinus Torvalds 449782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 44981da177e4SLinus Torvalds { 4499773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 45001da177e4SLinus Torvalds } 450182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 45021da177e4SLinus Torvalds 450382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 45041da177e4SLinus Torvalds { 4505773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 45061da177e4SLinus Torvalds } 450782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 45081da177e4SLinus Torvalds 450982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 45101da177e4SLinus Torvalds { 4511773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 45121da177e4SLinus Torvalds } 451382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 451482069379SAkinobu Mita size_t count) 45151da177e4SLinus Torvalds { 45161da177e4SLinus Torvalds int nth; 45171da177e4SLinus Torvalds 45181da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 4519773642d9SDouglas Gilbert sdebug_every_nth = nth; 4520c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 4521c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 4522c4837394SDouglas Gilbert sdebug_statistics = true; 4523c4837394SDouglas Gilbert } 4524c4837394SDouglas Gilbert tweak_cmnd_count(); 45251da177e4SLinus Torvalds return count; 45261da177e4SLinus Torvalds } 45271da177e4SLinus Torvalds return -EINVAL; 45281da177e4SLinus Torvalds } 452982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 45301da177e4SLinus Torvalds 453182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 45321da177e4SLinus Torvalds { 4533773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 45341da177e4SLinus Torvalds } 453582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 453682069379SAkinobu Mita size_t count) 45371da177e4SLinus Torvalds { 45381da177e4SLinus Torvalds int n; 453919c8ead7SEwan D. Milne bool changed; 45401da177e4SLinus Torvalds 45411da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 45428d039e22SDouglas Gilbert if (n > 256) { 45438d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 45448d039e22SDouglas Gilbert return -EINVAL; 45458d039e22SDouglas Gilbert } 4546773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 4547773642d9SDouglas Gilbert sdebug_max_luns = n; 45481da177e4SLinus Torvalds sdebug_max_tgts_luns(); 4549773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 455019c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 455119c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 455219c8ead7SEwan D. Milne 455319c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 455419c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 455519c8ead7SEwan D. Milne host_list) { 455619c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 455719c8ead7SEwan D. Milne dev_list) { 455819c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 455919c8ead7SEwan D. Milne dp->uas_bm); 456019c8ead7SEwan D. Milne } 456119c8ead7SEwan D. Milne } 456219c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 456319c8ead7SEwan D. Milne } 45641da177e4SLinus Torvalds return count; 45651da177e4SLinus Torvalds } 45661da177e4SLinus Torvalds return -EINVAL; 45671da177e4SLinus Torvalds } 456882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 45691da177e4SLinus Torvalds 457082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 457178d4e5a0SDouglas Gilbert { 4572773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 457378d4e5a0SDouglas Gilbert } 4574cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4575cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 457682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 457782069379SAkinobu Mita size_t count) 457878d4e5a0SDouglas Gilbert { 4579c4837394SDouglas Gilbert int j, n, k, a; 4580c4837394SDouglas Gilbert struct sdebug_queue *sqp; 458178d4e5a0SDouglas Gilbert 458278d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 4583c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 4584c4837394SDouglas Gilbert block_unblock_all_queues(true); 4585c4837394SDouglas Gilbert k = 0; 4586c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4587c4837394SDouglas Gilbert ++j, ++sqp) { 4588c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 4589c4837394SDouglas Gilbert if (a > k) 4590c4837394SDouglas Gilbert k = a; 4591c4837394SDouglas Gilbert } 4592773642d9SDouglas Gilbert sdebug_max_queue = n; 4593c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 4594cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4595cbf67842SDouglas Gilbert else if (k >= n) 4596cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4597cbf67842SDouglas Gilbert else 4598cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4599c4837394SDouglas Gilbert block_unblock_all_queues(false); 460078d4e5a0SDouglas Gilbert return count; 460178d4e5a0SDouglas Gilbert } 460278d4e5a0SDouglas Gilbert return -EINVAL; 460378d4e5a0SDouglas Gilbert } 460482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 460578d4e5a0SDouglas Gilbert 460682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 460778d4e5a0SDouglas Gilbert { 4608773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 460978d4e5a0SDouglas Gilbert } 461082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 461178d4e5a0SDouglas Gilbert 461282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 46131da177e4SLinus Torvalds { 4614773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 46151da177e4SLinus Torvalds } 461682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 46171da177e4SLinus Torvalds 461882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4619c65b1445SDouglas Gilbert { 4620773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 4621c65b1445SDouglas Gilbert } 462282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 462382069379SAkinobu Mita size_t count) 4624c65b1445SDouglas Gilbert { 4625c65b1445SDouglas Gilbert int n; 46260d01c5dfSDouglas Gilbert bool changed; 4627c65b1445SDouglas Gilbert 4628c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4629773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 4630773642d9SDouglas Gilbert sdebug_virtual_gb = n; 463128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 46320d01c5dfSDouglas Gilbert if (changed) { 46330d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 46340d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 463528898873SFUJITA Tomonori 46364bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 46370d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 46380d01c5dfSDouglas Gilbert host_list) { 46390d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 46400d01c5dfSDouglas Gilbert dev_list) { 46410d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 46420d01c5dfSDouglas Gilbert dp->uas_bm); 46430d01c5dfSDouglas Gilbert } 46440d01c5dfSDouglas Gilbert } 46454bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 46460d01c5dfSDouglas Gilbert } 4647c65b1445SDouglas Gilbert return count; 4648c65b1445SDouglas Gilbert } 4649c65b1445SDouglas Gilbert return -EINVAL; 4650c65b1445SDouglas Gilbert } 465182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4652c65b1445SDouglas Gilbert 465382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 46541da177e4SLinus Torvalds { 4655773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host); 46561da177e4SLinus Torvalds } 46571da177e4SLinus Torvalds 4658fd32119bSDouglas Gilbert static int sdebug_add_adapter(void); 4659fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void); 4660fd32119bSDouglas Gilbert 466182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 466282069379SAkinobu Mita size_t count) 46631da177e4SLinus Torvalds { 46641da177e4SLinus Torvalds int delta_hosts; 46651da177e4SLinus Torvalds 4666f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 46671da177e4SLinus Torvalds return -EINVAL; 46681da177e4SLinus Torvalds if (delta_hosts > 0) { 46691da177e4SLinus Torvalds do { 46701da177e4SLinus Torvalds sdebug_add_adapter(); 46711da177e4SLinus Torvalds } while (--delta_hosts); 46721da177e4SLinus Torvalds } else if (delta_hosts < 0) { 46731da177e4SLinus Torvalds do { 46741da177e4SLinus Torvalds sdebug_remove_adapter(); 46751da177e4SLinus Torvalds } while (++delta_hosts); 46761da177e4SLinus Torvalds } 46771da177e4SLinus Torvalds return count; 46781da177e4SLinus Torvalds } 467982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 46801da177e4SLinus Torvalds 468182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 468223183910SDouglas Gilbert { 4683773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 468423183910SDouglas Gilbert } 468582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 468682069379SAkinobu Mita size_t count) 468723183910SDouglas Gilbert { 468823183910SDouglas Gilbert int n; 468923183910SDouglas Gilbert 469023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4691773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 469223183910SDouglas Gilbert return count; 469323183910SDouglas Gilbert } 469423183910SDouglas Gilbert return -EINVAL; 469523183910SDouglas Gilbert } 469682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 469723183910SDouglas Gilbert 4698c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 4699c4837394SDouglas Gilbert { 4700c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 4701c4837394SDouglas Gilbert } 4702c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 4703c4837394SDouglas Gilbert size_t count) 4704c4837394SDouglas Gilbert { 4705c4837394SDouglas Gilbert int n; 4706c4837394SDouglas Gilbert 4707c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 4708c4837394SDouglas Gilbert if (n > 0) 4709c4837394SDouglas Gilbert sdebug_statistics = true; 4710c4837394SDouglas Gilbert else { 4711c4837394SDouglas Gilbert clear_queue_stats(); 4712c4837394SDouglas Gilbert sdebug_statistics = false; 4713c4837394SDouglas Gilbert } 4714c4837394SDouglas Gilbert return count; 4715c4837394SDouglas Gilbert } 4716c4837394SDouglas Gilbert return -EINVAL; 4717c4837394SDouglas Gilbert } 4718c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 4719c4837394SDouglas Gilbert 472082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4721597136abSMartin K. Petersen { 4722773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 4723597136abSMartin K. Petersen } 472482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4725597136abSMartin K. Petersen 4726c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 4727c4837394SDouglas Gilbert { 4728c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 4729c4837394SDouglas Gilbert } 4730c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 4731c4837394SDouglas Gilbert 473282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4733c6a44287SMartin K. Petersen { 4734773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 4735c6a44287SMartin K. Petersen } 473682069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4737c6a44287SMartin K. Petersen 473882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4739c6a44287SMartin K. Petersen { 4740773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 4741c6a44287SMartin K. Petersen } 474282069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4743c6a44287SMartin K. Petersen 474482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4745c6a44287SMartin K. Petersen { 4746773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 4747c6a44287SMartin K. Petersen } 474882069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4749c6a44287SMartin K. Petersen 475082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4751c6a44287SMartin K. Petersen { 4752773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 4753c6a44287SMartin K. Petersen } 475482069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4755c6a44287SMartin K. Petersen 475682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 475744d92694SMartin K. Petersen { 475844d92694SMartin K. Petersen ssize_t count; 475944d92694SMartin K. Petersen 47605b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 476144d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 476244d92694SMartin K. Petersen sdebug_store_sectors); 476344d92694SMartin K. Petersen 4764c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4765c7badc90STejun Heo (int)map_size, map_storep); 476644d92694SMartin K. Petersen buf[count++] = '\n'; 4767c7badc90STejun Heo buf[count] = '\0'; 476844d92694SMartin K. Petersen 476944d92694SMartin K. Petersen return count; 477044d92694SMartin K. Petersen } 477182069379SAkinobu Mita static DRIVER_ATTR_RO(map); 477244d92694SMartin K. Petersen 477382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4774d986788bSMartin Pitt { 4775773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 4776d986788bSMartin Pitt } 477782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 477882069379SAkinobu Mita size_t count) 4779d986788bSMartin Pitt { 4780d986788bSMartin Pitt int n; 4781d986788bSMartin Pitt 4782d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4783773642d9SDouglas Gilbert sdebug_removable = (n > 0); 4784d986788bSMartin Pitt return count; 4785d986788bSMartin Pitt } 4786d986788bSMartin Pitt return -EINVAL; 4787d986788bSMartin Pitt } 478882069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4789d986788bSMartin Pitt 4790cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4791cbf67842SDouglas Gilbert { 4792773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 4793cbf67842SDouglas Gilbert } 4794185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 4795cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4796cbf67842SDouglas Gilbert size_t count) 4797cbf67842SDouglas Gilbert { 4798185dd232SDouglas Gilbert int n; 4799cbf67842SDouglas Gilbert 4800cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4801185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 4802185dd232SDouglas Gilbert return count; 4803cbf67842SDouglas Gilbert } 4804cbf67842SDouglas Gilbert return -EINVAL; 4805cbf67842SDouglas Gilbert } 4806cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4807cbf67842SDouglas Gilbert 4808c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4809c2248fc9SDouglas Gilbert { 4810773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 4811c2248fc9SDouglas Gilbert } 4812c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4813c2248fc9SDouglas Gilbert size_t count) 4814c2248fc9SDouglas Gilbert { 4815c2248fc9SDouglas Gilbert int n; 4816c2248fc9SDouglas Gilbert 4817c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4818773642d9SDouglas Gilbert sdebug_strict = (n > 0); 4819c2248fc9SDouglas Gilbert return count; 4820c2248fc9SDouglas Gilbert } 4821c2248fc9SDouglas Gilbert return -EINVAL; 4822c2248fc9SDouglas Gilbert } 4823c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4824c2248fc9SDouglas Gilbert 482509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 482609ba24c1SDouglas Gilbert { 482709ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 482809ba24c1SDouglas Gilbert } 482909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 483009ba24c1SDouglas Gilbert 4831cbf67842SDouglas Gilbert 483282069379SAkinobu Mita /* Note: The following array creates attribute files in the 483323183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 483423183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 483523183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 483623183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 483723183910SDouglas Gilbert */ 48386ecaff7fSRandy Dunlap 483982069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 484082069379SAkinobu Mita &driver_attr_delay.attr, 484182069379SAkinobu Mita &driver_attr_opts.attr, 484282069379SAkinobu Mita &driver_attr_ptype.attr, 484382069379SAkinobu Mita &driver_attr_dsense.attr, 484482069379SAkinobu Mita &driver_attr_fake_rw.attr, 484582069379SAkinobu Mita &driver_attr_no_lun_0.attr, 484682069379SAkinobu Mita &driver_attr_num_tgts.attr, 484782069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 484882069379SAkinobu Mita &driver_attr_num_parts.attr, 484982069379SAkinobu Mita &driver_attr_every_nth.attr, 485082069379SAkinobu Mita &driver_attr_max_luns.attr, 485182069379SAkinobu Mita &driver_attr_max_queue.attr, 485282069379SAkinobu Mita &driver_attr_no_uld.attr, 485382069379SAkinobu Mita &driver_attr_scsi_level.attr, 485482069379SAkinobu Mita &driver_attr_virtual_gb.attr, 485582069379SAkinobu Mita &driver_attr_add_host.attr, 485682069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 485782069379SAkinobu Mita &driver_attr_sector_size.attr, 4858c4837394SDouglas Gilbert &driver_attr_statistics.attr, 4859c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 486082069379SAkinobu Mita &driver_attr_dix.attr, 486182069379SAkinobu Mita &driver_attr_dif.attr, 486282069379SAkinobu Mita &driver_attr_guard.attr, 486382069379SAkinobu Mita &driver_attr_ato.attr, 486482069379SAkinobu Mita &driver_attr_map.attr, 486582069379SAkinobu Mita &driver_attr_removable.attr, 4866cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4867cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4868c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 486909ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 487082069379SAkinobu Mita NULL, 487182069379SAkinobu Mita }; 487282069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 48731da177e4SLinus Torvalds 487411ddcecaSAkinobu Mita static struct device *pseudo_primary; 48758dea0d02SFUJITA Tomonori 48761da177e4SLinus Torvalds static int __init scsi_debug_init(void) 48771da177e4SLinus Torvalds { 48785f2578e5SFUJITA Tomonori unsigned long sz; 48791da177e4SLinus Torvalds int host_to_add; 48801da177e4SLinus Torvalds int k; 48816ecaff7fSRandy Dunlap int ret; 48821da177e4SLinus Torvalds 4883cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4884cbf67842SDouglas Gilbert 4885773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 4886c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 4887773642d9SDouglas Gilbert sdebug_ndelay = 0; 4888773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 4889c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 4890cbf67842SDouglas Gilbert 4891773642d9SDouglas Gilbert switch (sdebug_sector_size) { 4892597136abSMartin K. Petersen case 512: 4893597136abSMartin K. Petersen case 1024: 4894597136abSMartin K. Petersen case 2048: 4895597136abSMartin K. Petersen case 4096: 4896597136abSMartin K. Petersen break; 4897597136abSMartin K. Petersen default: 4898773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 4899597136abSMartin K. Petersen return -EINVAL; 4900597136abSMartin K. Petersen } 4901597136abSMartin K. Petersen 4902773642d9SDouglas Gilbert switch (sdebug_dif) { 4903c6a44287SMartin K. Petersen 4904c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 4905f46eb0e9SDouglas Gilbert break; 4906c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4907395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4908c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4909f46eb0e9SDouglas Gilbert have_dif_prot = true; 4910c6a44287SMartin K. Petersen break; 4911c6a44287SMartin K. Petersen 4912c6a44287SMartin K. Petersen default: 4913c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 4914c6a44287SMartin K. Petersen return -EINVAL; 4915c6a44287SMartin K. Petersen } 4916c6a44287SMartin K. Petersen 4917773642d9SDouglas Gilbert if (sdebug_guard > 1) { 4918c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 4919c6a44287SMartin K. Petersen return -EINVAL; 4920c6a44287SMartin K. Petersen } 4921c6a44287SMartin K. Petersen 4922773642d9SDouglas Gilbert if (sdebug_ato > 1) { 4923c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 4924c6a44287SMartin K. Petersen return -EINVAL; 4925c6a44287SMartin K. Petersen } 4926c6a44287SMartin K. Petersen 4927773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 4928773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 4929ea61fca5SMartin K. Petersen return -EINVAL; 4930ea61fca5SMartin K. Petersen } 49318d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 49328d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 49338d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 49348d039e22SDouglas Gilbert } 4935ea61fca5SMartin K. Petersen 4936773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 4937773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 4938ea61fca5SMartin K. Petersen return -EINVAL; 4939ea61fca5SMartin K. Petersen } 4940ea61fca5SMartin K. Petersen 4941c4837394SDouglas Gilbert if (submit_queues < 1) { 4942c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 4943c4837394SDouglas Gilbert return -EINVAL; 4944c4837394SDouglas Gilbert } 4945c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 4946c4837394SDouglas Gilbert GFP_KERNEL); 4947c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 4948c4837394SDouglas Gilbert return -ENOMEM; 4949c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 4950c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 4951c4837394SDouglas Gilbert 4952773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 4953773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 4954773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 4955773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 495628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 49571da177e4SLinus Torvalds 49581da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 49591da177e4SLinus Torvalds sdebug_heads = 8; 49601da177e4SLinus Torvalds sdebug_sectors_per = 32; 4961773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 49621da177e4SLinus Torvalds sdebug_heads = 64; 4963773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 4964fa785f0aSAndy Shevchenko sdebug_heads = 32; 49651da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 49661da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 49671da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 49681da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 49691da177e4SLinus Torvalds sdebug_heads = 255; 49701da177e4SLinus Torvalds sdebug_sectors_per = 63; 49711da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 49721da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 49731da177e4SLinus Torvalds } 49741da177e4SLinus Torvalds 4975b01f6f83SDouglas Gilbert if (sdebug_fake_rw == 0) { 49761da177e4SLinus Torvalds fake_storep = vmalloc(sz); 49771da177e4SLinus Torvalds if (NULL == fake_storep) { 4978c1287970STomas Winkler pr_err("out of memory, 1\n"); 4979c4837394SDouglas Gilbert ret = -ENOMEM; 4980c4837394SDouglas Gilbert goto free_q_arr; 49811da177e4SLinus Torvalds } 49821da177e4SLinus Torvalds memset(fake_storep, 0, sz); 4983773642d9SDouglas Gilbert if (sdebug_num_parts > 0) 4984f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 4985cbf67842SDouglas Gilbert } 49861da177e4SLinus Torvalds 4987773642d9SDouglas Gilbert if (sdebug_dix) { 4988c6a44287SMartin K. Petersen int dif_size; 4989c6a44287SMartin K. Petersen 4990c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 4991c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 4992c6a44287SMartin K. Petersen 4993c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 4994c6a44287SMartin K. Petersen 4995c6a44287SMartin K. Petersen if (dif_storep == NULL) { 4996c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 4997c6a44287SMartin K. Petersen ret = -ENOMEM; 4998c6a44287SMartin K. Petersen goto free_vm; 4999c6a44287SMartin K. Petersen } 5000c6a44287SMartin K. Petersen 5001c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 5002c6a44287SMartin K. Petersen } 5003c6a44287SMartin K. Petersen 50045b94e232SMartin K. Petersen /* Logical Block Provisioning */ 50055b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 5006773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 5007773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 50086014759cSMartin K. Petersen 5009773642d9SDouglas Gilbert sdebug_unmap_max_desc = 5010773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 50116014759cSMartin K. Petersen 5012773642d9SDouglas Gilbert sdebug_unmap_granularity = 5013773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 50146014759cSMartin K. Petersen 5015773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 5016773642d9SDouglas Gilbert sdebug_unmap_granularity <= 5017773642d9SDouglas Gilbert sdebug_unmap_alignment) { 5018c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 5019c4837394SDouglas Gilbert ret = -EINVAL; 5020c4837394SDouglas Gilbert goto free_vm; 502144d92694SMartin K. Petersen } 502244d92694SMartin K. Petersen 5023b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 5024b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 502544d92694SMartin K. Petersen 5026c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 502744d92694SMartin K. Petersen 502844d92694SMartin K. Petersen if (map_storep == NULL) { 5029c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 503044d92694SMartin K. Petersen ret = -ENOMEM; 503144d92694SMartin K. Petersen goto free_vm; 503244d92694SMartin K. Petersen } 503344d92694SMartin K. Petersen 5034b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 503544d92694SMartin K. Petersen 503644d92694SMartin K. Petersen /* Map first 1KB for partition table */ 5037773642d9SDouglas Gilbert if (sdebug_num_parts) 503844d92694SMartin K. Petersen map_region(0, 2); 503944d92694SMartin K. Petersen } 504044d92694SMartin K. Petersen 50419b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 50429b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 5043c1287970STomas Winkler pr_warn("root_device_register() error\n"); 50449b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 50456ecaff7fSRandy Dunlap goto free_vm; 50466ecaff7fSRandy Dunlap } 50476ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 50486ecaff7fSRandy Dunlap if (ret < 0) { 5049c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 50506ecaff7fSRandy Dunlap goto dev_unreg; 50516ecaff7fSRandy Dunlap } 50526ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 50536ecaff7fSRandy Dunlap if (ret < 0) { 5054c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 50556ecaff7fSRandy Dunlap goto bus_unreg; 50566ecaff7fSRandy Dunlap } 50571da177e4SLinus Torvalds 5058773642d9SDouglas Gilbert host_to_add = sdebug_add_host; 5059773642d9SDouglas Gilbert sdebug_add_host = 0; 50601da177e4SLinus Torvalds 50611da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 50621da177e4SLinus Torvalds if (sdebug_add_adapter()) { 5063c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 50641da177e4SLinus Torvalds break; 50651da177e4SLinus Torvalds } 50661da177e4SLinus Torvalds } 50671da177e4SLinus Torvalds 5068773642d9SDouglas Gilbert if (sdebug_verbose) 5069773642d9SDouglas Gilbert pr_info("built %d host(s)\n", sdebug_add_host); 5070c1287970STomas Winkler 50711da177e4SLinus Torvalds return 0; 50726ecaff7fSRandy Dunlap 50736ecaff7fSRandy Dunlap bus_unreg: 50746ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 50756ecaff7fSRandy Dunlap dev_unreg: 50769b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 50776ecaff7fSRandy Dunlap free_vm: 507844d92694SMartin K. Petersen vfree(map_storep); 5079c6a44287SMartin K. Petersen vfree(dif_storep); 50806ecaff7fSRandy Dunlap vfree(fake_storep); 5081c4837394SDouglas Gilbert free_q_arr: 5082c4837394SDouglas Gilbert kfree(sdebug_q_arr); 50836ecaff7fSRandy Dunlap return ret; 50841da177e4SLinus Torvalds } 50851da177e4SLinus Torvalds 50861da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 50871da177e4SLinus Torvalds { 5088773642d9SDouglas Gilbert int k = sdebug_add_host; 50891da177e4SLinus Torvalds 50901da177e4SLinus Torvalds stop_all_queued(); 5091cbf67842SDouglas Gilbert free_all_queued(); 50921da177e4SLinus Torvalds for (; k; k--) 50931da177e4SLinus Torvalds sdebug_remove_adapter(); 50941da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 50951da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 50969b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 50971da177e4SLinus Torvalds 5098c6a44287SMartin K. Petersen vfree(dif_storep); 50991da177e4SLinus Torvalds vfree(fake_storep); 5100c4837394SDouglas Gilbert kfree(sdebug_q_arr); 51011da177e4SLinus Torvalds } 51021da177e4SLinus Torvalds 51031da177e4SLinus Torvalds device_initcall(scsi_debug_init); 51041da177e4SLinus Torvalds module_exit(scsi_debug_exit); 51051da177e4SLinus Torvalds 51061da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 51071da177e4SLinus Torvalds { 51081da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51091da177e4SLinus Torvalds 51101da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 51111da177e4SLinus Torvalds kfree(sdbg_host); 51121da177e4SLinus Torvalds } 51131da177e4SLinus Torvalds 51141da177e4SLinus Torvalds static int sdebug_add_adapter(void) 51151da177e4SLinus Torvalds { 51161da177e4SLinus Torvalds int k, devs_per_host; 51171da177e4SLinus Torvalds int error = 0; 51181da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51198b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 51201da177e4SLinus Torvalds 512124669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 51221da177e4SLinus Torvalds if (NULL == sdbg_host) { 5123c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51241da177e4SLinus Torvalds return -ENOMEM; 51251da177e4SLinus Torvalds } 51261da177e4SLinus Torvalds 51271da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 51281da177e4SLinus Torvalds 5129773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 51301da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 51315cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 51325cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 5133c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51341da177e4SLinus Torvalds error = -ENOMEM; 51351da177e4SLinus Torvalds goto clean; 51361da177e4SLinus Torvalds } 51371da177e4SLinus Torvalds } 51381da177e4SLinus Torvalds 51391da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51401da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 51411da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51421da177e4SLinus Torvalds 51431da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 51449b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 51451da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 5146773642d9SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host); 51471da177e4SLinus Torvalds 51481da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 51491da177e4SLinus Torvalds 51501da177e4SLinus Torvalds if (error) 51511da177e4SLinus Torvalds goto clean; 51521da177e4SLinus Torvalds 5153773642d9SDouglas Gilbert ++sdebug_add_host; 51541da177e4SLinus Torvalds return error; 51551da177e4SLinus Torvalds 51561da177e4SLinus Torvalds clean: 51578b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 51588b40228fSFUJITA Tomonori dev_list) { 51591da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 51601da177e4SLinus Torvalds kfree(sdbg_devinfo); 51611da177e4SLinus Torvalds } 51621da177e4SLinus Torvalds 51631da177e4SLinus Torvalds kfree(sdbg_host); 51641da177e4SLinus Torvalds return error; 51651da177e4SLinus Torvalds } 51661da177e4SLinus Torvalds 51671da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 51681da177e4SLinus Torvalds { 51691da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 51701da177e4SLinus Torvalds 51711da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51721da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 51731da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 51741da177e4SLinus Torvalds struct sdebug_host_info, host_list); 51751da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 51761da177e4SLinus Torvalds } 51771da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51781da177e4SLinus Torvalds 51791da177e4SLinus Torvalds if (!sdbg_host) 51801da177e4SLinus Torvalds return; 51811da177e4SLinus Torvalds 51821da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 5183773642d9SDouglas Gilbert --sdebug_add_host; 51841da177e4SLinus Torvalds } 51851da177e4SLinus Torvalds 5186fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 5187cbf67842SDouglas Gilbert { 5188cbf67842SDouglas Gilbert int num_in_q = 0; 5189cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5190cbf67842SDouglas Gilbert 5191c4837394SDouglas Gilbert block_unblock_all_queues(true); 5192cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 5193cbf67842SDouglas Gilbert if (NULL == devip) { 5194c4837394SDouglas Gilbert block_unblock_all_queues(false); 5195cbf67842SDouglas Gilbert return -ENODEV; 5196cbf67842SDouglas Gilbert } 5197cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5198c40ecc12SChristoph Hellwig 5199cbf67842SDouglas Gilbert if (qdepth < 1) 5200cbf67842SDouglas Gilbert qdepth = 1; 5201c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 5202c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 5203c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 5204db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 5205cbf67842SDouglas Gilbert 5206773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 5207c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 5208c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 5209cbf67842SDouglas Gilbert } 5210c4837394SDouglas Gilbert block_unblock_all_queues(false); 5211cbf67842SDouglas Gilbert return sdev->queue_depth; 5212cbf67842SDouglas Gilbert } 5213cbf67842SDouglas Gilbert 5214c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 5215817fd66bSDouglas Gilbert { 5216c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 5217773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 5218773642d9SDouglas Gilbert sdebug_every_nth = -1; 5219773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 5220c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 5221773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 5222817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5223c4837394SDouglas Gilbert return true; /* time out reads and writes */ 5224817fd66bSDouglas Gilbert } 5225c4837394SDouglas Gilbert return false; 5226817fd66bSDouglas Gilbert } 5227817fd66bSDouglas Gilbert 5228fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 5229fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 5230c2248fc9SDouglas Gilbert { 5231c2248fc9SDouglas Gilbert u8 sdeb_i; 5232c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5233c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5234c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5235c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5236c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5237c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5238c2248fc9SDouglas Gilbert int k, na; 5239c2248fc9SDouglas Gilbert int errsts = 0; 5240c2248fc9SDouglas Gilbert u32 flags; 5241c2248fc9SDouglas Gilbert u16 sa; 5242c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5243c2248fc9SDouglas Gilbert bool has_wlun_rl; 5244c2248fc9SDouglas Gilbert 5245c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5246c4837394SDouglas Gilbert if (sdebug_statistics) 5247c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 5248f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 5249f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 5250c2248fc9SDouglas Gilbert char b[120]; 5251c2248fc9SDouglas Gilbert int n, len, sb; 5252c2248fc9SDouglas Gilbert 5253c2248fc9SDouglas Gilbert len = scp->cmd_len; 5254c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5255c2248fc9SDouglas Gilbert if (len > 32) 5256c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5257c2248fc9SDouglas Gilbert else { 5258c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5259c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5260c2248fc9SDouglas Gilbert (u32)cmd[k]); 5261c2248fc9SDouglas Gilbert } 5262c4837394SDouglas Gilbert if (sdebug_mq_active) 5263c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", 5264c4837394SDouglas Gilbert my_name, blk_mq_unique_tag(scp->request), 5265c4837394SDouglas Gilbert b); 5266c4837394SDouglas Gilbert else 5267c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, 5268c4837394SDouglas Gilbert b); 5269c2248fc9SDouglas Gilbert } 527034d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 5271f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 5272f46eb0e9SDouglas Gilbert goto err_out; 5273c2248fc9SDouglas Gilbert 5274c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5275c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5276c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5277f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 5278f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5279c2248fc9SDouglas Gilbert if (NULL == devip) 5280f46eb0e9SDouglas Gilbert goto err_out; 5281c2248fc9SDouglas Gilbert } 5282c2248fc9SDouglas Gilbert na = oip->num_attached; 5283c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5284c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5285c2248fc9SDouglas Gilbert r_oip = oip; 5286c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5287c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5288c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5289c2248fc9SDouglas Gilbert else 5290c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5291c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5292c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5293c2248fc9SDouglas Gilbert break; 5294c2248fc9SDouglas Gilbert } 5295c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5296c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5297c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5298c2248fc9SDouglas Gilbert break; 5299c2248fc9SDouglas Gilbert } 5300c2248fc9SDouglas Gilbert } 5301c2248fc9SDouglas Gilbert if (k > na) { 5302c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5303c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5304c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5305c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5306c2248fc9SDouglas Gilbert else 5307c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5308c2248fc9SDouglas Gilbert goto check_cond; 5309c2248fc9SDouglas Gilbert } 5310c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5311c2248fc9SDouglas Gilbert flags = oip->flags; 5312f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 5313c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5314c2248fc9SDouglas Gilbert goto check_cond; 5315c2248fc9SDouglas Gilbert } 5316f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 5317773642d9SDouglas Gilbert if (sdebug_verbose) 5318773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 5319773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 5320c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5321c2248fc9SDouglas Gilbert goto check_cond; 5322c2248fc9SDouglas Gilbert } 5323f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 5324c2248fc9SDouglas Gilbert u8 rem; 5325c2248fc9SDouglas Gilbert int j; 5326c2248fc9SDouglas Gilbert 5327c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5328c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5329c2248fc9SDouglas Gilbert if (rem) { 5330c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5331c2248fc9SDouglas Gilbert if (0x80 & rem) 5332c2248fc9SDouglas Gilbert break; 5333c2248fc9SDouglas Gilbert } 5334c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5335c2248fc9SDouglas Gilbert goto check_cond; 5336c2248fc9SDouglas Gilbert } 5337c2248fc9SDouglas Gilbert } 5338c2248fc9SDouglas Gilbert } 5339f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 5340b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 5341b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 5342f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 5343c2248fc9SDouglas Gilbert if (errsts) 5344c2248fc9SDouglas Gilbert goto check_cond; 5345c2248fc9SDouglas Gilbert } 5346c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 5347c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5348773642d9SDouglas Gilbert if (sdebug_verbose) 5349c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5350c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5351c2248fc9SDouglas Gilbert "required"); 5352c2248fc9SDouglas Gilbert errsts = check_condition_result; 5353c2248fc9SDouglas Gilbert goto fini; 5354c2248fc9SDouglas Gilbert } 5355773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 5356c2248fc9SDouglas Gilbert goto fini; 5357f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 5358c4837394SDouglas Gilbert if (fake_timeout(scp)) 5359c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5360c2248fc9SDouglas Gilbert } 5361f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 5362f46eb0e9SDouglas Gilbert errsts = oip->pfp(scp, devip); /* calls a resp_* function */ 5363c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5364c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5365c2248fc9SDouglas Gilbert 5366c2248fc9SDouglas Gilbert fini: 5367c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5368c2206098SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay)); 5369c2248fc9SDouglas Gilbert check_cond: 5370c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5371f46eb0e9SDouglas Gilbert err_out: 5372f46eb0e9SDouglas Gilbert return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0); 5373c2248fc9SDouglas Gilbert } 5374c2248fc9SDouglas Gilbert 53759e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5376c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5377c8ed555aSAl Viro .write_info = scsi_debug_write_info, 53789e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 53799e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 53809e603ca0SFUJITA Tomonori .info = scsi_debug_info, 53819e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 53829e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 53839e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 53849e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5385185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 5386cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 53879e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 53889e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5389cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5390cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 53919e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 5392c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 53939e603ca0SFUJITA Tomonori .this_id = 7, 539465e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 5395cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 53966bb5e6e7SAkinobu Mita .max_sectors = -1U, 53979e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 53989e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5399c40ecc12SChristoph Hellwig .track_queue_depth = 1, 54009e603ca0SFUJITA Tomonori }; 54019e603ca0SFUJITA Tomonori 54021da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 54031da177e4SLinus Torvalds { 54041da177e4SLinus Torvalds int error = 0; 54051da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 54061da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5407f46eb0e9SDouglas Gilbert int hprot; 54081da177e4SLinus Torvalds 54091da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 54101da177e4SLinus Torvalds 5411773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 5412773642d9SDouglas Gilbert if (sdebug_clustering) 54130759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 54141da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 54151da177e4SLinus Torvalds if (NULL == hpnt) { 5416c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 54171da177e4SLinus Torvalds error = -ENODEV; 54181da177e4SLinus Torvalds return error; 54191da177e4SLinus Torvalds } 5420c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 5421c4837394SDouglas Gilbert pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%d\n", 5422c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 5423c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 5424c4837394SDouglas Gilbert } 5425c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 5426c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 5427c4837394SDouglas Gilbert sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); 5428c4837394SDouglas Gilbert if (sdebug_mq_active) 5429c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 54301da177e4SLinus Torvalds 54311da177e4SLinus Torvalds sdbg_host->shost = hpnt; 54321da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 5433773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 5434773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 54351da177e4SLinus Torvalds else 5436773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 5437773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 5438f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 54391da177e4SLinus Torvalds 5440f46eb0e9SDouglas Gilbert hprot = 0; 5441c6a44287SMartin K. Petersen 5442773642d9SDouglas Gilbert switch (sdebug_dif) { 5443c6a44287SMartin K. Petersen 5444c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 5445f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 5446773642d9SDouglas Gilbert if (sdebug_dix) 5447f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 5448c6a44287SMartin K. Petersen break; 5449c6a44287SMartin K. Petersen 5450c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 5451f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 5452773642d9SDouglas Gilbert if (sdebug_dix) 5453f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 5454c6a44287SMartin K. Petersen break; 5455c6a44287SMartin K. Petersen 5456c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 5457f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 5458773642d9SDouglas Gilbert if (sdebug_dix) 5459f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 5460c6a44287SMartin K. Petersen break; 5461c6a44287SMartin K. Petersen 5462c6a44287SMartin K. Petersen default: 5463773642d9SDouglas Gilbert if (sdebug_dix) 5464f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 5465c6a44287SMartin K. Petersen break; 5466c6a44287SMartin K. Petersen } 5467c6a44287SMartin K. Petersen 5468f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 5469c6a44287SMartin K. Petersen 5470f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 5471c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5472f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5473f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5474f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5475f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5476f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5477f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5478f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5479c6a44287SMartin K. Petersen 5480773642d9SDouglas Gilbert if (sdebug_guard == 1) 5481c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5482c6a44287SMartin K. Petersen else 5483c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5484c6a44287SMartin K. Petersen 5485773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 5486773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 5487c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 5488c4837394SDouglas Gilbert sdebug_statistics = true; 54891da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 54901da177e4SLinus Torvalds if (error) { 5491c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 54921da177e4SLinus Torvalds error = -ENODEV; 54931da177e4SLinus Torvalds scsi_host_put(hpnt); 54941da177e4SLinus Torvalds } else 54951da177e4SLinus Torvalds scsi_scan_host(hpnt); 54961da177e4SLinus Torvalds 54971da177e4SLinus Torvalds return error; 54981da177e4SLinus Torvalds } 54991da177e4SLinus Torvalds 55001da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 55011da177e4SLinus Torvalds { 55021da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 55038b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 55041da177e4SLinus Torvalds 55051da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 55061da177e4SLinus Torvalds 55071da177e4SLinus Torvalds if (!sdbg_host) { 5508c1287970STomas Winkler pr_err("Unable to locate host info\n"); 55091da177e4SLinus Torvalds return -ENODEV; 55101da177e4SLinus Torvalds } 55111da177e4SLinus Torvalds 55121da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 55131da177e4SLinus Torvalds 55148b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 55158b40228fSFUJITA Tomonori dev_list) { 55161da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 55171da177e4SLinus Torvalds kfree(sdbg_devinfo); 55181da177e4SLinus Torvalds } 55191da177e4SLinus Torvalds 55201da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 55211da177e4SLinus Torvalds return 0; 55221da177e4SLinus Torvalds } 55231da177e4SLinus Torvalds 55248dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 55258dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 55261da177e4SLinus Torvalds { 55278dea0d02SFUJITA Tomonori return 1; 55288dea0d02SFUJITA Tomonori } 55291da177e4SLinus Torvalds 55308dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 55318dea0d02SFUJITA Tomonori .name = "pseudo", 55328dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 55338dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 55348dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 553582069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 55368dea0d02SFUJITA Tomonori }; 5537