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> 44c6a44287SMartin K. Petersen 45c6a44287SMartin K. Petersen #include <net/checksum.h> 469ff26eefSFUJITA Tomonori 4744d92694SMartin K. Petersen #include <asm/unaligned.h> 4844d92694SMartin K. Petersen 499ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 509ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 519ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 521da177e4SLinus Torvalds #include <scsi/scsi_host.h> 531da177e4SLinus Torvalds #include <scsi/scsicam.h> 54a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 55cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 56395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 571da177e4SLinus Torvalds 58c6a44287SMartin K. Petersen #include "sd.h" 591da177e4SLinus Torvalds #include "scsi_logging.h" 601da177e4SLinus Torvalds 61773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 62773642d9SDouglas Gilbert #define SCSI_DEBUG_VERSION "1.86" 63773642d9SDouglas Gilbert static const char *sdebug_version_date = "20160422"; 64cbf67842SDouglas Gilbert 65cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 661da177e4SLinus Torvalds 676f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 68c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 69c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 70c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 711da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 72c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 731da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7422017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 751da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 76c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 77cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 78cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 7919c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8019c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8122017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8222017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 83cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 84cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 85cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8622017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 871da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 886f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 89c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 90c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9122017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 92acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 93acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 941da177e4SLinus Torvalds 956f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 966f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 976f3cbf55SDouglas Gilbert 981da177e4SLinus Torvalds /* Default values for driver parameters */ 991da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1001da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1011da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1021da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1031da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1041da177e4SLinus Torvalds */ 1055b94e232SMartin K. Petersen #define DEF_ATO 1 106c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1071da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1085b94e232SMartin K. Petersen #define DEF_DIF 0 1095b94e232SMartin K. Petersen #define DEF_DIX 0 1105b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1111da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1125b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1135b94e232SMartin K. Petersen #define DEF_GUARD 0 114cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1155b94e232SMartin K. Petersen #define DEF_LBPU 0 1165b94e232SMartin K. Petersen #define DEF_LBPWS 0 1175b94e232SMartin K. Petersen #define DEF_LBPWS10 0 118be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1195b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 120cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1215b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1221da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1231da177e4SLinus Torvalds #define DEF_OPTS 0 12432c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1255b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 1265b94e232SMartin K. Petersen #define DEF_PTYPE 0 127d986788bSMartin Pitt #define DEF_REMOVABLE false 128e46b0344SDouglas Gilbert #define DEF_SCSI_LEVEL 6 /* INQUIRY, byte2 [6->SPC-4] */ 1295b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1305b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1315b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1326014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1336014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1345b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1355b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1365b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 137c2248fc9SDouglas Gilbert #define DEF_STRICT 0 138c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1391da177e4SLinus Torvalds 140773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 141773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 142773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 143773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 144773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 145773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 146773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 147773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 148773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 149773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 150773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 151773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 152773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 153773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 154773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 155773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 156773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 157773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 158773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 159773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 160773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 161773642d9SDouglas Gilbert SDEBUG_OPT_SHORT_TRANSFER) 1621da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 163fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1641da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 165773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1666f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 167773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1681da177e4SLinus Torvalds * 1691da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 170fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1711da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 172773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1736f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 174773642d9SDouglas Gilbert * commands if _DEBUG_OPT_TRANSPORT_ERR is set. 175773642d9SDouglas Gilbert * This will continue on every subsequent command until some other action 176773642d9SDouglas Gilbert * occurs (e.g. the user * writing a new value (other than -1 or 1) to 177773642d9SDouglas Gilbert * every_nth via sysfs). 1781da177e4SLinus Torvalds */ 1791da177e4SLinus Torvalds 180cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 181cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 182cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 183cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 184cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 185cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 186cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1870d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 18819c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 189acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 190acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 191acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 192cbf67842SDouglas Gilbert 193773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 1941da177e4SLinus Torvalds * sector on read commands: */ 1951da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 19632f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 1971da177e4SLinus Torvalds 1981da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 1991da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2001da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2011da177e4SLinus Torvalds 202cbf67842SDouglas Gilbert /* SCSI_DEBUG_CANQUEUE is the maximum number of commands that can be queued 203cbf67842SDouglas Gilbert * (for response) at one time. Can be reduced by max_queue option. Command 204c2206098SDouglas Gilbert * responses are not queued when jdelay=0 and ndelay=0. The per-device 205cbf67842SDouglas Gilbert * DEF_CMD_PER_LUN can be changed via sysfs: 206cbf67842SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth but cannot exceed 207cbf67842SDouglas Gilbert * SCSI_DEBUG_CANQUEUE. */ 208cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE_WORDS 9 /* a WORD is bits in a long */ 209cbf67842SDouglas Gilbert #define SCSI_DEBUG_CANQUEUE (SCSI_DEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 210cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 211cbf67842SDouglas Gilbert 212cbf67842SDouglas Gilbert #if DEF_CMD_PER_LUN > SCSI_DEBUG_CANQUEUE 213cbf67842SDouglas Gilbert #warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE" 214cbf67842SDouglas Gilbert #endif 21578d4e5a0SDouglas Gilbert 216fd32119bSDouglas Gilbert #define F_D_IN 1 217fd32119bSDouglas Gilbert #define F_D_OUT 2 218fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 219fd32119bSDouglas Gilbert #define F_D_UNKN 8 220fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 221fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 222fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 223fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 224fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 225fd32119bSDouglas Gilbert #define F_INV_OP 0x200 226fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 227fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 228fd32119bSDouglas Gilbert 229fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 230fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 231fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 232fd32119bSDouglas Gilbert 233fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 234fd32119bSDouglas Gilbert 235fd32119bSDouglas Gilbert #define SCSI_DEBUG_MAX_CMD_LEN 32 236fd32119bSDouglas Gilbert 237fd32119bSDouglas Gilbert 238fd32119bSDouglas Gilbert struct sdebug_dev_info { 239fd32119bSDouglas Gilbert struct list_head dev_list; 240fd32119bSDouglas Gilbert unsigned int channel; 241fd32119bSDouglas Gilbert unsigned int target; 242fd32119bSDouglas Gilbert u64 lun; 243fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 244fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 245fd32119bSDouglas Gilbert atomic_t num_in_q; 246fd32119bSDouglas Gilbert char stopped; /* TODO: should be atomic */ 247fd32119bSDouglas Gilbert bool used; 248fd32119bSDouglas Gilbert }; 249fd32119bSDouglas Gilbert 250fd32119bSDouglas Gilbert struct sdebug_host_info { 251fd32119bSDouglas Gilbert struct list_head host_list; 252fd32119bSDouglas Gilbert struct Scsi_Host *shost; 253fd32119bSDouglas Gilbert struct device dev; 254fd32119bSDouglas Gilbert struct list_head dev_info_list; 255fd32119bSDouglas Gilbert }; 256fd32119bSDouglas Gilbert 257fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 258fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 259fd32119bSDouglas Gilbert 260fd32119bSDouglas Gilbert struct sdebug_defer { 261fd32119bSDouglas Gilbert struct hrtimer hrt; 262fd32119bSDouglas Gilbert struct execute_work ew; 263fd32119bSDouglas Gilbert int qa_indx; 264fd32119bSDouglas Gilbert }; 265fd32119bSDouglas Gilbert 266fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 267fd32119bSDouglas Gilbert /* in_use flagged by a bit in queued_in_use_bm[] */ 268fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 269fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 270fd32119bSDouglas Gilbert }; 271fd32119bSDouglas Gilbert 272fd32119bSDouglas Gilbert struct sdebug_scmd_extra_t { 273fd32119bSDouglas Gilbert bool inj_recovered; 274fd32119bSDouglas Gilbert bool inj_transport; 275fd32119bSDouglas Gilbert bool inj_dif; 276fd32119bSDouglas Gilbert bool inj_dix; 277fd32119bSDouglas Gilbert bool inj_short; 278fd32119bSDouglas Gilbert }; 279fd32119bSDouglas Gilbert 280fd32119bSDouglas Gilbert struct opcode_info_t { 281fd32119bSDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff 282fd32119bSDouglas Gilbert * for terminating element */ 283fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 284fd32119bSDouglas Gilbert u16 sa; /* service action */ 285fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 286fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 287fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 288fd32119bSDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 289fd32119bSDouglas Gilbert /* ignore cdb bytes after position 15 */ 290fd32119bSDouglas Gilbert }; 291fd32119bSDouglas Gilbert 292fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 293c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 294c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 295c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 296c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 297c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 298c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 299c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 300c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 301c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 302c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 303c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 304c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 305c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 306c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 307c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 308c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 309c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 310c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 311c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 312c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 313c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 314c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 315c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 316c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 317c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 318c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 319c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 320c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 321c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 322c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 323c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 324c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 325c2248fc9SDouglas Gilbert }; 326c2248fc9SDouglas Gilbert 327c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 328c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 329c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 330c2248fc9SDouglas Gilbert 0, 0, 0, 0, 331c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 332c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 333c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 334c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 335c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 336c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 337c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 338c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 339c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 340c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 341c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 342c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 343c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 344c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 345c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 346c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 347fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 348c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 349c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 350c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 351c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 352c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 353c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 354c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 355c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 356c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 357c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 358c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 359c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 360c2248fc9SDouglas Gilbert 0, 0, 0, 0, 361c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 362c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 363c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 364c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 365c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 0, 0, 368c2248fc9SDouglas Gilbert }; 369c2248fc9SDouglas Gilbert 370c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 371c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 372c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 373c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 374c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 375c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 376c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 377c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 378c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 379c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 380c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 381c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 382c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 383c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 38438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 38538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 386c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 387c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 388c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 38938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 390acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 391c2248fc9SDouglas Gilbert 392c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 393c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 394c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 395c2248fc9SDouglas Gilbert }; 396c2248fc9SDouglas Gilbert 397c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 398c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 399c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 400c2248fc9SDouglas Gilbert }; 401c2248fc9SDouglas Gilbert 402c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 403c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 404c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 405c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 406c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 407c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 408c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 409c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 410c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 411c2248fc9SDouglas Gilbert }; 412c2248fc9SDouglas Gilbert 413c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 414c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 415c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 416c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 417c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 418c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 419c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 420c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 421c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 422c2248fc9SDouglas Gilbert }; 423c2248fc9SDouglas Gilbert 424c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 425c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 426c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 427c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 428c2248fc9SDouglas Gilbert }; 429c2248fc9SDouglas Gilbert 430c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 431c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 432c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 433c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 434c2248fc9SDouglas Gilbert }; 435c2248fc9SDouglas Gilbert 436c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 43738d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 438c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 439c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 44038d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 441c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 442c2248fc9SDouglas Gilbert 0, 0} }, 443c2248fc9SDouglas Gilbert }; 444c2248fc9SDouglas Gilbert 445c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 446c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 447c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 448c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 449c2248fc9SDouglas Gilbert }; 450c2248fc9SDouglas Gilbert 451c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 452c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 453c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 454c2248fc9SDouglas Gilbert }; 455c2248fc9SDouglas Gilbert 456c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 457c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 458c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 459c2248fc9SDouglas Gilbert }; 460c2248fc9SDouglas Gilbert 461c2248fc9SDouglas Gilbert 462c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 463c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 464c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 465c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 466c2248fc9SDouglas Gilbert /* 0 */ 467c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 468c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 469c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 470c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 471c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 472c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 473c2248fc9SDouglas Gilbert 0, 0} }, 474c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 475c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 476c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 477c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 478c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 479c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 480c2248fc9SDouglas Gilbert 0} }, 481c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 482c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 483c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 484c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 485c2248fc9SDouglas Gilbert 0, 0, 0} }, 486c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 487c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 488c2248fc9SDouglas Gilbert 0, 0} }, 489c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 490c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 491c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 492c2248fc9SDouglas Gilbert /* 10 */ 493c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 494c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 495c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 496c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 497c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 498c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 499c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 500c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 501c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 502c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 503c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 504c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 505c2248fc9SDouglas Gilbert 0} }, 506c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 507c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 508f7f9f26bSDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ 509f7f9f26bSDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 510f7f9f26bSDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 511c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 512c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 513c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 514c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 515c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 516c2248fc9SDouglas Gilbert 0} }, 517c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 518c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 519c2248fc9SDouglas Gilbert 0} }, 520c2248fc9SDouglas Gilbert /* 20 */ 521f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 522f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 523c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 524c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 525c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 526c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 527c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 528c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 529c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 530c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 531c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 532c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 533c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 534acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 535acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 536acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 537c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 538c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 539c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 540c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 541c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 542c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 54338d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 544c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 545c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 546c2248fc9SDouglas Gilbert 547c2248fc9SDouglas Gilbert /* 30 */ 548c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 549c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 550c2248fc9SDouglas Gilbert }; 551c2248fc9SDouglas Gilbert 552773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; 553773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 554c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 555773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 556773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 557773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 558773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 559773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 560773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 561773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 562773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 563773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 564773642d9SDouglas Gilbert static int sdebug_max_queue = SCSI_DEBUG_CANQUEUE; 565cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 566c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 567773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 568773642d9SDouglas Gilbert static int sdebug_no_uld; 569773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 570773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 571773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 572773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 573773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 574773642d9SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */ 575773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 576773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 577773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 578773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 579773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 580773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 581773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 582773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 583773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 584773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 585773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 586773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 587773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 588773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 589773642d9SDouglas Gilbert static bool sdebug_clustering; 590773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 591773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 592817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 593773642d9SDouglas Gilbert static bool sdebug_verbose; 594f46eb0e9SDouglas Gilbert static bool have_dif_prot; 5951da177e4SLinus Torvalds 596cbf67842SDouglas Gilbert static atomic_t sdebug_cmnd_count; 597cbf67842SDouglas Gilbert static atomic_t sdebug_completions; 598cbf67842SDouglas Gilbert static atomic_t sdebug_a_tsf; /* counter of 'almost' TSFs */ 5991da177e4SLinus Torvalds 600c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 6011da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 6021da177e4SLinus Torvalds 6031da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 6041da177e4SLinus Torvalds may still need them */ 6051da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 6061da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 6071da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 6101da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds static unsigned char *fake_storep; /* ramdisk storage */ 613e18d8beaSAkinobu Mita static struct sd_dif_tuple *dif_storep; /* protection info */ 61444d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6151da177e4SLinus Torvalds 61644d92694SMartin K. Petersen static unsigned long map_size; 617cbf67842SDouglas Gilbert static int num_aborts; 618cbf67842SDouglas Gilbert static int num_dev_resets; 619cbf67842SDouglas Gilbert static int num_target_resets; 620cbf67842SDouglas Gilbert static int num_bus_resets; 621cbf67842SDouglas Gilbert static int num_host_resets; 622c6a44287SMartin K. Petersen static int dix_writes; 623c6a44287SMartin K. Petersen static int dix_reads; 624c6a44287SMartin K. Petersen static int dif_errors; 6251da177e4SLinus Torvalds 626fd32119bSDouglas Gilbert static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE]; 627fd32119bSDouglas Gilbert static unsigned long queued_in_use_bm[SCSI_DEBUG_CANQUEUE_WORDS]; 628fd32119bSDouglas Gilbert 6291da177e4SLinus Torvalds static DEFINE_SPINLOCK(queued_arr_lock); 6301da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6311da177e4SLinus Torvalds 632cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 633cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6341da177e4SLinus Torvalds 6351da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6381da177e4SLinus Torvalds .name = sdebug_proc_name, 6391da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6401da177e4SLinus Torvalds }; 6411da177e4SLinus Torvalds 6421da177e4SLinus Torvalds static const int check_condition_result = 6431da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6441da177e4SLinus Torvalds 645c6a44287SMartin K. Petersen static const int illegal_condition_result = 646c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 647c6a44287SMartin K. Petersen 648cbf67842SDouglas Gilbert static const int device_qfull_result = 649cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 650cbf67842SDouglas Gilbert 651fd32119bSDouglas Gilbert 652fd32119bSDouglas Gilbert static unsigned int scsi_debug_lbp(void) 653fd32119bSDouglas Gilbert { 654fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 655fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 656fd32119bSDouglas Gilbert } 657c65b1445SDouglas Gilbert 65814faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 65914faa944SAkinobu Mita { 66014faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 66114faa944SAkinobu Mita 662773642d9SDouglas Gilbert return fake_storep + lba * sdebug_sector_size; 66314faa944SAkinobu Mita } 66414faa944SAkinobu Mita 66514faa944SAkinobu Mita static struct sd_dif_tuple *dif_store(sector_t sector) 66614faa944SAkinobu Mita { 66749413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 66814faa944SAkinobu Mita 66914faa944SAkinobu Mita return dif_storep + sector; 67014faa944SAkinobu Mita } 67114faa944SAkinobu Mita 6728dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 6738dea0d02SFUJITA Tomonori { 6748dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 6758dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 6768dea0d02SFUJITA Tomonori 6778dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 6788dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 6798dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 6808dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 681773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 682773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 6838dea0d02SFUJITA Tomonori else 684773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 685773642d9SDouglas Gilbert /* sdebug_max_luns; */ 686f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 6878dea0d02SFUJITA Tomonori } 6888dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 6898dea0d02SFUJITA Tomonori } 6908dea0d02SFUJITA Tomonori 69122017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 69222017ed2SDouglas Gilbert 69322017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 694fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 695fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 69622017ed2SDouglas Gilbert int in_byte, int in_bit) 69722017ed2SDouglas Gilbert { 69822017ed2SDouglas Gilbert unsigned char *sbuff; 69922017ed2SDouglas Gilbert u8 sks[4]; 70022017ed2SDouglas Gilbert int sl, asc; 70122017ed2SDouglas Gilbert 70222017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 70322017ed2SDouglas Gilbert if (!sbuff) { 70422017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 70522017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 70622017ed2SDouglas Gilbert return; 70722017ed2SDouglas Gilbert } 70822017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 70922017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 710773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 71122017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 71222017ed2SDouglas Gilbert sks[0] = 0x80; 71322017ed2SDouglas Gilbert if (c_d) 71422017ed2SDouglas Gilbert sks[0] |= 0x40; 71522017ed2SDouglas Gilbert if (in_bit >= 0) { 71622017ed2SDouglas Gilbert sks[0] |= 0x8; 71722017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 71822017ed2SDouglas Gilbert } 71922017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 720773642d9SDouglas Gilbert if (sdebug_dsense) { 72122017ed2SDouglas Gilbert sl = sbuff[7] + 8; 72222017ed2SDouglas Gilbert sbuff[7] = sl; 72322017ed2SDouglas Gilbert sbuff[sl] = 0x2; 72422017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 72522017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 72622017ed2SDouglas Gilbert } else 72722017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 728773642d9SDouglas Gilbert if (sdebug_verbose) 72922017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 73022017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 73122017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 73222017ed2SDouglas Gilbert } 73322017ed2SDouglas Gilbert 734cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7358dea0d02SFUJITA Tomonori { 7368dea0d02SFUJITA Tomonori unsigned char *sbuff; 7378dea0d02SFUJITA Tomonori 738cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 739cbf67842SDouglas Gilbert if (!sbuff) { 740cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 741cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 742cbf67842SDouglas Gilbert return; 743cbf67842SDouglas Gilbert } 744cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7458dea0d02SFUJITA Tomonori 746773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 7478dea0d02SFUJITA Tomonori 748773642d9SDouglas Gilbert if (sdebug_verbose) 749cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 750cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 751cbf67842SDouglas Gilbert my_name, key, asc, asq); 7528dea0d02SFUJITA Tomonori } 7531da177e4SLinus Torvalds 754fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 75522017ed2SDouglas Gilbert { 75622017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 75722017ed2SDouglas Gilbert } 75822017ed2SDouglas Gilbert 7591da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7601da177e4SLinus Torvalds { 761773642d9SDouglas Gilbert if (sdebug_verbose) { 762cbf67842SDouglas Gilbert if (0x1261 == cmd) 763cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 764cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 765cbf67842SDouglas Gilbert else if (0x5331 == cmd) 766cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 767cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 768cbf67842SDouglas Gilbert __func__); 769cbf67842SDouglas Gilbert else 770cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 771cbf67842SDouglas Gilbert __func__, cmd); 7721da177e4SLinus Torvalds } 7731da177e4SLinus Torvalds return -EINVAL; 7741da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 7751da177e4SLinus Torvalds } 7761da177e4SLinus Torvalds 77719c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 77819c8ead7SEwan D. Milne { 77919c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 78019c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 78119c8ead7SEwan D. Milne 78219c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 78319c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 78419c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 78519c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 78619c8ead7SEwan D. Milne (devip->target == dp->target)) 78719c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 78819c8ead7SEwan D. Milne } 78919c8ead7SEwan D. Milne } 79019c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 79119c8ead7SEwan D. Milne } 79219c8ead7SEwan D. Milne 793f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 7941da177e4SLinus Torvalds { 795cbf67842SDouglas Gilbert int k; 796cbf67842SDouglas Gilbert 797cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 798cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 799cbf67842SDouglas Gilbert const char *cp = NULL; 800cbf67842SDouglas Gilbert 801cbf67842SDouglas Gilbert switch (k) { 802cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 803f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 804f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 805773642d9SDouglas Gilbert if (sdebug_verbose) 806cbf67842SDouglas Gilbert cp = "power on reset"; 807cbf67842SDouglas Gilbert break; 808cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 809f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 810f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 811773642d9SDouglas Gilbert if (sdebug_verbose) 812cbf67842SDouglas Gilbert cp = "bus reset"; 813cbf67842SDouglas Gilbert break; 814cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 815f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 816f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 817773642d9SDouglas Gilbert if (sdebug_verbose) 818cbf67842SDouglas Gilbert cp = "mode parameters changed"; 819cbf67842SDouglas Gilbert break; 8200d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 821f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 822f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 823773642d9SDouglas Gilbert if (sdebug_verbose) 8240d01c5dfSDouglas Gilbert cp = "capacity data changed"; 825f49accf1SEwan D. Milne break; 826acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 827f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 828acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ); 829773642d9SDouglas Gilbert if (sdebug_verbose) 830acafd0b9SEwan D. Milne cp = "microcode has been changed"; 831acafd0b9SEwan D. Milne break; 832acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 833f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 834acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 835acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 836773642d9SDouglas Gilbert if (sdebug_verbose) 837acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 838acafd0b9SEwan D. Milne break; 83919c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 84019c8ead7SEwan D. Milne /* 84119c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 84219c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 84319c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 84419c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 845773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 84619c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 84719c8ead7SEwan D. Milne */ 848773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 84919c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 850f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 85119c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 85219c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 853773642d9SDouglas Gilbert if (sdebug_verbose) 85419c8ead7SEwan D. Milne cp = "reported luns data has changed"; 85519c8ead7SEwan D. Milne break; 856cbf67842SDouglas Gilbert default: 857773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 858773642d9SDouglas Gilbert if (sdebug_verbose) 859cbf67842SDouglas Gilbert cp = "unknown"; 860cbf67842SDouglas Gilbert break; 861cbf67842SDouglas Gilbert } 862cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 863773642d9SDouglas Gilbert if (sdebug_verbose) 864f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 865cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 866cbf67842SDouglas Gilbert my_name, cp); 8671da177e4SLinus Torvalds return check_condition_result; 8681da177e4SLinus Torvalds } 8691da177e4SLinus Torvalds return 0; 8701da177e4SLinus Torvalds } 8711da177e4SLinus Torvalds 8721da177e4SLinus Torvalds /* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */ 8731da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 8741da177e4SLinus Torvalds int arr_len) 8751da177e4SLinus Torvalds { 87621a61829SFUJITA Tomonori int act_len; 877072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 8781da177e4SLinus Torvalds 879072d0bb3SFUJITA Tomonori if (!sdb->length) 8801da177e4SLinus Torvalds return 0; 881072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 882773642d9SDouglas Gilbert return DID_ERROR << 16; 88321a61829SFUJITA Tomonori 88421a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 88521a61829SFUJITA Tomonori arr, arr_len); 88621a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 88721a61829SFUJITA Tomonori 8881da177e4SLinus Torvalds return 0; 8891da177e4SLinus Torvalds } 8901da177e4SLinus Torvalds 8911da177e4SLinus Torvalds /* Returns number of bytes fetched into 'arr' or -1 if error. */ 8921da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 89321a61829SFUJITA Tomonori int arr_len) 8941da177e4SLinus Torvalds { 89521a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 8961da177e4SLinus Torvalds return 0; 897072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 8981da177e4SLinus Torvalds return -1; 89921a61829SFUJITA Tomonori 90021a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 9011da177e4SLinus Torvalds } 9021da177e4SLinus Torvalds 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds static const char * inq_vendor_id = "Linux "; 9051da177e4SLinus Torvalds static const char * inq_product_id = "scsi_debug "; 906773642d9SDouglas Gilbert static const char *inq_product_rev = "0186"; /* version less '.' */ 907773642d9SDouglas Gilbert static const u64 naa5_comp_a = 0x5222222000000000ULL; 908773642d9SDouglas Gilbert static const u64 naa5_comp_b = 0x5333333000000000ULL; 909773642d9SDouglas Gilbert static const u64 naa5_comp_c = 0x5111111000000000ULL; 9101da177e4SLinus Torvalds 911cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 9125a09e398SHannes Reinecke static int inquiry_evpd_83(unsigned char * arr, int port_group_id, 9135a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 9145a09e398SHannes Reinecke const char * dev_id_str, 915c65b1445SDouglas Gilbert int dev_id_str_len) 9161da177e4SLinus Torvalds { 917c65b1445SDouglas Gilbert int num, port_a; 918c65b1445SDouglas Gilbert char b[32]; 9191da177e4SLinus Torvalds 920c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 9211da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 9221da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 9231da177e4SLinus Torvalds arr[1] = 0x1; 9241da177e4SLinus Torvalds arr[2] = 0x0; 9251da177e4SLinus Torvalds memcpy(&arr[4], inq_vendor_id, 8); 9261da177e4SLinus Torvalds memcpy(&arr[12], inq_product_id, 16); 9271da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 9281da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9291da177e4SLinus Torvalds arr[3] = num; 9301da177e4SLinus Torvalds num += 4; 931c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 932c65b1445SDouglas Gilbert /* NAA-5, Logical unit identifier (binary) */ 933c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 934c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 935c65b1445SDouglas Gilbert arr[num++] = 0x0; 936c65b1445SDouglas Gilbert arr[num++] = 0x8; 937773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_b + dev_id_num, arr + num); 938773642d9SDouglas Gilbert num += 8; 939c65b1445SDouglas Gilbert /* Target relative port number */ 940c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 941c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 942c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 943c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 944c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 945c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 946c65b1445SDouglas Gilbert arr[num++] = 0x0; 947c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 948c65b1445SDouglas Gilbert } 949c65b1445SDouglas Gilbert /* NAA-5, Target port identifier */ 950c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 951c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 952c65b1445SDouglas Gilbert arr[num++] = 0x0; 953c65b1445SDouglas Gilbert arr[num++] = 0x8; 954773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_a, arr + num); 955773642d9SDouglas Gilbert num += 8; 9565a09e398SHannes Reinecke /* NAA-5, Target port group identifier */ 9575a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 9585a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 9595a09e398SHannes Reinecke arr[num++] = 0x0; 9605a09e398SHannes Reinecke arr[num++] = 0x4; 9615a09e398SHannes Reinecke arr[num++] = 0; 9625a09e398SHannes Reinecke arr[num++] = 0; 963773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 964773642d9SDouglas Gilbert num += 2; 965c65b1445SDouglas Gilbert /* NAA-5, Target device identifier */ 966c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 967c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 968c65b1445SDouglas Gilbert arr[num++] = 0x0; 969c65b1445SDouglas Gilbert arr[num++] = 0x8; 970773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + target_dev_id, arr + num); 971773642d9SDouglas Gilbert num += 8; 972c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 973c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 974c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 975c65b1445SDouglas Gilbert arr[num++] = 0x0; 976c65b1445SDouglas Gilbert arr[num++] = 24; 977c65b1445SDouglas Gilbert memcpy(arr + num, "naa.52222220", 12); 978c65b1445SDouglas Gilbert num += 12; 979c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 980c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 981c65b1445SDouglas Gilbert num += 8; 982c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 983c65b1445SDouglas Gilbert num += 4; 984c65b1445SDouglas Gilbert return num; 985c65b1445SDouglas Gilbert } 986c65b1445SDouglas Gilbert 987c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 988c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 989c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 990c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 991c65b1445SDouglas Gilbert }; 992c65b1445SDouglas Gilbert 993cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 994c65b1445SDouglas Gilbert static int inquiry_evpd_84(unsigned char * arr) 995c65b1445SDouglas Gilbert { 996c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 997c65b1445SDouglas Gilbert return sizeof(vpd84_data); 998c65b1445SDouglas Gilbert } 999c65b1445SDouglas Gilbert 1000cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1001c65b1445SDouglas Gilbert static int inquiry_evpd_85(unsigned char * arr) 1002c65b1445SDouglas Gilbert { 1003c65b1445SDouglas Gilbert int num = 0; 1004c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1005c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1006c65b1445SDouglas Gilbert int plen, olen; 1007c65b1445SDouglas Gilbert 1008c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1009c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1010c65b1445SDouglas Gilbert arr[num++] = 0x0; 1011c65b1445SDouglas Gilbert olen = strlen(na1); 1012c65b1445SDouglas Gilbert plen = olen + 1; 1013c65b1445SDouglas Gilbert if (plen % 4) 1014c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1015c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1016c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1017c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1018c65b1445SDouglas Gilbert num += plen; 1019c65b1445SDouglas Gilbert 1020c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1021c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1022c65b1445SDouglas Gilbert arr[num++] = 0x0; 1023c65b1445SDouglas Gilbert olen = strlen(na2); 1024c65b1445SDouglas Gilbert plen = olen + 1; 1025c65b1445SDouglas Gilbert if (plen % 4) 1026c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1027c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1028c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1029c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1030c65b1445SDouglas Gilbert num += plen; 1031c65b1445SDouglas Gilbert 1032c65b1445SDouglas Gilbert return num; 1033c65b1445SDouglas Gilbert } 1034c65b1445SDouglas Gilbert 1035c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1036c65b1445SDouglas Gilbert static int inquiry_evpd_88(unsigned char * arr, int target_dev_id) 1037c65b1445SDouglas Gilbert { 1038c65b1445SDouglas Gilbert int num = 0; 1039c65b1445SDouglas Gilbert int port_a, port_b; 1040c65b1445SDouglas Gilbert 1041c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1042c65b1445SDouglas Gilbert port_b = port_a + 1; 1043c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1044c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1045c65b1445SDouglas Gilbert arr[num++] = 0x0; 1046c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1047c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1048c65b1445SDouglas Gilbert num += 6; 1049c65b1445SDouglas Gilbert arr[num++] = 0x0; 1050c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1051c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1052c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1053c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1054c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1055c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1056773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_a, arr + num); 1057773642d9SDouglas Gilbert num += 8; 1058c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1059c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1060c65b1445SDouglas Gilbert arr[num++] = 0x0; 1061c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1062c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1063c65b1445SDouglas Gilbert num += 6; 1064c65b1445SDouglas Gilbert arr[num++] = 0x0; 1065c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1066c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1067c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1068c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1069c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1070c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 1071773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a + port_b, arr + num); 1072773642d9SDouglas Gilbert num += 8; 1073c65b1445SDouglas Gilbert 1074c65b1445SDouglas Gilbert return num; 1075c65b1445SDouglas Gilbert } 1076c65b1445SDouglas Gilbert 1077c65b1445SDouglas Gilbert 1078c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1079c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1080c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1081c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1082c65b1445SDouglas Gilbert '1','2','3','4', 1083c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1084c65b1445SDouglas Gilbert 0xec,0,0,0, 1085c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1086c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1087c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1088c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1089c65b1445SDouglas Gilbert 0x53,0x41, 1090c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1091c65b1445SDouglas Gilbert 0x20,0x20, 1092c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1093c65b1445SDouglas Gilbert 0x10,0x80, 1094c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1095c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1096c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1097c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1098c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1099c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1100c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1101c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1102c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1103c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1104c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1105c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1106c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1107c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1108c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1109c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1110c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1111c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1112c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1113c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1114c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1115c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1116c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1117c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1118c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1119c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1120c65b1445SDouglas Gilbert }; 1121c65b1445SDouglas Gilbert 1122cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1123c65b1445SDouglas Gilbert static int inquiry_evpd_89(unsigned char * arr) 1124c65b1445SDouglas Gilbert { 1125c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1126c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1127c65b1445SDouglas Gilbert } 1128c65b1445SDouglas Gilbert 1129c65b1445SDouglas Gilbert 1130c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11311e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 11321e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11331e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11341e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1135c65b1445SDouglas Gilbert }; 1136c65b1445SDouglas Gilbert 1137cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1138c65b1445SDouglas Gilbert static int inquiry_evpd_b0(unsigned char * arr) 1139c65b1445SDouglas Gilbert { 1140ea61fca5SMartin K. Petersen unsigned int gran; 1141ea61fca5SMartin K. Petersen 1142c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1143e308b3d1SMartin K. Petersen 1144e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 1145773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1146773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1147e308b3d1SMartin K. Petersen 1148e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1149773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1150773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 115144d92694SMartin K. Petersen 1152e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1153773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1154e308b3d1SMartin K. Petersen 1155773642d9SDouglas Gilbert if (sdebug_lbpu) { 1156e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1157773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1158e308b3d1SMartin K. Petersen 1159e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1160773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 116144d92694SMartin K. Petersen } 116244d92694SMartin K. Petersen 1163e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1164773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1165773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 116644d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 116744d92694SMartin K. Petersen } 116844d92694SMartin K. Petersen 1169e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1170773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 11716014759cSMartin K. Petersen 11725b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1173773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 11745b94e232SMartin K. Petersen 11755b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 117644d92694SMartin K. Petersen 1177c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds 11801e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1181eac6e8e4SMatthew Wilcox static int inquiry_evpd_b1(unsigned char *arr) 1182eac6e8e4SMatthew Wilcox { 1183eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1184eac6e8e4SMatthew Wilcox arr[0] = 0; 11851e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 11861e49f785SDouglas Gilbert arr[2] = 0; 11871e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1188eac6e8e4SMatthew Wilcox 1189eac6e8e4SMatthew Wilcox return 0x3c; 1190eac6e8e4SMatthew Wilcox } 11911da177e4SLinus Torvalds 1192be1dd78dSEric Sandeen /* Logical block provisioning VPD page (SBC-3) */ 11936014759cSMartin K. Petersen static int inquiry_evpd_b2(unsigned char *arr) 11946014759cSMartin K. Petersen { 11953f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 11966014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 11976014759cSMartin K. Petersen 1198773642d9SDouglas Gilbert if (sdebug_lbpu) 11996014759cSMartin K. Petersen arr[1] = 1 << 7; 12006014759cSMartin K. Petersen 1201773642d9SDouglas Gilbert if (sdebug_lbpws) 12026014759cSMartin K. Petersen arr[1] |= 1 << 6; 12036014759cSMartin K. Petersen 1204773642d9SDouglas Gilbert if (sdebug_lbpws10) 12055b94e232SMartin K. Petersen arr[1] |= 1 << 5; 12065b94e232SMartin K. Petersen 1207773642d9SDouglas Gilbert if (sdebug_lbprz) 1208be1dd78dSEric Sandeen arr[1] |= 1 << 2; 1209be1dd78dSEric Sandeen 12103f0bc3b3SMartin K. Petersen return 0x4; 12116014759cSMartin K. Petersen } 12126014759cSMartin K. Petersen 12131da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1214c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12151da177e4SLinus Torvalds 1216c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12171da177e4SLinus Torvalds { 12181da177e4SLinus Torvalds unsigned char pq_pdt; 12195a09e398SHannes Reinecke unsigned char * arr; 122001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12215a09e398SHannes Reinecke int alloc_len, n, ret; 1222c2248fc9SDouglas Gilbert bool have_wlun; 12231da177e4SLinus Torvalds 1224773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 12256f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12266f3cbf55SDouglas Gilbert if (! arr) 12276f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 122834d55434STomas Winkler have_wlun = (scp->device->lun == SCSI_W_LUN_REPORT_LUNS); 1229c2248fc9SDouglas Gilbert if (have_wlun) 1230c65b1445SDouglas Gilbert pq_pdt = 0x1e; /* present, wlun */ 1231773642d9SDouglas Gilbert else if (sdebug_no_lun_0 && (0 == devip->lun)) 1232c65b1445SDouglas Gilbert pq_pdt = 0x7f; /* not present, no device type */ 1233c65b1445SDouglas Gilbert else 1234773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 12351da177e4SLinus Torvalds arr[0] = pq_pdt; 12361da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 123722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 12385a09e398SHannes Reinecke kfree(arr); 12391da177e4SLinus Torvalds return check_condition_result; 12401da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 12415a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1242c65b1445SDouglas Gilbert char lu_id_str[6]; 1243c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 12441da177e4SLinus Torvalds 12455a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 12465a09e398SHannes Reinecke (devip->channel & 0x7f); 1247773642d9SDouglas Gilbert if (0 == sdebug_vpd_use_hostno) 124823183910SDouglas Gilbert host_no = 0; 1249c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1250c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1251c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1252c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1253c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 12541da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1255c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1256c65b1445SDouglas Gilbert n = 4; 1257c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1258c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1259c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1260c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1261c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1262c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1263c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1264c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1265c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1266c65b1445SDouglas Gilbert arr[n++] = 0xb0; /* Block limits (SBC) */ 1267eac6e8e4SMatthew Wilcox arr[n++] = 0xb1; /* Block characteristics (SBC) */ 12685b94e232SMartin K. Petersen if (scsi_debug_lbp()) /* Logical Block Prov. (SBC) */ 12695b94e232SMartin K. Petersen arr[n++] = 0xb2; 1270c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 12711da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1272c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 12731da177e4SLinus Torvalds arr[3] = len; 1274c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 12751da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1276c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 12775a09e398SHannes Reinecke arr[3] = inquiry_evpd_83(&arr[4], port_group_id, 12785a09e398SHannes Reinecke target_dev_id, lu_id_num, 12795a09e398SHannes Reinecke lu_id_str, len); 1280c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1281c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1282c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_84(&arr[4]); 1283c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1284c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1285c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_85(&arr[4]); 1286c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1287c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1288c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 1289773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE3_PROTECTION) 1290c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1291773642d9SDouglas Gilbert else if (sdebug_dif) 1292c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1293c6a44287SMartin K. Petersen else 1294c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1295c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1296c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1297c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1298c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1299c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1300c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1301c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1302c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1303c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1304c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1305c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_88(&arr[4], target_dev_id); 1306c65b1445SDouglas Gilbert } else if (0x89 == cmd[2]) { /* ATA information */ 1307c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1308c65b1445SDouglas Gilbert n = inquiry_evpd_89(&arr[4]); 1309773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1310c65b1445SDouglas Gilbert } else if (0xb0 == cmd[2]) { /* Block limits (SBC) */ 1311c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1312c65b1445SDouglas Gilbert arr[3] = inquiry_evpd_b0(&arr[4]); 1313eac6e8e4SMatthew Wilcox } else if (0xb1 == cmd[2]) { /* Block characteristics (SBC) */ 1314eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1315eac6e8e4SMatthew Wilcox arr[3] = inquiry_evpd_b1(&arr[4]); 13165b94e232SMartin K. Petersen } else if (0xb2 == cmd[2]) { /* Logical Block Prov. (SBC) */ 13176014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 13186014759cSMartin K. Petersen arr[3] = inquiry_evpd_b2(&arr[4]); 13191da177e4SLinus Torvalds } else { 132022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13215a09e398SHannes Reinecke kfree(arr); 13221da177e4SLinus Torvalds return check_condition_result; 13231da177e4SLinus Torvalds } 1324773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 13255a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1326c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13275a09e398SHannes Reinecke kfree(arr); 13285a09e398SHannes Reinecke return ret; 13291da177e4SLinus Torvalds } 13301da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1331773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1332773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 13331da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 13341da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1335f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1336773642d9SDouglas Gilbert if (0 == sdebug_vpd_use_hostno) 13375a09e398SHannes Reinecke arr[5] = 0x10; /* claim: implicit TGPS */ 1338c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 13391da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1340c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 13411da177e4SLinus Torvalds memcpy(&arr[8], inq_vendor_id, 8); 13421da177e4SLinus Torvalds memcpy(&arr[16], inq_product_id, 16); 13431da177e4SLinus Torvalds memcpy(&arr[32], inq_product_rev, 4); 13441da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1345e46b0344SDouglas Gilbert arr[58] = 0x0; arr[59] = 0xa2; /* SAM-5 rev 4 */ 1346e46b0344SDouglas Gilbert arr[60] = 0x4; arr[61] = 0x68; /* SPC-4 rev 37 */ 1347c65b1445SDouglas Gilbert n = 62; 1348773642d9SDouglas Gilbert if (sdebug_ptype == 0) { 1349e46b0344SDouglas Gilbert arr[n++] = 0x4; arr[n++] = 0xc5; /* SBC-4 rev 36 */ 1350773642d9SDouglas Gilbert } else if (sdebug_ptype == 1) { 1351e46b0344SDouglas Gilbert arr[n++] = 0x5; arr[n++] = 0x25; /* SSC-4 rev 3 */ 13521da177e4SLinus Torvalds } 1353e46b0344SDouglas Gilbert arr[n++] = 0x20; arr[n++] = 0xe6; /* SPL-3 rev 7 */ 13545a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 13551da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 13565a09e398SHannes Reinecke kfree(arr); 13575a09e398SHannes Reinecke return ret; 13581da177e4SLinus Torvalds } 13591da177e4SLinus Torvalds 1360fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1361fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1362fd32119bSDouglas Gilbert 13631da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 13641da177e4SLinus Torvalds struct sdebug_dev_info * devip) 13651da177e4SLinus Torvalds { 13661da177e4SLinus Torvalds unsigned char * sbuff; 136701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1368cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 13692492fc09STomas Winkler bool dsense; 13701da177e4SLinus Torvalds int len = 18; 13711da177e4SLinus Torvalds 1372c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1373c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1374cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1375c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1376c2248fc9SDouglas Gilbert if (dsense) { 1377c65b1445SDouglas Gilbert arr[0] = 0x72; 1378c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1379c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1380c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1381c2248fc9SDouglas Gilbert len = 8; 1382c65b1445SDouglas Gilbert } else { 1383c65b1445SDouglas Gilbert arr[0] = 0x70; 1384c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1385c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1386c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1387c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1388c65b1445SDouglas Gilbert } 1389c65b1445SDouglas Gilbert } else { 1390cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1391773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1392c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1393c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1394c2248fc9SDouglas Gilbert if (dsense) { 1395c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1396c2248fc9SDouglas Gilbert arr[0] = 0x72; 1397c2248fc9SDouglas Gilbert len = 8; 1398c2248fc9SDouglas Gilbert } else { 1399c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1400c2248fc9SDouglas Gilbert arr[0] = 0x70; 1401c2248fc9SDouglas Gilbert arr[7] = 0xa; 1402c2248fc9SDouglas Gilbert } 1403c2248fc9SDouglas Gilbert } else if (dsense) { 1404c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14051da177e4SLinus Torvalds arr[0] = 0x72; 14061da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14071da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14081da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14091da177e4SLinus Torvalds len = 8; 1410c2248fc9SDouglas Gilbert } else { 1411c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1412c2248fc9SDouglas Gilbert arr[0] = 0x70; 1413c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1414c2248fc9SDouglas Gilbert arr[7] = 0xa; 1415c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1416c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1417c65b1445SDouglas Gilbert } 1418c2248fc9SDouglas Gilbert 1419c65b1445SDouglas Gilbert } 1420cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14211da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14221da177e4SLinus Torvalds } 14231da177e4SLinus Torvalds 1424c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1425c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1426c65b1445SDouglas Gilbert { 142701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1428c2248fc9SDouglas Gilbert int power_cond, start; 1429c65b1445SDouglas Gilbert 1430c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1431c65b1445SDouglas Gilbert if (power_cond) { 143222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1433c65b1445SDouglas Gilbert return check_condition_result; 1434c65b1445SDouglas Gilbert } 1435c65b1445SDouglas Gilbert start = cmd[4] & 1; 1436c65b1445SDouglas Gilbert if (start == devip->stopped) 1437c65b1445SDouglas Gilbert devip->stopped = !start; 1438c65b1445SDouglas Gilbert return 0; 1439c65b1445SDouglas Gilbert } 1440c65b1445SDouglas Gilbert 144128898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 144228898873SFUJITA Tomonori { 1443773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1444773642d9SDouglas Gilbert 1445773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1446773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1447773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 144828898873SFUJITA Tomonori else 144928898873SFUJITA Tomonori return sdebug_store_sectors; 145028898873SFUJITA Tomonori } 145128898873SFUJITA Tomonori 14521da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 14531da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 14541da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14551da177e4SLinus Torvalds { 14561da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1457c65b1445SDouglas Gilbert unsigned int capac; 14581da177e4SLinus Torvalds 1459c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 146028898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 14611da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1462c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1463c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1464773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1465773642d9SDouglas Gilbert } else 1466773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1467773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 14681da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 14691da177e4SLinus Torvalds } 14701da177e4SLinus Torvalds 1471c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1472c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1473c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1474c65b1445SDouglas Gilbert { 147501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1476c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1477773642d9SDouglas Gilbert int alloc_len; 1478c65b1445SDouglas Gilbert 1479773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1480c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 148128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1482c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1483773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1484773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1485773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1486773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 148744d92694SMartin K. Petersen 1488be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 14895b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1490773642d9SDouglas Gilbert if (sdebug_lbprz) 1491be1dd78dSEric Sandeen arr[14] |= 0x40; /* LBPRZ */ 1492be1dd78dSEric Sandeen } 149344d92694SMartin K. Petersen 1494773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1495c6a44287SMartin K. Petersen 1496773642d9SDouglas Gilbert if (sdebug_dif) { 1497773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1498c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1499c6a44287SMartin K. Petersen } 1500c6a44287SMartin K. Petersen 1501c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1502c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1503c65b1445SDouglas Gilbert } 1504c65b1445SDouglas Gilbert 15055a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15065a09e398SHannes Reinecke 15075a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15085a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15095a09e398SHannes Reinecke { 151001123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15115a09e398SHannes Reinecke unsigned char * arr; 15125a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15135a09e398SHannes Reinecke int n, ret, alen, rlen; 15145a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15155a09e398SHannes Reinecke 1516773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 15176f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15186f3cbf55SDouglas Gilbert if (! arr) 15196f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15205a09e398SHannes Reinecke /* 15215a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 15225a09e398SHannes Reinecke * real and a fake port with no device connected. 15235a09e398SHannes Reinecke * So we create two port groups with one port each 15245a09e398SHannes Reinecke * and set the group with port B to unavailable. 15255a09e398SHannes Reinecke */ 15265a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 15275a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 15285a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 15295a09e398SHannes Reinecke (devip->channel & 0x7f); 15305a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 15315a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 15325a09e398SHannes Reinecke 15335a09e398SHannes Reinecke /* 15345a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 15355a09e398SHannes Reinecke */ 15365a09e398SHannes Reinecke n = 4; 1537773642d9SDouglas Gilbert if (0 == sdebug_vpd_use_hostno) { 15385a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 15395a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 15405a09e398SHannes Reinecke } else { 15415a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1542773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 15435a09e398SHannes Reinecke } 1544773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1545773642d9SDouglas Gilbert n += 2; 15465a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15475a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15485a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15495a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15505a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15515a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1552773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1553773642d9SDouglas Gilbert n += 2; 15545a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 15555a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1556773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1557773642d9SDouglas Gilbert n += 2; 15585a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15595a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 15605a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 15615a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 15625a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 15635a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1564773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1565773642d9SDouglas Gilbert n += 2; 15665a09e398SHannes Reinecke 15675a09e398SHannes Reinecke rlen = n - 4; 1568773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 15695a09e398SHannes Reinecke 15705a09e398SHannes Reinecke /* 15715a09e398SHannes Reinecke * Return the smallest value of either 15725a09e398SHannes Reinecke * - The allocated length 15735a09e398SHannes Reinecke * - The constructed command length 15745a09e398SHannes Reinecke * - The maximum array size 15755a09e398SHannes Reinecke */ 15765a09e398SHannes Reinecke rlen = min(alen,n); 15775a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 15785a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 15795a09e398SHannes Reinecke kfree(arr); 15805a09e398SHannes Reinecke return ret; 15815a09e398SHannes Reinecke } 15825a09e398SHannes Reinecke 1583fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1584fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 158538d5c833SDouglas Gilbert { 158638d5c833SDouglas Gilbert bool rctd; 158738d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 158838d5c833SDouglas Gilbert u16 req_sa, u; 158938d5c833SDouglas Gilbert u32 alloc_len, a_len; 159038d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 159138d5c833SDouglas Gilbert const struct opcode_info_t *oip; 159238d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 159338d5c833SDouglas Gilbert u8 *arr; 159438d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 159538d5c833SDouglas Gilbert 159638d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 159738d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 159838d5c833SDouglas Gilbert req_opcode = cmd[3]; 159938d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 160038d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16016d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 160238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 160338d5c833SDouglas Gilbert return check_condition_result; 160438d5c833SDouglas Gilbert } 160538d5c833SDouglas Gilbert if (alloc_len > 8192) 160638d5c833SDouglas Gilbert a_len = 8192; 160738d5c833SDouglas Gilbert else 160838d5c833SDouglas Gilbert a_len = alloc_len; 160999531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 161038d5c833SDouglas Gilbert if (NULL == arr) { 161138d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 161238d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 161338d5c833SDouglas Gilbert return check_condition_result; 161438d5c833SDouglas Gilbert } 161538d5c833SDouglas Gilbert switch (reporting_opts) { 161638d5c833SDouglas Gilbert case 0: /* all commands */ 161738d5c833SDouglas Gilbert /* count number of commands */ 161838d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 161938d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 162038d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 162138d5c833SDouglas Gilbert continue; 162238d5c833SDouglas Gilbert count += (oip->num_attached + 1); 162338d5c833SDouglas Gilbert } 162438d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 162538d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 162638d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 162738d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 162838d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 162938d5c833SDouglas Gilbert continue; 163038d5c833SDouglas Gilbert na = oip->num_attached; 163138d5c833SDouglas Gilbert arr[offset] = oip->opcode; 163238d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 163338d5c833SDouglas Gilbert if (rctd) 163438d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 163538d5c833SDouglas Gilbert if (FF_SA & oip->flags) 163638d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 163738d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 163838d5c833SDouglas Gilbert if (rctd) 163938d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 164038d5c833SDouglas Gilbert r_oip = oip; 164138d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 164238d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 164338d5c833SDouglas Gilbert continue; 164438d5c833SDouglas Gilbert offset += bump; 164538d5c833SDouglas Gilbert arr[offset] = oip->opcode; 164638d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 164738d5c833SDouglas Gilbert if (rctd) 164838d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 164938d5c833SDouglas Gilbert if (FF_SA & oip->flags) 165038d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 165138d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 165238d5c833SDouglas Gilbert arr + offset + 6); 165338d5c833SDouglas Gilbert if (rctd) 165438d5c833SDouglas Gilbert put_unaligned_be16(0xa, 165538d5c833SDouglas Gilbert arr + offset + 8); 165638d5c833SDouglas Gilbert } 165738d5c833SDouglas Gilbert oip = r_oip; 165838d5c833SDouglas Gilbert offset += bump; 165938d5c833SDouglas Gilbert } 166038d5c833SDouglas Gilbert break; 166138d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 166238d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 166338d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 166438d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 166538d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 166638d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 166738d5c833SDouglas Gilbert supp = 1; 166838d5c833SDouglas Gilbert offset = 4; 166938d5c833SDouglas Gilbert } else { 167038d5c833SDouglas Gilbert if (1 == reporting_opts) { 167138d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 167238d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 167338d5c833SDouglas Gilbert 2, 2); 167438d5c833SDouglas Gilbert kfree(arr); 167538d5c833SDouglas Gilbert return check_condition_result; 167638d5c833SDouglas Gilbert } 167738d5c833SDouglas Gilbert req_sa = 0; 167838d5c833SDouglas Gilbert } else if (2 == reporting_opts && 167938d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 168038d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 168138d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 168238d5c833SDouglas Gilbert return check_condition_result; 168338d5c833SDouglas Gilbert } 168438d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 168538d5c833SDouglas Gilbert req_opcode == oip->opcode) 168638d5c833SDouglas Gilbert supp = 3; 168738d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 168838d5c833SDouglas Gilbert na = oip->num_attached; 168938d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 169038d5c833SDouglas Gilbert ++k, ++oip) { 169138d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 169238d5c833SDouglas Gilbert break; 169338d5c833SDouglas Gilbert } 169438d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 169538d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 169638d5c833SDouglas Gilbert na = oip->num_attached; 169738d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 169838d5c833SDouglas Gilbert ++k, ++oip) { 169938d5c833SDouglas Gilbert if (req_sa == oip->sa) 170038d5c833SDouglas Gilbert break; 170138d5c833SDouglas Gilbert } 170238d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 170338d5c833SDouglas Gilbert } else 170438d5c833SDouglas Gilbert supp = 3; 170538d5c833SDouglas Gilbert if (3 == supp) { 170638d5c833SDouglas Gilbert u = oip->len_mask[0]; 170738d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 170838d5c833SDouglas Gilbert arr[4] = oip->opcode; 170938d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 171038d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 171138d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 171238d5c833SDouglas Gilbert offset = 4 + u; 171338d5c833SDouglas Gilbert } else 171438d5c833SDouglas Gilbert offset = 4; 171538d5c833SDouglas Gilbert } 171638d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 171738d5c833SDouglas Gilbert if (rctd) { 171838d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 171938d5c833SDouglas Gilbert offset += 12; 172038d5c833SDouglas Gilbert } 172138d5c833SDouglas Gilbert break; 172238d5c833SDouglas Gilbert default: 172338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 172438d5c833SDouglas Gilbert kfree(arr); 172538d5c833SDouglas Gilbert return check_condition_result; 172638d5c833SDouglas Gilbert } 172738d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 172838d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 172938d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 173038d5c833SDouglas Gilbert kfree(arr); 173138d5c833SDouglas Gilbert return errsts; 173238d5c833SDouglas Gilbert } 173338d5c833SDouglas Gilbert 1734fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1735fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 173638d5c833SDouglas Gilbert { 173738d5c833SDouglas Gilbert bool repd; 173838d5c833SDouglas Gilbert u32 alloc_len, len; 173938d5c833SDouglas Gilbert u8 arr[16]; 174038d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 174138d5c833SDouglas Gilbert 174238d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 174338d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 174438d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 174538d5c833SDouglas Gilbert if (alloc_len < 4) { 174638d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 174738d5c833SDouglas Gilbert return check_condition_result; 174838d5c833SDouglas Gilbert } 174938d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 175038d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 175138d5c833SDouglas Gilbert if (repd) { 175238d5c833SDouglas Gilbert arr[3] = 0xc; 175338d5c833SDouglas Gilbert len = 16; 175438d5c833SDouglas Gilbert } else 175538d5c833SDouglas Gilbert len = 4; 175638d5c833SDouglas Gilbert 175738d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 175838d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 175938d5c833SDouglas Gilbert } 176038d5c833SDouglas Gilbert 17611da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 17621da177e4SLinus Torvalds 17631da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 17641da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 17651da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 17661da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 17671da177e4SLinus Torvalds 17681da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 17691da177e4SLinus Torvalds if (1 == pcontrol) 17701da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 17711da177e4SLinus Torvalds return sizeof(err_recov_pg); 17721da177e4SLinus Torvalds } 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 17751da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 17761da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 17771da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 17781da177e4SLinus Torvalds 17791da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 17801da177e4SLinus Torvalds if (1 == pcontrol) 17811da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 17821da177e4SLinus Torvalds return sizeof(disconnect_pg); 17831da177e4SLinus Torvalds } 17841da177e4SLinus Torvalds 17851da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 17861da177e4SLinus Torvalds { /* Format device page for mode_sense */ 17871da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 17881da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 17891da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 17901da177e4SLinus Torvalds 17911da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 1792773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 1793773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 1794773642d9SDouglas Gilbert if (sdebug_removable) 17951da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 17961da177e4SLinus Torvalds if (1 == pcontrol) 17971da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 17981da177e4SLinus Torvalds return sizeof(format_pg); 17991da177e4SLinus Torvalds } 18001da177e4SLinus Torvalds 1801fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 1802fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 1803fd32119bSDouglas Gilbert 0, 0, 0, 0}; 1804fd32119bSDouglas Gilbert 18051da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18061da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1807cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1808cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1809cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18101da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18111da177e4SLinus Torvalds 1812773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 1813cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18141da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18151da177e4SLinus Torvalds if (1 == pcontrol) 1816cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1817cbf67842SDouglas Gilbert else if (2 == pcontrol) 1818cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18191da177e4SLinus Torvalds return sizeof(caching_pg); 18201da177e4SLinus Torvalds } 18211da177e4SLinus Torvalds 1822fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 1823fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 1824fd32119bSDouglas Gilbert 18251da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 18261da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1827c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1828c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1829c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 18301da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 18311da177e4SLinus Torvalds 1832773642d9SDouglas Gilbert if (sdebug_dsense) 18331da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1834c65b1445SDouglas Gilbert else 1835c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1836c6a44287SMartin K. Petersen 1837773642d9SDouglas Gilbert if (sdebug_ato) 1838c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1839c6a44287SMartin K. Petersen 18401da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 18411da177e4SLinus Torvalds if (1 == pcontrol) 1842c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1843c65b1445SDouglas Gilbert else if (2 == pcontrol) 1844c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 18451da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 18461da177e4SLinus Torvalds } 18471da177e4SLinus Torvalds 1848c65b1445SDouglas Gilbert 18491da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 18501da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1851c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 18521da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1853c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1854c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1855c65b1445SDouglas Gilbert 18561da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 18571da177e4SLinus Torvalds if (1 == pcontrol) 1858c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1859c65b1445SDouglas Gilbert else if (2 == pcontrol) 1860c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 18611da177e4SLinus Torvalds return sizeof(iec_m_pg); 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds 1864c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1865c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1866c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1867c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1868c65b1445SDouglas Gilbert 1869c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1870c65b1445SDouglas Gilbert if (1 == pcontrol) 1871c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1872c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1873c65b1445SDouglas Gilbert } 1874c65b1445SDouglas Gilbert 1875c65b1445SDouglas Gilbert 1876c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1877c65b1445SDouglas Gilbert int target_dev_id) 1878c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1879c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1880c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1881773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1882773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1883c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1884c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1885c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1886c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1887773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1888773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1889c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1890c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1891c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1892c65b1445SDouglas Gilbert }; 1893c65b1445SDouglas Gilbert int port_a, port_b; 1894c65b1445SDouglas Gilbert 1895773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 16); 1896773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 24); 1897773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_a, sas_pcd_m_pg + 64); 1898773642d9SDouglas Gilbert put_unaligned_be64(naa5_comp_c + 1, sas_pcd_m_pg + 72); 1899c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1900c65b1445SDouglas Gilbert port_b = port_a + 1; 1901c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1902773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 1903773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 1904c65b1445SDouglas Gilbert if (1 == pcontrol) 1905c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1906c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1907c65b1445SDouglas Gilbert } 1908c65b1445SDouglas Gilbert 1909c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1910c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1911c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1912c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1913c65b1445SDouglas Gilbert }; 1914c65b1445SDouglas Gilbert 1915c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1916c65b1445SDouglas Gilbert if (1 == pcontrol) 1917c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1918c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1919c65b1445SDouglas Gilbert } 1920c65b1445SDouglas Gilbert 19211da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 19221da177e4SLinus Torvalds 1923fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 1924fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 19251da177e4SLinus Torvalds { 192623183910SDouglas Gilbert unsigned char dbd, llbaa; 192723183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 19281da177e4SLinus Torvalds unsigned char dev_spec; 1929773642d9SDouglas Gilbert int alloc_len, msense_6, offset, len, target_dev_id; 1930c2248fc9SDouglas Gilbert int target = scp->device->id; 19311da177e4SLinus Torvalds unsigned char * ap; 19321da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 193301123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 19341da177e4SLinus Torvalds 193523183910SDouglas Gilbert dbd = !!(cmd[1] & 0x8); 19361da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 19371da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 19381da177e4SLinus Torvalds subpcode = cmd[3]; 19391da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 194023183910SDouglas Gilbert llbaa = msense_6 ? 0 : !!(cmd[1] & 0x10); 1941773642d9SDouglas Gilbert if ((0 == sdebug_ptype) && (0 == dbd)) 194223183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 194323183910SDouglas Gilbert else 194423183910SDouglas Gilbert bd_len = 0; 1945773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 19461da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 19471da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 1948cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 19491da177e4SLinus Torvalds return check_condition_result; 19501da177e4SLinus Torvalds } 1951c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 1952c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 195323183910SDouglas Gilbert /* set DPOFUA bit for disks */ 1954773642d9SDouglas Gilbert if (0 == sdebug_ptype) 1955fd32119bSDouglas Gilbert dev_spec = 0x10; /* would be 0x90 if read-only */ 195623183910SDouglas Gilbert else 195723183910SDouglas Gilbert dev_spec = 0x0; 19581da177e4SLinus Torvalds if (msense_6) { 19591da177e4SLinus Torvalds arr[2] = dev_spec; 196023183910SDouglas Gilbert arr[3] = bd_len; 19611da177e4SLinus Torvalds offset = 4; 19621da177e4SLinus Torvalds } else { 19631da177e4SLinus Torvalds arr[3] = dev_spec; 196423183910SDouglas Gilbert if (16 == bd_len) 196523183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 196623183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 19671da177e4SLinus Torvalds offset = 8; 19681da177e4SLinus Torvalds } 19691da177e4SLinus Torvalds ap = arr + offset; 197028898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 197128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 197228898873SFUJITA Tomonori 197323183910SDouglas Gilbert if (8 == bd_len) { 1974773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 1975773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 1976773642d9SDouglas Gilbert else 1977773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 1978773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 197923183910SDouglas Gilbert offset += bd_len; 198023183910SDouglas Gilbert ap = arr + offset; 198123183910SDouglas Gilbert } else if (16 == bd_len) { 1982773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 1983773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 198423183910SDouglas Gilbert offset += bd_len; 198523183910SDouglas Gilbert ap = arr + offset; 198623183910SDouglas Gilbert } 19871da177e4SLinus Torvalds 1988c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 1989c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 199022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 19911da177e4SLinus Torvalds return check_condition_result; 19921da177e4SLinus Torvalds } 19931da177e4SLinus Torvalds switch (pcode) { 19941da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 19951da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 19961da177e4SLinus Torvalds offset += len; 19971da177e4SLinus Torvalds break; 19981da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 19991da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20001da177e4SLinus Torvalds offset += len; 20011da177e4SLinus Torvalds break; 20021da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 20031da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20041da177e4SLinus Torvalds offset += len; 20051da177e4SLinus Torvalds break; 20061da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 20071da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 20081da177e4SLinus Torvalds offset += len; 20091da177e4SLinus Torvalds break; 20101da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 20111da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 20121da177e4SLinus Torvalds offset += len; 20131da177e4SLinus Torvalds break; 2014c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2015c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 201622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2017c65b1445SDouglas Gilbert return check_condition_result; 2018c65b1445SDouglas Gilbert } 2019c65b1445SDouglas Gilbert len = 0; 2020c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2021c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2022c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2023c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2024c65b1445SDouglas Gilbert target_dev_id); 2025c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2026c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2027c65b1445SDouglas Gilbert offset += len; 2028c65b1445SDouglas Gilbert break; 20291da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 20301da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 20311da177e4SLinus Torvalds offset += len; 20321da177e4SLinus Torvalds break; 20331da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2034c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 20351da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20361da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 20371da177e4SLinus Torvalds len += resp_format_pg(ap + len, pcontrol, target); 20381da177e4SLinus Torvalds len += resp_caching_pg(ap + len, pcontrol, target); 20391da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2040c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2041c65b1445SDouglas Gilbert if (0xff == subpcode) { 2042c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2043c65b1445SDouglas Gilbert target, target_dev_id); 2044c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2045c65b1445SDouglas Gilbert } 20461da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2047c65b1445SDouglas Gilbert } else { 204822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2049c65b1445SDouglas Gilbert return check_condition_result; 2050c65b1445SDouglas Gilbert } 20511da177e4SLinus Torvalds offset += len; 20521da177e4SLinus Torvalds break; 20531da177e4SLinus Torvalds default: 205422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 20551da177e4SLinus Torvalds return check_condition_result; 20561da177e4SLinus Torvalds } 20571da177e4SLinus Torvalds if (msense_6) 20581da177e4SLinus Torvalds arr[0] = offset - 1; 2059773642d9SDouglas Gilbert else 2060773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 20611da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 20621da177e4SLinus Torvalds } 20631da177e4SLinus Torvalds 2064c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2065c65b1445SDouglas Gilbert 2066fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2067fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2068c65b1445SDouglas Gilbert { 2069c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2070c2248fc9SDouglas Gilbert int param_len, res, mpage; 2071c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 207201123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2073c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2074c65b1445SDouglas Gilbert 2075c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2076c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2077c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2078773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2079c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 208022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2081c65b1445SDouglas Gilbert return check_condition_result; 2082c65b1445SDouglas Gilbert } 2083c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2084c65b1445SDouglas Gilbert if (-1 == res) 2085773642d9SDouglas Gilbert return DID_ERROR << 16; 2086773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2087cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2088cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2089cbf67842SDouglas Gilbert __func__, param_len, res); 2090773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2091773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 209223183910SDouglas Gilbert if (md_len > 2) { 209322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2094c65b1445SDouglas Gilbert return check_condition_result; 2095c65b1445SDouglas Gilbert } 2096c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2097c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2098c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2099c65b1445SDouglas Gilbert if (ps) { 210022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2101c65b1445SDouglas Gilbert return check_condition_result; 2102c65b1445SDouglas Gilbert } 2103c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2104773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2105c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2106c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2107cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2108c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2109c65b1445SDouglas Gilbert return check_condition_result; 2110c65b1445SDouglas Gilbert } 2111c65b1445SDouglas Gilbert switch (mpage) { 2112cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2113cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2114cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2115cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2116cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2117cbf67842SDouglas Gilbert } 2118cbf67842SDouglas Gilbert break; 2119c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2120c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2121c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2122c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2123773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2124cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2125c65b1445SDouglas Gilbert } 2126c65b1445SDouglas Gilbert break; 2127c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2128c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2129c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2130c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2131cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2132c65b1445SDouglas Gilbert } 2133c65b1445SDouglas Gilbert break; 2134c65b1445SDouglas Gilbert default: 2135c65b1445SDouglas Gilbert break; 2136c65b1445SDouglas Gilbert } 213722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2138c65b1445SDouglas Gilbert return check_condition_result; 2139cbf67842SDouglas Gilbert set_mode_changed_ua: 2140cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2141cbf67842SDouglas Gilbert return 0; 2142c65b1445SDouglas Gilbert } 2143c65b1445SDouglas Gilbert 2144c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2145c65b1445SDouglas Gilbert { 2146c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2147c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2148c65b1445SDouglas Gilbert }; 2149c65b1445SDouglas Gilbert 2150c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2151c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2152c65b1445SDouglas Gilbert } 2153c65b1445SDouglas Gilbert 2154c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2155c65b1445SDouglas Gilbert { 2156c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2157c65b1445SDouglas Gilbert }; 2158c65b1445SDouglas Gilbert 2159c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2160c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2161c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2162c65b1445SDouglas Gilbert arr[5] = 0xff; 2163c65b1445SDouglas Gilbert } 2164c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2165c65b1445SDouglas Gilbert } 2166c65b1445SDouglas Gilbert 2167c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2168c65b1445SDouglas Gilbert 2169c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2170c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2171c65b1445SDouglas Gilbert { 2172c2248fc9SDouglas Gilbert int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n; 2173c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 217401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2175c65b1445SDouglas Gilbert 2176c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2177c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2178c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2179c65b1445SDouglas Gilbert if (ppc || sp) { 218022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2181c65b1445SDouglas Gilbert return check_condition_result; 2182c65b1445SDouglas Gilbert } 2183c65b1445SDouglas Gilbert pcontrol = (cmd[2] & 0xc0) >> 6; 2184c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 218523183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2186773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2187c65b1445SDouglas Gilbert arr[0] = pcode; 218823183910SDouglas Gilbert if (0 == subpcode) { 2189c65b1445SDouglas Gilbert switch (pcode) { 2190c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2191c65b1445SDouglas Gilbert n = 4; 2192c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2193c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2194c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2195c65b1445SDouglas Gilbert arr[3] = n - 4; 2196c65b1445SDouglas Gilbert break; 2197c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2198c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2199c65b1445SDouglas Gilbert break; 2200c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2201c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2202c65b1445SDouglas Gilbert break; 2203c65b1445SDouglas Gilbert default: 220422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2205c65b1445SDouglas Gilbert return check_condition_result; 2206c65b1445SDouglas Gilbert } 220723183910SDouglas Gilbert } else if (0xff == subpcode) { 220823183910SDouglas Gilbert arr[0] |= 0x40; 220923183910SDouglas Gilbert arr[1] = subpcode; 221023183910SDouglas Gilbert switch (pcode) { 221123183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 221223183910SDouglas Gilbert n = 4; 221323183910SDouglas Gilbert arr[n++] = 0x0; 221423183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 221523183910SDouglas Gilbert arr[n++] = 0x0; 221623183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 221723183910SDouglas Gilbert arr[n++] = 0xd; 221823183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 221923183910SDouglas Gilbert arr[n++] = 0x2f; 222023183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 222123183910SDouglas Gilbert arr[3] = n - 4; 222223183910SDouglas Gilbert break; 222323183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 222423183910SDouglas Gilbert n = 4; 222523183910SDouglas Gilbert arr[n++] = 0xd; 222623183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 222723183910SDouglas Gilbert arr[3] = n - 4; 222823183910SDouglas Gilbert break; 222923183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 223023183910SDouglas Gilbert n = 4; 223123183910SDouglas Gilbert arr[n++] = 0x2f; 223223183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 223323183910SDouglas Gilbert arr[3] = n - 4; 223423183910SDouglas Gilbert break; 223523183910SDouglas Gilbert default: 223622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 223723183910SDouglas Gilbert return check_condition_result; 223823183910SDouglas Gilbert } 223923183910SDouglas Gilbert } else { 224022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 224123183910SDouglas Gilbert return check_condition_result; 224223183910SDouglas Gilbert } 2243773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 2244c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2245c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2246c65b1445SDouglas Gilbert } 2247c65b1445SDouglas Gilbert 2248cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 224919789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 22501da177e4SLinus Torvalds { 2251c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 225222017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 22531da177e4SLinus Torvalds return check_condition_result; 22541da177e4SLinus Torvalds } 2255c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2256c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 225722017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2258cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2259c65b1445SDouglas Gilbert return check_condition_result; 2260c65b1445SDouglas Gilbert } 226119789100SFUJITA Tomonori return 0; 226219789100SFUJITA Tomonori } 226319789100SFUJITA Tomonori 2264a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2265fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, 2266fd32119bSDouglas Gilbert bool do_write) 226719789100SFUJITA Tomonori { 226819789100SFUJITA Tomonori int ret; 2269c2248fc9SDouglas Gilbert u64 block, rest = 0; 2270a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2271a4517511SAkinobu Mita enum dma_data_direction dir; 227219789100SFUJITA Tomonori 2273c2248fc9SDouglas Gilbert if (do_write) { 2274a4517511SAkinobu Mita sdb = scsi_out(scmd); 2275a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2276a4517511SAkinobu Mita } else { 2277a4517511SAkinobu Mita sdb = scsi_in(scmd); 2278a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2279a4517511SAkinobu Mita } 2280a4517511SAkinobu Mita 2281a4517511SAkinobu Mita if (!sdb->length) 2282a4517511SAkinobu Mita return 0; 2283a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2284a4517511SAkinobu Mita return -1; 228519789100SFUJITA Tomonori 228619789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 228719789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 228819789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 228919789100SFUJITA Tomonori 2290386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2291773642d9SDouglas Gilbert fake_storep + (block * sdebug_sector_size), 2292773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, 0, do_write); 2293773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2294a4517511SAkinobu Mita return ret; 2295a4517511SAkinobu Mita 2296a4517511SAkinobu Mita if (rest) { 2297386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2298773642d9SDouglas Gilbert fake_storep, rest * sdebug_sector_size, 2299773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, do_write); 2300a4517511SAkinobu Mita } 230119789100SFUJITA Tomonori 230219789100SFUJITA Tomonori return ret; 230319789100SFUJITA Tomonori } 230419789100SFUJITA Tomonori 230538d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 230638d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 230738d5c833SDouglas Gilbert * return false. */ 2308fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr) 230938d5c833SDouglas Gilbert { 231038d5c833SDouglas Gilbert bool res; 231138d5c833SDouglas Gilbert u64 block, rest = 0; 231238d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2313773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 231438d5c833SDouglas Gilbert 231538d5c833SDouglas Gilbert block = do_div(lba, store_blks); 231638d5c833SDouglas Gilbert if (block + num > store_blks) 231738d5c833SDouglas Gilbert rest = block + num - store_blks; 231838d5c833SDouglas Gilbert 231938d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 232038d5c833SDouglas Gilbert (num - rest) * lb_size); 232138d5c833SDouglas Gilbert if (!res) 232238d5c833SDouglas Gilbert return res; 232338d5c833SDouglas Gilbert if (rest) 232438d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 232538d5c833SDouglas Gilbert rest * lb_size); 232638d5c833SDouglas Gilbert if (!res) 232738d5c833SDouglas Gilbert return res; 232838d5c833SDouglas Gilbert arr += num * lb_size; 232938d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 233038d5c833SDouglas Gilbert if (rest) 233138d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 233238d5c833SDouglas Gilbert rest * lb_size); 233338d5c833SDouglas Gilbert return res; 233438d5c833SDouglas Gilbert } 233538d5c833SDouglas Gilbert 233651d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2337beb40ea4SAkinobu Mita { 233851d648afSAkinobu Mita __be16 csum; 2339beb40ea4SAkinobu Mita 2340773642d9SDouglas Gilbert if (sdebug_guard) 234151d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 234251d648afSAkinobu Mita else 2343beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 234451d648afSAkinobu Mita 2345beb40ea4SAkinobu Mita return csum; 2346beb40ea4SAkinobu Mita } 2347beb40ea4SAkinobu Mita 2348beb40ea4SAkinobu Mita static int dif_verify(struct sd_dif_tuple *sdt, const void *data, 2349beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2350beb40ea4SAkinobu Mita { 2351773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2352beb40ea4SAkinobu Mita 2353beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2354c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2355beb40ea4SAkinobu Mita (unsigned long)sector, 2356beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2357beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2358beb40ea4SAkinobu Mita return 0x01; 2359beb40ea4SAkinobu Mita } 2360773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE1_PROTECTION && 2361beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2362c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2363c1287970STomas Winkler (unsigned long)sector); 2364beb40ea4SAkinobu Mita return 0x03; 2365beb40ea4SAkinobu Mita } 2366773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2367beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2368c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2369c1287970STomas Winkler (unsigned long)sector); 2370beb40ea4SAkinobu Mita return 0x03; 2371beb40ea4SAkinobu Mita } 2372beb40ea4SAkinobu Mita return 0; 2373beb40ea4SAkinobu Mita } 2374beb40ea4SAkinobu Mita 2375bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 237665f72f2aSAkinobu Mita unsigned int sectors, bool read) 2377c6a44287SMartin K. Petersen { 2378be4e11beSAkinobu Mita size_t resid; 2379c6a44287SMartin K. Petersen void *paddr; 238014faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2381be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2382c6a44287SMartin K. Petersen 2383e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2384e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2385c6a44287SMartin K. Petersen 2386be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2387be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2388be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2389be4e11beSAkinobu Mita 2390be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2391be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 239214faa944SAkinobu Mita void *start = dif_store(sector); 2393be4e11beSAkinobu Mita size_t rest = 0; 239414faa944SAkinobu Mita 239514faa944SAkinobu Mita if (dif_store_end < start + len) 239614faa944SAkinobu Mita rest = start + len - dif_store_end; 2397c6a44287SMartin K. Petersen 2398be4e11beSAkinobu Mita paddr = miter.addr; 239914faa944SAkinobu Mita 240065f72f2aSAkinobu Mita if (read) 240165f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 240265f72f2aSAkinobu Mita else 240365f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 240465f72f2aSAkinobu Mita 240565f72f2aSAkinobu Mita if (rest) { 240665f72f2aSAkinobu Mita if (read) 240714faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 240865f72f2aSAkinobu Mita else 240965f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 241065f72f2aSAkinobu Mita } 2411c6a44287SMartin K. Petersen 2412e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2413c6a44287SMartin K. Petersen resid -= len; 2414c6a44287SMartin K. Petersen } 2415be4e11beSAkinobu Mita sg_miter_stop(&miter); 2416bb8c063cSAkinobu Mita } 2417c6a44287SMartin K. Petersen 2418bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2419bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2420bb8c063cSAkinobu Mita { 2421bb8c063cSAkinobu Mita unsigned int i; 2422bb8c063cSAkinobu Mita struct sd_dif_tuple *sdt; 2423bb8c063cSAkinobu Mita sector_t sector; 2424bb8c063cSAkinobu Mita 2425c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2426bb8c063cSAkinobu Mita int ret; 2427bb8c063cSAkinobu Mita 2428bb8c063cSAkinobu Mita sector = start_sec + i; 2429bb8c063cSAkinobu Mita sdt = dif_store(sector); 2430bb8c063cSAkinobu Mita 243151d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2432bb8c063cSAkinobu Mita continue; 2433bb8c063cSAkinobu Mita 2434bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2435bb8c063cSAkinobu Mita if (ret) { 2436bb8c063cSAkinobu Mita dif_errors++; 2437bb8c063cSAkinobu Mita return ret; 2438bb8c063cSAkinobu Mita } 2439bb8c063cSAkinobu Mita } 2440bb8c063cSAkinobu Mita 244165f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2442c6a44287SMartin K. Petersen dix_reads++; 2443c6a44287SMartin K. Petersen 2444c6a44287SMartin K. Petersen return 0; 2445c6a44287SMartin K. Petersen } 2446c6a44287SMartin K. Petersen 2447fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 244819789100SFUJITA Tomonori { 2449c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2450c2248fc9SDouglas Gilbert u64 lba; 2451c2248fc9SDouglas Gilbert u32 num; 2452c2248fc9SDouglas Gilbert u32 ei_lba; 245319789100SFUJITA Tomonori unsigned long iflags; 245419789100SFUJITA Tomonori int ret; 2455c2248fc9SDouglas Gilbert bool check_prot; 245619789100SFUJITA Tomonori 2457c2248fc9SDouglas Gilbert switch (cmd[0]) { 2458c2248fc9SDouglas Gilbert case READ_16: 2459c2248fc9SDouglas Gilbert ei_lba = 0; 2460c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2461c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2462c2248fc9SDouglas Gilbert check_prot = true; 2463c2248fc9SDouglas Gilbert break; 2464c2248fc9SDouglas Gilbert case READ_10: 2465c2248fc9SDouglas Gilbert ei_lba = 0; 2466c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2467c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2468c2248fc9SDouglas Gilbert check_prot = true; 2469c2248fc9SDouglas Gilbert break; 2470c2248fc9SDouglas Gilbert case READ_6: 2471c2248fc9SDouglas Gilbert ei_lba = 0; 2472c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2473c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2474c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2475c2248fc9SDouglas Gilbert check_prot = true; 2476c2248fc9SDouglas Gilbert break; 2477c2248fc9SDouglas Gilbert case READ_12: 2478c2248fc9SDouglas Gilbert ei_lba = 0; 2479c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2480c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2481c2248fc9SDouglas Gilbert check_prot = true; 2482c2248fc9SDouglas Gilbert break; 2483c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2484c2248fc9SDouglas Gilbert ei_lba = 0; 2485c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2486c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2487c2248fc9SDouglas Gilbert check_prot = false; 2488c2248fc9SDouglas Gilbert break; 2489c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2490c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2491c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2492c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2493c2248fc9SDouglas Gilbert check_prot = false; 2494c2248fc9SDouglas Gilbert break; 2495c2248fc9SDouglas Gilbert } 2496f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2497773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2498c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2499c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2500c2248fc9SDouglas Gilbert return check_condition_result; 2501c2248fc9SDouglas Gilbert } 2502773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2503773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2504c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2505c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2506c2248fc9SDouglas Gilbert "to DIF device\n"); 2507c2248fc9SDouglas Gilbert } 2508f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2509c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2510c2248fc9SDouglas Gilbert 2511c2248fc9SDouglas Gilbert if (ep->inj_short) 2512c2248fc9SDouglas Gilbert num /= 2; 2513c2248fc9SDouglas Gilbert } 2514c2248fc9SDouglas Gilbert 2515c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2516f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2517c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2518c2248fc9SDouglas Gilbert return check_condition_result; 2519c2248fc9SDouglas Gilbert } 2520c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2521f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2522c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2523c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2524c2248fc9SDouglas Gilbert return check_condition_result; 2525c2248fc9SDouglas Gilbert } 252619789100SFUJITA Tomonori 2527f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 252832f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2529f46eb0e9SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { 2530c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2531c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2532c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2533c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2534c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 253532f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 253632f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2537c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2538c65b1445SDouglas Gilbert } 2539c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 25401da177e4SLinus Torvalds return check_condition_result; 25411da177e4SLinus Torvalds } 2542c6a44287SMartin K. Petersen 25436c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 25446c78cc06SAkinobu Mita 2545c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2546f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2547c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2548c6a44287SMartin K. Petersen 2549c6a44287SMartin K. Petersen if (prot_ret) { 25506c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2551c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2552c6a44287SMartin K. Petersen return illegal_condition_result; 2553c6a44287SMartin K. Petersen } 2554c6a44287SMartin K. Petersen } 2555c6a44287SMartin K. Petersen 2556c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 25571da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2558f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2559a4517511SAkinobu Mita return DID_ERROR << 16; 2560a4517511SAkinobu Mita 2561c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2562a4517511SAkinobu Mita 2563f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2564c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2565c2248fc9SDouglas Gilbert 2566c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2567c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2568c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2569c2248fc9SDouglas Gilbert return check_condition_result; 2570c2248fc9SDouglas Gilbert } else if (ep->inj_transport) { 2571c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2572c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2573c2248fc9SDouglas Gilbert return check_condition_result; 2574c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2575c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2576c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2577c2248fc9SDouglas Gilbert return illegal_condition_result; 2578c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2579c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2580c2248fc9SDouglas Gilbert return illegal_condition_result; 2581c2248fc9SDouglas Gilbert } 2582c2248fc9SDouglas Gilbert } 2583a4517511SAkinobu Mita return 0; 25841da177e4SLinus Torvalds } 25851da177e4SLinus Torvalds 258658a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2587c6a44287SMartin K. Petersen { 2588cbf67842SDouglas Gilbert int i, j, n; 2589c6a44287SMartin K. Petersen 2590cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2591c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2592cbf67842SDouglas Gilbert char b[128]; 2593c6a44287SMartin K. Petersen 2594cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2595c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2596c6a44287SMartin K. Petersen 2597cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2598cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2599cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2600cbf67842SDouglas Gilbert else 2601cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2602cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2603cbf67842SDouglas Gilbert } 2604cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2605c6a44287SMartin K. Petersen } 2606c6a44287SMartin K. Petersen } 2607c6a44287SMartin K. Petersen 2608c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2609395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2610c6a44287SMartin K. Petersen { 2611be4e11beSAkinobu Mita int ret; 2612c6a44287SMartin K. Petersen struct sd_dif_tuple *sdt; 2613be4e11beSAkinobu Mita void *daddr; 261465f72f2aSAkinobu Mita sector_t sector = start_sec; 2615c6a44287SMartin K. Petersen int ppage_offset; 2616be4e11beSAkinobu Mita int dpage_offset; 2617be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2618be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2619c6a44287SMartin K. Petersen 2620c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2621c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2622c6a44287SMartin K. Petersen 2623be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2624be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2625be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2626be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2627be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2628c6a44287SMartin K. Petersen 2629be4e11beSAkinobu Mita /* For each protection page */ 2630be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2631be4e11beSAkinobu Mita dpage_offset = 0; 2632be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2633be4e11beSAkinobu Mita ret = 0x01; 2634be4e11beSAkinobu Mita goto out; 2635c6a44287SMartin K. Petersen } 2636c6a44287SMartin K. Petersen 2637be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 2638be4e11beSAkinobu Mita ppage_offset += sizeof(struct sd_dif_tuple)) { 2639be4e11beSAkinobu Mita /* If we're at the end of the current 2640be4e11beSAkinobu Mita * data page advance to the next one 2641be4e11beSAkinobu Mita */ 2642be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2643be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2644be4e11beSAkinobu Mita ret = 0x01; 2645be4e11beSAkinobu Mita goto out; 2646be4e11beSAkinobu Mita } 2647be4e11beSAkinobu Mita dpage_offset = 0; 2648be4e11beSAkinobu Mita } 2649c6a44287SMartin K. Petersen 2650be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2651be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2652be4e11beSAkinobu Mita 2653be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2654beb40ea4SAkinobu Mita if (ret) { 2655773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2656395cef03SMartin K. Petersen goto out; 2657395cef03SMartin K. Petersen } 2658395cef03SMartin K. Petersen 2659c6a44287SMartin K. Petersen sector++; 2660395cef03SMartin K. Petersen ei_lba++; 2661773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2662c6a44287SMartin K. Petersen } 2663be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2664be4e11beSAkinobu Mita sg_miter_stop(&diter); 2665c6a44287SMartin K. Petersen } 2666be4e11beSAkinobu Mita sg_miter_stop(&piter); 2667c6a44287SMartin K. Petersen 266865f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2669c6a44287SMartin K. Petersen dix_writes++; 2670c6a44287SMartin K. Petersen 2671c6a44287SMartin K. Petersen return 0; 2672c6a44287SMartin K. Petersen 2673c6a44287SMartin K. Petersen out: 2674c6a44287SMartin K. Petersen dif_errors++; 2675be4e11beSAkinobu Mita sg_miter_stop(&diter); 2676be4e11beSAkinobu Mita sg_miter_stop(&piter); 2677c6a44287SMartin K. Petersen return ret; 2678c6a44287SMartin K. Petersen } 2679c6a44287SMartin K. Petersen 2680b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2681b90ebc3dSAkinobu Mita { 2682773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2683773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2684773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2685b90ebc3dSAkinobu Mita return lba; 2686b90ebc3dSAkinobu Mita } 2687b90ebc3dSAkinobu Mita 2688b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2689b90ebc3dSAkinobu Mita { 2690773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2691a027b5b9SAkinobu Mita 2692773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2693773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2694a027b5b9SAkinobu Mita return lba; 2695a027b5b9SAkinobu Mita } 2696a027b5b9SAkinobu Mita 269744d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 269844d92694SMartin K. Petersen { 2699b90ebc3dSAkinobu Mita sector_t end; 2700b90ebc3dSAkinobu Mita unsigned int mapped; 2701b90ebc3dSAkinobu Mita unsigned long index; 2702b90ebc3dSAkinobu Mita unsigned long next; 270344d92694SMartin K. Petersen 2704b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2705b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 270644d92694SMartin K. Petersen 270744d92694SMartin K. Petersen if (mapped) 2708b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 270944d92694SMartin K. Petersen else 2710b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 271144d92694SMartin K. Petersen 2712b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 271344d92694SMartin K. Petersen *num = end - lba; 271444d92694SMartin K. Petersen return mapped; 271544d92694SMartin K. Petersen } 271644d92694SMartin K. Petersen 271744d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 271844d92694SMartin K. Petersen { 271944d92694SMartin K. Petersen sector_t end = lba + len; 272044d92694SMartin K. Petersen 272144d92694SMartin K. Petersen while (lba < end) { 2722b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 272344d92694SMartin K. Petersen 2724b90ebc3dSAkinobu Mita if (index < map_size) 2725b90ebc3dSAkinobu Mita set_bit(index, map_storep); 272644d92694SMartin K. Petersen 2727b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 272844d92694SMartin K. Petersen } 272944d92694SMartin K. Petersen } 273044d92694SMartin K. Petersen 273144d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 273244d92694SMartin K. Petersen { 273344d92694SMartin K. Petersen sector_t end = lba + len; 273444d92694SMartin K. Petersen 273544d92694SMartin K. Petersen while (lba < end) { 2736b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 273744d92694SMartin K. Petersen 2738b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2739773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 2740b90ebc3dSAkinobu Mita index < map_size) { 2741b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2742773642d9SDouglas Gilbert if (sdebug_lbprz) { 2743be1dd78dSEric Sandeen memset(fake_storep + 2744773642d9SDouglas Gilbert lba * sdebug_sector_size, 0, 2745773642d9SDouglas Gilbert sdebug_sector_size * 2746773642d9SDouglas Gilbert sdebug_unmap_granularity); 2747be1dd78dSEric Sandeen } 2748e9926b43SAkinobu Mita if (dif_storep) { 2749e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2750e9926b43SAkinobu Mita sizeof(*dif_storep) * 2751773642d9SDouglas Gilbert sdebug_unmap_granularity); 2752e9926b43SAkinobu Mita } 2753b90ebc3dSAkinobu Mita } 2754b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 275544d92694SMartin K. Petersen } 275644d92694SMartin K. Petersen } 275744d92694SMartin K. Petersen 2758fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 27591da177e4SLinus Torvalds { 2760c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2761c2248fc9SDouglas Gilbert u64 lba; 2762c2248fc9SDouglas Gilbert u32 num; 2763c2248fc9SDouglas Gilbert u32 ei_lba; 27641da177e4SLinus Torvalds unsigned long iflags; 276519789100SFUJITA Tomonori int ret; 2766c2248fc9SDouglas Gilbert bool check_prot; 27671da177e4SLinus Torvalds 2768c2248fc9SDouglas Gilbert switch (cmd[0]) { 2769c2248fc9SDouglas Gilbert case WRITE_16: 2770c2248fc9SDouglas Gilbert ei_lba = 0; 2771c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2772c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2773c2248fc9SDouglas Gilbert check_prot = true; 2774c2248fc9SDouglas Gilbert break; 2775c2248fc9SDouglas Gilbert case WRITE_10: 2776c2248fc9SDouglas Gilbert ei_lba = 0; 2777c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2778c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2779c2248fc9SDouglas Gilbert check_prot = true; 2780c2248fc9SDouglas Gilbert break; 2781c2248fc9SDouglas Gilbert case WRITE_6: 2782c2248fc9SDouglas Gilbert ei_lba = 0; 2783c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2784c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2785c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2786c2248fc9SDouglas Gilbert check_prot = true; 2787c2248fc9SDouglas Gilbert break; 2788c2248fc9SDouglas Gilbert case WRITE_12: 2789c2248fc9SDouglas Gilbert ei_lba = 0; 2790c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2791c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2792c2248fc9SDouglas Gilbert check_prot = true; 2793c2248fc9SDouglas Gilbert break; 2794c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2795c2248fc9SDouglas Gilbert ei_lba = 0; 2796c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2797c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2798c2248fc9SDouglas Gilbert check_prot = false; 2799c2248fc9SDouglas Gilbert break; 2800c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2801c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2802c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2803c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2804c2248fc9SDouglas Gilbert check_prot = false; 2805c2248fc9SDouglas Gilbert break; 2806c2248fc9SDouglas Gilbert } 2807f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 2808773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 2809c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2810c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2811c2248fc9SDouglas Gilbert return check_condition_result; 2812c2248fc9SDouglas Gilbert } 2813773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 2814773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 2815c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2816c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2817c2248fc9SDouglas Gilbert "to DIF device\n"); 2818c2248fc9SDouglas Gilbert } 2819c2248fc9SDouglas Gilbert 2820c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2821f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2822c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2823c2248fc9SDouglas Gilbert return check_condition_result; 2824c2248fc9SDouglas Gilbert } 2825c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2826f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2827c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2828c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2829c2248fc9SDouglas Gilbert return check_condition_result; 2830c2248fc9SDouglas Gilbert } 28311da177e4SLinus Torvalds 28326c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 28336c78cc06SAkinobu Mita 2834c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2835f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2836c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2837c6a44287SMartin K. Petersen 2838c6a44287SMartin K. Petersen if (prot_ret) { 28396c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2840c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2841c6a44287SMartin K. Petersen return illegal_condition_result; 2842c6a44287SMartin K. Petersen } 2843c6a44287SMartin K. Petersen } 2844c6a44287SMartin K. Petersen 2845c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 2846f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 284744d92694SMartin K. Petersen map_region(lba, num); 28481da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 2849f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 2850773642d9SDouglas Gilbert return DID_ERROR << 16; 2851773642d9SDouglas Gilbert else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) 2852c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2853cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2854773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 285544d92694SMartin K. Petersen 2856f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2857c2248fc9SDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 2858c2248fc9SDouglas Gilbert 2859c2248fc9SDouglas Gilbert if (ep->inj_recovered) { 2860c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2861c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2862c2248fc9SDouglas Gilbert return check_condition_result; 2863c2248fc9SDouglas Gilbert } else if (ep->inj_dif) { 2864c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2865c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2866c2248fc9SDouglas Gilbert return illegal_condition_result; 2867c2248fc9SDouglas Gilbert } else if (ep->inj_dix) { 2868c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2869c2248fc9SDouglas Gilbert return illegal_condition_result; 2870c2248fc9SDouglas Gilbert } 2871c2248fc9SDouglas Gilbert } 28721da177e4SLinus Torvalds return 0; 28731da177e4SLinus Torvalds } 28741da177e4SLinus Torvalds 2875fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 2876fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 287744d92694SMartin K. Petersen { 287844d92694SMartin K. Petersen unsigned long iflags; 287944d92694SMartin K. Petersen unsigned long long i; 288044d92694SMartin K. Petersen int ret; 2881773642d9SDouglas Gilbert u64 lba_off; 288244d92694SMartin K. Petersen 2883c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 288444d92694SMartin K. Petersen if (ret) 288544d92694SMartin K. Petersen return ret; 288644d92694SMartin K. Petersen 288744d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 288844d92694SMartin K. Petersen 28899ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 289044d92694SMartin K. Petersen unmap_region(lba, num); 289144d92694SMartin K. Petersen goto out; 289244d92694SMartin K. Petersen } 289344d92694SMartin K. Petersen 2894773642d9SDouglas Gilbert lba_off = lba * sdebug_sector_size; 2895c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 2896c2248fc9SDouglas Gilbert if (ndob) { 2897773642d9SDouglas Gilbert memset(fake_storep + lba_off, 0, sdebug_sector_size); 2898c2248fc9SDouglas Gilbert ret = 0; 2899c2248fc9SDouglas Gilbert } else 2900773642d9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + lba_off, 2901773642d9SDouglas Gilbert sdebug_sector_size); 290244d92694SMartin K. Petersen 290344d92694SMartin K. Petersen if (-1 == ret) { 290444d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 2905773642d9SDouglas Gilbert return DID_ERROR << 16; 2906773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) 2907c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2908cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 2909cbf67842SDouglas Gilbert my_name, "write same", 2910773642d9SDouglas Gilbert num * sdebug_sector_size, ret); 291144d92694SMartin K. Petersen 291244d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 291344d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 2914773642d9SDouglas Gilbert memcpy(fake_storep + ((lba + i) * sdebug_sector_size), 2915773642d9SDouglas Gilbert fake_storep + lba_off, 2916773642d9SDouglas Gilbert sdebug_sector_size); 291744d92694SMartin K. Petersen 29189ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 291944d92694SMartin K. Petersen map_region(lba, num); 292044d92694SMartin K. Petersen out: 292144d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 292244d92694SMartin K. Petersen 292344d92694SMartin K. Petersen return 0; 292444d92694SMartin K. Petersen } 292544d92694SMartin K. Petersen 2926fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 2927fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2928c2248fc9SDouglas Gilbert { 2929c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2930c2248fc9SDouglas Gilbert u32 lba; 2931c2248fc9SDouglas Gilbert u16 num; 2932c2248fc9SDouglas Gilbert u32 ei_lba = 0; 2933c2248fc9SDouglas Gilbert bool unmap = false; 2934c2248fc9SDouglas Gilbert 2935c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 2936773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 2937c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 2938c2248fc9SDouglas Gilbert return check_condition_result; 2939c2248fc9SDouglas Gilbert } else 2940c2248fc9SDouglas Gilbert unmap = true; 2941c2248fc9SDouglas Gilbert } 2942c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2943c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2944773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 2945c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 2946c2248fc9SDouglas Gilbert return check_condition_result; 2947c2248fc9SDouglas Gilbert } 2948c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 2949c2248fc9SDouglas Gilbert } 2950c2248fc9SDouglas Gilbert 2951fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 2952fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2953c2248fc9SDouglas Gilbert { 2954c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2955c2248fc9SDouglas Gilbert u64 lba; 2956c2248fc9SDouglas Gilbert u32 num; 2957c2248fc9SDouglas Gilbert u32 ei_lba = 0; 2958c2248fc9SDouglas Gilbert bool unmap = false; 2959c2248fc9SDouglas Gilbert bool ndob = false; 2960c2248fc9SDouglas Gilbert 2961c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 2962773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 2963c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 2964c2248fc9SDouglas Gilbert return check_condition_result; 2965c2248fc9SDouglas Gilbert } else 2966c2248fc9SDouglas Gilbert unmap = true; 2967c2248fc9SDouglas Gilbert } 2968c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 2969c2248fc9SDouglas Gilbert ndob = true; 2970c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2971c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2972773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 2973c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 2974c2248fc9SDouglas Gilbert return check_condition_result; 2975c2248fc9SDouglas Gilbert } 2976c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 2977c2248fc9SDouglas Gilbert } 2978c2248fc9SDouglas Gilbert 2979acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 2980acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 2981acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 2982fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 2983fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2984acafd0b9SEwan D. Milne { 2985acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 2986acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 2987acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 2988acafd0b9SEwan D. Milne u8 mode; 2989acafd0b9SEwan D. Milne 2990acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 2991acafd0b9SEwan D. Milne switch (mode) { 2992acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 2993acafd0b9SEwan D. Milne /* set UAs on this device only */ 2994acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 2995acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 2996acafd0b9SEwan D. Milne break; 2997acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 2998acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 2999acafd0b9SEwan D. Milne break; 3000acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3001acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3002acafd0b9SEwan D. Milne list_for_each_entry(dp, 3003acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3004acafd0b9SEwan D. Milne dev_list) 3005acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3006acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3007acafd0b9SEwan D. Milne if (devip != dp) 3008acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3009acafd0b9SEwan D. Milne dp->uas_bm); 3010acafd0b9SEwan D. Milne } 3011acafd0b9SEwan D. Milne break; 3012acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3013acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3014acafd0b9SEwan D. Milne list_for_each_entry(dp, 3015acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3016acafd0b9SEwan D. Milne dev_list) 3017acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3018acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3019acafd0b9SEwan D. Milne dp->uas_bm); 3020acafd0b9SEwan D. Milne break; 3021acafd0b9SEwan D. Milne default: 3022acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3023acafd0b9SEwan D. Milne break; 3024acafd0b9SEwan D. Milne } 3025acafd0b9SEwan D. Milne return 0; 3026acafd0b9SEwan D. Milne } 3027acafd0b9SEwan D. Milne 3028fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3029fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 303038d5c833SDouglas Gilbert { 303138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 303238d5c833SDouglas Gilbert u8 *arr; 303338d5c833SDouglas Gilbert u8 *fake_storep_hold; 303438d5c833SDouglas Gilbert u64 lba; 303538d5c833SDouglas Gilbert u32 dnum; 3036773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 303738d5c833SDouglas Gilbert u8 num; 303838d5c833SDouglas Gilbert unsigned long iflags; 303938d5c833SDouglas Gilbert int ret; 3040d467d31fSDouglas Gilbert int retval = 0; 304138d5c833SDouglas Gilbert 3042d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 304338d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 304438d5c833SDouglas Gilbert if (0 == num) 304538d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 3046773642d9SDouglas Gilbert if (sdebug_dif == SD_DIF_TYPE2_PROTECTION && 304738d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 304838d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 304938d5c833SDouglas Gilbert return check_condition_result; 305038d5c833SDouglas Gilbert } 3051773642d9SDouglas Gilbert if ((sdebug_dif == SD_DIF_TYPE1_PROTECTION || 3052773642d9SDouglas Gilbert sdebug_dif == SD_DIF_TYPE3_PROTECTION) && 305338d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 305438d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 305538d5c833SDouglas Gilbert "to DIF device\n"); 305638d5c833SDouglas Gilbert 305738d5c833SDouglas Gilbert /* inline check_device_access_params() */ 305838d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 305938d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 306038d5c833SDouglas Gilbert return check_condition_result; 306138d5c833SDouglas Gilbert } 306238d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 306338d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 306438d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 306538d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 306638d5c833SDouglas Gilbert return check_condition_result; 306738d5c833SDouglas Gilbert } 3068d467d31fSDouglas Gilbert dnum = 2 * num; 3069d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3070d467d31fSDouglas Gilbert if (NULL == arr) { 3071d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3072d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3073d467d31fSDouglas Gilbert return check_condition_result; 3074d467d31fSDouglas Gilbert } 307538d5c833SDouglas Gilbert 307638d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 307738d5c833SDouglas Gilbert 307838d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 307938d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 308038d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 308138d5c833SDouglas Gilbert fake_storep = arr; 308238d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 308338d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 308438d5c833SDouglas Gilbert if (ret == -1) { 3085d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3086d467d31fSDouglas Gilbert goto cleanup; 3087773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 308838d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 308938d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 309038d5c833SDouglas Gilbert dnum * lb_size, ret); 309138d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 309238d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3093d467d31fSDouglas Gilbert retval = check_condition_result; 3094d467d31fSDouglas Gilbert goto cleanup; 309538d5c833SDouglas Gilbert } 309638d5c833SDouglas Gilbert if (scsi_debug_lbp()) 309738d5c833SDouglas Gilbert map_region(lba, num); 3098d467d31fSDouglas Gilbert cleanup: 309938d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3100d467d31fSDouglas Gilbert kfree(arr); 3101d467d31fSDouglas Gilbert return retval; 310238d5c833SDouglas Gilbert } 310338d5c833SDouglas Gilbert 310444d92694SMartin K. Petersen struct unmap_block_desc { 310544d92694SMartin K. Petersen __be64 lba; 310644d92694SMartin K. Petersen __be32 blocks; 310744d92694SMartin K. Petersen __be32 __reserved; 310844d92694SMartin K. Petersen }; 310944d92694SMartin K. Petersen 3110fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 311144d92694SMartin K. Petersen { 311244d92694SMartin K. Petersen unsigned char *buf; 311344d92694SMartin K. Petersen struct unmap_block_desc *desc; 311444d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 311544d92694SMartin K. Petersen int ret; 31166c78cc06SAkinobu Mita unsigned long iflags; 311744d92694SMartin K. Petersen 311844d92694SMartin K. Petersen 3119c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3120c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3121c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3122c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 312344d92694SMartin K. Petersen 312444d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3125773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3126c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 312744d92694SMartin K. Petersen return check_condition_result; 3128c2248fc9SDouglas Gilbert } 312944d92694SMartin K. Petersen 3130b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3131c2248fc9SDouglas Gilbert if (!buf) { 3132c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3133c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3134c2248fc9SDouglas Gilbert return check_condition_result; 3135c2248fc9SDouglas Gilbert } 3136c2248fc9SDouglas Gilbert 3137c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 313844d92694SMartin K. Petersen 313944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 314044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 314144d92694SMartin K. Petersen 314244d92694SMartin K. Petersen desc = (void *)&buf[8]; 314344d92694SMartin K. Petersen 31446c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 31456c78cc06SAkinobu Mita 314644d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 314744d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 314844d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 314944d92694SMartin K. Petersen 3150c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 315144d92694SMartin K. Petersen if (ret) 315244d92694SMartin K. Petersen goto out; 315344d92694SMartin K. Petersen 315444d92694SMartin K. Petersen unmap_region(lba, num); 315544d92694SMartin K. Petersen } 315644d92694SMartin K. Petersen 315744d92694SMartin K. Petersen ret = 0; 315844d92694SMartin K. Petersen 315944d92694SMartin K. Petersen out: 31606c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 316144d92694SMartin K. Petersen kfree(buf); 316244d92694SMartin K. Petersen 316344d92694SMartin K. Petersen return ret; 316444d92694SMartin K. Petersen } 316544d92694SMartin K. Petersen 316644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 316744d92694SMartin K. Petersen 3168fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3169fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 317044d92694SMartin K. Petersen { 3171c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3172c2248fc9SDouglas Gilbert u64 lba; 3173c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3174c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 317544d92694SMartin K. Petersen int ret; 317644d92694SMartin K. Petersen 3177c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3178c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 317944d92694SMartin K. Petersen 318044d92694SMartin K. Petersen if (alloc_len < 24) 318144d92694SMartin K. Petersen return 0; 318244d92694SMartin K. Petersen 3183c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 318444d92694SMartin K. Petersen if (ret) 318544d92694SMartin K. Petersen return ret; 318644d92694SMartin K. Petersen 3187c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 318844d92694SMartin K. Petersen mapped = map_state(lba, &num); 3189c2248fc9SDouglas Gilbert else { 3190c2248fc9SDouglas Gilbert mapped = 1; 3191c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3192c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3193c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3194c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3195c2248fc9SDouglas Gilbert else 3196c2248fc9SDouglas Gilbert num = 0xffffffff; 3197c2248fc9SDouglas Gilbert } 319844d92694SMartin K. Petersen 319944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3200c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3201c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3202c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3203c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 320444d92694SMartin K. Petersen 3205c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 320644d92694SMartin K. Petersen } 320744d92694SMartin K. Petersen 3208c65b1445SDouglas Gilbert #define SDEBUG_RLUN_ARR_SZ 256 32091da177e4SLinus Torvalds 32101da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd * scp, 32111da177e4SLinus Torvalds struct sdebug_dev_info * devip) 32121da177e4SLinus Torvalds { 32131da177e4SLinus Torvalds unsigned int alloc_len; 321422017ed2SDouglas Gilbert int lun_cnt, i, upper, num, n, want_wlun, shortish; 321522017ed2SDouglas Gilbert u64 lun; 321601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 32171da177e4SLinus Torvalds int select_report = (int)cmd[2]; 32181da177e4SLinus Torvalds struct scsi_lun *one_lun; 32191da177e4SLinus Torvalds unsigned char arr[SDEBUG_RLUN_ARR_SZ]; 3220c65b1445SDouglas Gilbert unsigned char * max_addr; 32211da177e4SLinus Torvalds 322219c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 32231da177e4SLinus Torvalds alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24); 322422017ed2SDouglas Gilbert shortish = (alloc_len < 4); 322522017ed2SDouglas Gilbert if (shortish || (select_report > 2)) { 322622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1); 32271da177e4SLinus Torvalds return check_condition_result; 32281da177e4SLinus Torvalds } 32291da177e4SLinus Torvalds /* can produce response with up to 16k luns (lun 0 to lun 16383) */ 32301da177e4SLinus Torvalds memset(arr, 0, SDEBUG_RLUN_ARR_SZ); 3231773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 3232c65b1445SDouglas Gilbert if (1 == select_report) 3233c65b1445SDouglas Gilbert lun_cnt = 0; 3234773642d9SDouglas Gilbert else if (sdebug_no_lun_0 && (lun_cnt > 0)) 3235c65b1445SDouglas Gilbert --lun_cnt; 323622017ed2SDouglas Gilbert want_wlun = (select_report > 0) ? 1 : 0; 323722017ed2SDouglas Gilbert num = lun_cnt + want_wlun; 3238c65b1445SDouglas Gilbert arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff; 3239c65b1445SDouglas Gilbert arr[3] = (sizeof(struct scsi_lun) * num) & 0xff; 3240c65b1445SDouglas Gilbert n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) / 3241c65b1445SDouglas Gilbert sizeof(struct scsi_lun)), num); 3242c65b1445SDouglas Gilbert if (n < num) { 324322017ed2SDouglas Gilbert want_wlun = 0; 3244c65b1445SDouglas Gilbert lun_cnt = n; 3245c65b1445SDouglas Gilbert } 32461da177e4SLinus Torvalds one_lun = (struct scsi_lun *) &arr[8]; 3247c65b1445SDouglas Gilbert max_addr = arr + SDEBUG_RLUN_ARR_SZ; 3248773642d9SDouglas Gilbert for (i = 0, lun = (sdebug_no_lun_0 ? 1 : 0); 3249c65b1445SDouglas Gilbert ((i < lun_cnt) && ((unsigned char *)(one_lun + i) < max_addr)); 3250c65b1445SDouglas Gilbert i++, lun++) { 3251c65b1445SDouglas Gilbert upper = (lun >> 8) & 0x3f; 32521da177e4SLinus Torvalds if (upper) 32531da177e4SLinus Torvalds one_lun[i].scsi_lun[0] = 32541da177e4SLinus Torvalds (upper | (SAM2_LUN_ADDRESS_METHOD << 6)); 3255c65b1445SDouglas Gilbert one_lun[i].scsi_lun[1] = lun & 0xff; 32561da177e4SLinus Torvalds } 325722017ed2SDouglas Gilbert if (want_wlun) { 325834d55434STomas Winkler one_lun[i].scsi_lun[0] = (SCSI_W_LUN_REPORT_LUNS >> 8) & 0xff; 325934d55434STomas Winkler one_lun[i].scsi_lun[1] = SCSI_W_LUN_REPORT_LUNS & 0xff; 3260c65b1445SDouglas Gilbert i++; 3261c65b1445SDouglas Gilbert } 3262c65b1445SDouglas Gilbert alloc_len = (unsigned char *)(one_lun + i) - arr; 32631da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, 32641da177e4SLinus Torvalds min((int)alloc_len, SDEBUG_RLUN_ARR_SZ)); 32651da177e4SLinus Torvalds } 32661da177e4SLinus Torvalds 3267c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3268c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3269c639d14eSFUJITA Tomonori { 3270be4e11beSAkinobu Mita int j; 3271c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3272c639d14eSFUJITA Tomonori unsigned int offset; 3273c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3274be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3275c639d14eSFUJITA Tomonori 3276c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3277b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3278c5af0db9SAkinobu Mita if (!buf) { 327922017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 328022017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3281c5af0db9SAkinobu Mita return check_condition_result; 3282c5af0db9SAkinobu Mita } 3283c639d14eSFUJITA Tomonori 328421a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3285c639d14eSFUJITA Tomonori 3286c639d14eSFUJITA Tomonori offset = 0; 3287be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3288be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3289c639d14eSFUJITA Tomonori 3290be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3291be4e11beSAkinobu Mita kaddr = miter.addr; 3292be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3293be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3294c639d14eSFUJITA Tomonori 3295be4e11beSAkinobu Mita offset += miter.length; 3296c639d14eSFUJITA Tomonori } 3297be4e11beSAkinobu Mita sg_miter_stop(&miter); 3298c639d14eSFUJITA Tomonori kfree(buf); 3299c639d14eSFUJITA Tomonori 3300be4e11beSAkinobu Mita return 0; 3301c639d14eSFUJITA Tomonori } 3302c639d14eSFUJITA Tomonori 3303fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp, 3304fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3305c2248fc9SDouglas Gilbert { 3306c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3307c2248fc9SDouglas Gilbert u64 lba; 3308c2248fc9SDouglas Gilbert u32 num; 3309c2248fc9SDouglas Gilbert int errsts; 3310c2248fc9SDouglas Gilbert 3311c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3312c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3313c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3314c2248fc9SDouglas Gilbert return check_condition_result; 3315c2248fc9SDouglas Gilbert } 3316c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3317c2248fc9SDouglas Gilbert if (errsts) 3318c2248fc9SDouglas Gilbert return errsts; 3319c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3320c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3321c2248fc9SDouglas Gilbert if (errsts) 3322c2248fc9SDouglas Gilbert return errsts; 3323c2248fc9SDouglas Gilbert } 3324c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3325c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3326c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3327c2248fc9SDouglas Gilbert } 3328c2248fc9SDouglas Gilbert 3329a10bc12aSDouglas Gilbert /* Queued command completions converge here. */ 3330fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 33311da177e4SLinus Torvalds { 3332cbf67842SDouglas Gilbert int qa_indx; 3333cbf67842SDouglas Gilbert int retiring = 0; 33341da177e4SLinus Torvalds unsigned long iflags; 3335cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3336cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3337cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 33381da177e4SLinus Torvalds 3339cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3340a10bc12aSDouglas Gilbert qa_indx = sd_dp->qa_indx; 3341f46eb0e9SDouglas Gilbert if (unlikely((qa_indx < 0) || (qa_indx >= SCSI_DEBUG_CANQUEUE))) { 3342c1287970STomas Winkler pr_err("wild qa_indx=%d\n", qa_indx); 33431da177e4SLinus Torvalds return; 33441da177e4SLinus Torvalds } 33451da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3346cbf67842SDouglas Gilbert sqcp = &queued_arr[qa_indx]; 3347cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3348f46eb0e9SDouglas Gilbert if (unlikely(NULL == scp)) { 33491da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3350c1287970STomas Winkler pr_err("scp is NULL\n"); 33511da177e4SLinus Torvalds return; 33521da177e4SLinus Torvalds } 3353cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3354f46eb0e9SDouglas Gilbert if (likely(devip)) 3355cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3356cbf67842SDouglas Gilbert else 3357c1287970STomas Winkler pr_err("devip=NULL\n"); 3358f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3359cbf67842SDouglas Gilbert retiring = 1; 3360cbf67842SDouglas Gilbert 3361cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3362f46eb0e9SDouglas Gilbert if (unlikely(!test_and_clear_bit(qa_indx, queued_in_use_bm))) { 33631da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3364c1287970STomas Winkler pr_err("Unexpected completion\n"); 3365cbf67842SDouglas Gilbert return; 33661da177e4SLinus Torvalds } 33671da177e4SLinus Torvalds 3368cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3369cbf67842SDouglas Gilbert int k, retval; 3370cbf67842SDouglas Gilbert 3371cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3372cbf67842SDouglas Gilbert if (qa_indx >= retval) { 3373cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3374c1287970STomas Winkler pr_err("index %d too large\n", retval); 3375cbf67842SDouglas Gilbert return; 3376cbf67842SDouglas Gilbert } 3377cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, retval); 3378773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3379cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3380cbf67842SDouglas Gilbert else 3381cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3382cbf67842SDouglas Gilbert } 3383cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3384cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3385cbf67842SDouglas Gilbert } 3386cbf67842SDouglas Gilbert 3387cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3388fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3389cbf67842SDouglas Gilbert { 3390a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 3391a10bc12aSDouglas Gilbert hrt); 3392a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3393cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3394cbf67842SDouglas Gilbert } 33951da177e4SLinus Torvalds 3396a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 3397fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 3398a10bc12aSDouglas Gilbert { 3399a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 3400a10bc12aSDouglas Gilbert ew.work); 3401a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3402a10bc12aSDouglas Gilbert } 3403a10bc12aSDouglas Gilbert 3404fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 3405fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 34065cb2fc06SFUJITA Tomonori { 34075cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 34085cb2fc06SFUJITA Tomonori 34095cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 34105cb2fc06SFUJITA Tomonori if (devip) { 34115cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 34125cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 34135cb2fc06SFUJITA Tomonori } 34145cb2fc06SFUJITA Tomonori return devip; 34155cb2fc06SFUJITA Tomonori } 34165cb2fc06SFUJITA Tomonori 3417f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 34181da177e4SLinus Torvalds { 34191da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 34201da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 3421f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 34221da177e4SLinus Torvalds 3423d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 34241da177e4SLinus Torvalds if (!sdbg_host) { 3425c1287970STomas Winkler pr_err("Host info NULL\n"); 34261da177e4SLinus Torvalds return NULL; 34271da177e4SLinus Torvalds } 34281da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 34291da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 34301da177e4SLinus Torvalds (devip->target == sdev->id) && 34311da177e4SLinus Torvalds (devip->lun == sdev->lun)) 34321da177e4SLinus Torvalds return devip; 34331da177e4SLinus Torvalds else { 34341da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 34351da177e4SLinus Torvalds open_devip = devip; 34361da177e4SLinus Torvalds } 34371da177e4SLinus Torvalds } 34385cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 34395cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 34405cb2fc06SFUJITA Tomonori if (!open_devip) { 3441c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 34421da177e4SLinus Torvalds return NULL; 34431da177e4SLinus Torvalds } 34441da177e4SLinus Torvalds } 3445a75869d1SFUJITA Tomonori 34461da177e4SLinus Torvalds open_devip->channel = sdev->channel; 34471da177e4SLinus Torvalds open_devip->target = sdev->id; 34481da177e4SLinus Torvalds open_devip->lun = sdev->lun; 34491da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3450cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3451cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3452c2248fc9SDouglas Gilbert open_devip->used = true; 34531da177e4SLinus Torvalds return open_devip; 34541da177e4SLinus Torvalds } 34551da177e4SLinus Torvalds 34568dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 34571da177e4SLinus Torvalds { 3458773642d9SDouglas Gilbert if (sdebug_verbose) 3459c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 34608dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 346175ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 34628dea0d02SFUJITA Tomonori return 0; 34638dea0d02SFUJITA Tomonori } 34641da177e4SLinus Torvalds 34658dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 34668dea0d02SFUJITA Tomonori { 3467f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3468f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3469a34c4e98SFUJITA Tomonori 3470773642d9SDouglas Gilbert if (sdebug_verbose) 3471c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 34728dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 34738dea0d02SFUJITA Tomonori if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN) 34748dea0d02SFUJITA Tomonori sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN; 3475f46eb0e9SDouglas Gilbert if (NULL == devip) { 3476f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 34778dea0d02SFUJITA Tomonori if (NULL == devip) 34788dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3479f46eb0e9SDouglas Gilbert } 3480c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 34816bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 3482773642d9SDouglas Gilbert if (sdebug_no_uld) 348378d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 34848dea0d02SFUJITA Tomonori return 0; 34858dea0d02SFUJITA Tomonori } 34868dea0d02SFUJITA Tomonori 34878dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 34888dea0d02SFUJITA Tomonori { 34898dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 34908dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 34918dea0d02SFUJITA Tomonori 3492773642d9SDouglas Gilbert if (sdebug_verbose) 3493c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 34948dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 34958dea0d02SFUJITA Tomonori if (devip) { 349625985edcSLucas De Marchi /* make this slot available for re-use */ 3497c2248fc9SDouglas Gilbert devip->used = false; 34988dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 34998dea0d02SFUJITA Tomonori } 35008dea0d02SFUJITA Tomonori } 35018dea0d02SFUJITA Tomonori 3502a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 3503a10bc12aSDouglas Gilbert returns false */ 3504a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 35058dea0d02SFUJITA Tomonori { 35068dea0d02SFUJITA Tomonori unsigned long iflags; 3507cbf67842SDouglas Gilbert int k, qmax, r_qmax; 35088dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3509cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3510a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 35118dea0d02SFUJITA Tomonori 35128dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3513773642d9SDouglas Gilbert qmax = sdebug_max_queue; 3514cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3515cbf67842SDouglas Gilbert if (r_qmax > qmax) 3516cbf67842SDouglas Gilbert qmax = r_qmax; 3517cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3518cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 35198dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3520a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 3521a10bc12aSDouglas Gilbert continue; 3522a10bc12aSDouglas Gilbert /* found command */ 3523db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3524db525fceSDouglas Gilbert cmnd->device->hostdata; 3525db525fceSDouglas Gilbert if (devip) 3526db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3527db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3528a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3529db525fceSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, 3530db525fceSDouglas Gilbert iflags); 3531a10bc12aSDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) { 3532a10bc12aSDouglas Gilbert if (sd_dp) 3533a10bc12aSDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3534c2206098SDouglas Gilbert } else if (sdebug_jdelay < 0) { 3535a10bc12aSDouglas Gilbert if (sd_dp) 3536a10bc12aSDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3537cbf67842SDouglas Gilbert } 3538db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3539a10bc12aSDouglas Gilbert return true; 35408dea0d02SFUJITA Tomonori } 3541cbf67842SDouglas Gilbert } 35428dea0d02SFUJITA Tomonori spin_unlock_irqrestore(&queued_arr_lock, iflags); 3543a10bc12aSDouglas Gilbert return false; 35448dea0d02SFUJITA Tomonori } 35458dea0d02SFUJITA Tomonori 3546a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 35478dea0d02SFUJITA Tomonori static void stop_all_queued(void) 35488dea0d02SFUJITA Tomonori { 35498dea0d02SFUJITA Tomonori unsigned long iflags; 35508dea0d02SFUJITA Tomonori int k; 35518dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3552cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3553a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 35548dea0d02SFUJITA Tomonori 35558dea0d02SFUJITA Tomonori spin_lock_irqsave(&queued_arr_lock, iflags); 3556cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3557cbf67842SDouglas Gilbert if (test_bit(k, queued_in_use_bm)) { 35588dea0d02SFUJITA Tomonori sqcp = &queued_arr[k]; 3559a10bc12aSDouglas Gilbert if (NULL == sqcp->a_cmnd) 3560a10bc12aSDouglas Gilbert continue; 3561db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3562db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3563db525fceSDouglas Gilbert if (devip) 3564db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3565db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3566a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3567a10bc12aSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3568a10bc12aSDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) { 3569a10bc12aSDouglas Gilbert if (sd_dp) 3570a10bc12aSDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3571c2206098SDouglas Gilbert } else if (sdebug_jdelay < 0) { 3572a10bc12aSDouglas Gilbert if (sd_dp) 3573a10bc12aSDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3574cbf67842SDouglas Gilbert } 3575db525fceSDouglas Gilbert clear_bit(k, queued_in_use_bm); 3576db525fceSDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 35778dea0d02SFUJITA Tomonori } 35788dea0d02SFUJITA Tomonori } 3579cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3580cbf67842SDouglas Gilbert } 3581cbf67842SDouglas Gilbert 3582cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3583cbf67842SDouglas Gilbert static void free_all_queued(void) 3584cbf67842SDouglas Gilbert { 3585cbf67842SDouglas Gilbert int k; 3586cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3587cbf67842SDouglas Gilbert 3588cbf67842SDouglas Gilbert for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) { 3589cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 3590a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 3591a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 3592cbf67842SDouglas Gilbert } 35931da177e4SLinus Torvalds } 35941da177e4SLinus Torvalds 35951da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 35961da177e4SLinus Torvalds { 3597a10bc12aSDouglas Gilbert bool ok; 3598a10bc12aSDouglas Gilbert 35991da177e4SLinus Torvalds ++num_aborts; 3600cbf67842SDouglas Gilbert if (SCpnt) { 3601a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 3602a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3603a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3604a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 3605a10bc12aSDouglas Gilbert ok ? "" : " not"); 3606cbf67842SDouglas Gilbert } 36071da177e4SLinus Torvalds return SUCCESS; 36081da177e4SLinus Torvalds } 36091da177e4SLinus Torvalds 36101da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 36111da177e4SLinus Torvalds { 36121da177e4SLinus Torvalds ++num_dev_resets; 3613cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3614cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3615f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3616f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3617cbf67842SDouglas Gilbert 3618773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3619cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 36201da177e4SLinus Torvalds if (devip) 3621cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 36221da177e4SLinus Torvalds } 36231da177e4SLinus Torvalds return SUCCESS; 36241da177e4SLinus Torvalds } 36251da177e4SLinus Torvalds 3626cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3627cbf67842SDouglas Gilbert { 3628cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3629cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3630cbf67842SDouglas Gilbert struct scsi_device *sdp; 3631cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3632cbf67842SDouglas Gilbert int k = 0; 3633cbf67842SDouglas Gilbert 3634cbf67842SDouglas Gilbert ++num_target_resets; 3635cbf67842SDouglas Gilbert if (!SCpnt) 3636cbf67842SDouglas Gilbert goto lie; 3637cbf67842SDouglas Gilbert sdp = SCpnt->device; 3638cbf67842SDouglas Gilbert if (!sdp) 3639cbf67842SDouglas Gilbert goto lie; 3640773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3641cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3642cbf67842SDouglas Gilbert hp = sdp->host; 3643cbf67842SDouglas Gilbert if (!hp) 3644cbf67842SDouglas Gilbert goto lie; 3645cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3646cbf67842SDouglas Gilbert if (sdbg_host) { 3647cbf67842SDouglas Gilbert list_for_each_entry(devip, 3648cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3649cbf67842SDouglas Gilbert dev_list) 3650cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3651cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3652cbf67842SDouglas Gilbert ++k; 3653cbf67842SDouglas Gilbert } 3654cbf67842SDouglas Gilbert } 3655773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3656cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3657cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3658cbf67842SDouglas Gilbert lie: 3659cbf67842SDouglas Gilbert return SUCCESS; 3660cbf67842SDouglas Gilbert } 3661cbf67842SDouglas Gilbert 36621da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 36631da177e4SLinus Torvalds { 36641da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3665cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 36661da177e4SLinus Torvalds struct scsi_device * sdp; 36671da177e4SLinus Torvalds struct Scsi_Host * hp; 3668cbf67842SDouglas Gilbert int k = 0; 36691da177e4SLinus Torvalds 36701da177e4SLinus Torvalds ++num_bus_resets; 3671cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3672cbf67842SDouglas Gilbert goto lie; 3673cbf67842SDouglas Gilbert sdp = SCpnt->device; 3674773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3675cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3676cbf67842SDouglas Gilbert hp = sdp->host; 3677cbf67842SDouglas Gilbert if (hp) { 3678d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 36791da177e4SLinus Torvalds if (sdbg_host) { 3680cbf67842SDouglas Gilbert list_for_each_entry(devip, 36811da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3682cbf67842SDouglas Gilbert dev_list) { 3683cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3684cbf67842SDouglas Gilbert ++k; 36851da177e4SLinus Torvalds } 36861da177e4SLinus Torvalds } 3687cbf67842SDouglas Gilbert } 3688773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3689cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3690cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3691cbf67842SDouglas Gilbert lie: 36921da177e4SLinus Torvalds return SUCCESS; 36931da177e4SLinus Torvalds } 36941da177e4SLinus Torvalds 36951da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 36961da177e4SLinus Torvalds { 36971da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3698cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3699cbf67842SDouglas Gilbert int k = 0; 37001da177e4SLinus Torvalds 37011da177e4SLinus Torvalds ++num_host_resets; 3702773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3703cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 37041da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 37051da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3706cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3707cbf67842SDouglas Gilbert dev_list) { 3708cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3709cbf67842SDouglas Gilbert ++k; 3710cbf67842SDouglas Gilbert } 37111da177e4SLinus Torvalds } 37121da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 37131da177e4SLinus Torvalds stop_all_queued(); 3714773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3715cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3716cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 37171da177e4SLinus Torvalds return SUCCESS; 37181da177e4SLinus Torvalds } 37191da177e4SLinus Torvalds 3720f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 37215f2578e5SFUJITA Tomonori unsigned long store_size) 37221da177e4SLinus Torvalds { 37231da177e4SLinus Torvalds struct partition * pp; 37241da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 37251da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 37261da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 37271da177e4SLinus Torvalds 37281da177e4SLinus Torvalds /* assume partition table already zeroed */ 3729773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 37301da177e4SLinus Torvalds return; 3731773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 3732773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 3733c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 37341da177e4SLinus Torvalds } 3735c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 37361da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 3737773642d9SDouglas Gilbert / sdebug_num_parts; 37381da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 37391da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 3740773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 37411da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 37421da177e4SLinus Torvalds * heads_by_sects; 3743773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 3744773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 37451da177e4SLinus Torvalds 37461da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 37471da177e4SLinus Torvalds ramp[511] = 0xAA; 37481da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 37491da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 37501da177e4SLinus Torvalds start_sec = starts[k]; 37511da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 37521da177e4SLinus Torvalds pp->boot_ind = 0; 37531da177e4SLinus Torvalds 37541da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 37551da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 37561da177e4SLinus Torvalds / sdebug_sectors_per; 37571da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 37581da177e4SLinus Torvalds 37591da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 37601da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 37611da177e4SLinus Torvalds / sdebug_sectors_per; 37621da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 37631da177e4SLinus Torvalds 3764150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3765150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 37661da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 37671da177e4SLinus Torvalds } 37681da177e4SLinus Torvalds } 37691da177e4SLinus Torvalds 3770fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 3771cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 37721da177e4SLinus Torvalds { 3773cbf67842SDouglas Gilbert unsigned long iflags; 3774cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 3775cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp = NULL; 3776299b6c07STomas Winkler struct scsi_device *sdp; 3777a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 37781da177e4SLinus Torvalds 3779f46eb0e9SDouglas Gilbert if (unlikely(WARN_ON(!cmnd))) 3780299b6c07STomas Winkler return SCSI_MLQUEUE_HOST_BUSY; 3781299b6c07STomas Winkler 3782f46eb0e9SDouglas Gilbert if (unlikely(NULL == devip)) { 3783f46eb0e9SDouglas Gilbert if (0 == scsi_result) 3784f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 3785f46eb0e9SDouglas Gilbert goto respond_in_thread; 37861da177e4SLinus Torvalds } 3787299b6c07STomas Winkler 3788299b6c07STomas Winkler sdp = cmnd->device; 3789299b6c07STomas Winkler 3790f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && scsi_result)) 3791cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 3792cbf67842SDouglas Gilbert __func__, scsi_result); 3793cd62b7daSDouglas Gilbert if (delta_jiff == 0) 3794cd62b7daSDouglas Gilbert goto respond_in_thread; 37951da177e4SLinus Torvalds 3796cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 37971da177e4SLinus Torvalds spin_lock_irqsave(&queued_arr_lock, iflags); 3798cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 3799cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 3800cbf67842SDouglas Gilbert inject = 0; 3801f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 3802cd62b7daSDouglas Gilbert if (scsi_result) { 3803cd62b7daSDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 3804cd62b7daSDouglas Gilbert goto respond_in_thread; 3805cd62b7daSDouglas Gilbert } else 3806cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3807f46eb0e9SDouglas Gilbert } else if (unlikely((sdebug_every_nth != 0) && 3808773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 3809f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 3810cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 3811cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 3812773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 3813cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3814cbf67842SDouglas Gilbert inject = 1; 3815cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 38161da177e4SLinus Torvalds } 3817cbf67842SDouglas Gilbert } 3818cbf67842SDouglas Gilbert 3819773642d9SDouglas Gilbert k = find_first_zero_bit(queued_in_use_bm, sdebug_max_queue); 3820f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 38211da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3822cd62b7daSDouglas Gilbert if (scsi_result) 3823cd62b7daSDouglas Gilbert goto respond_in_thread; 3824773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 3825cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 3826773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 3827cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3828cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 3829773642d9SDouglas Gilbert __func__, sdebug_max_queue, 3830cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 3831cbf67842SDouglas Gilbert "report: host busy")); 3832cd62b7daSDouglas Gilbert if (scsi_result) 3833cd62b7daSDouglas Gilbert goto respond_in_thread; 3834cd62b7daSDouglas Gilbert else 3835cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 38361da177e4SLinus Torvalds } 3837cbf67842SDouglas Gilbert __set_bit(k, queued_in_use_bm); 3838cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 3839cbf67842SDouglas Gilbert sqcp = &queued_arr[k]; 38401da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 3841cbf67842SDouglas Gilbert cmnd->result = scsi_result; 38421da177e4SLinus Torvalds spin_unlock_irqrestore(&queued_arr_lock, iflags); 3843a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3844b333a819SDouglas Gilbert if ((delta_jiff > 0) || (sdebug_ndelay > 0)) { 3845b333a819SDouglas Gilbert ktime_t kt; 3846cbf67842SDouglas Gilbert 3847b333a819SDouglas Gilbert if (delta_jiff > 0) { 3848b333a819SDouglas Gilbert struct timespec ts; 3849b333a819SDouglas Gilbert 3850b333a819SDouglas Gilbert jiffies_to_timespec(delta_jiff, &ts); 3851b333a819SDouglas Gilbert kt = ktime_set(ts.tv_sec, ts.tv_nsec); 3852b333a819SDouglas Gilbert } else 3853b333a819SDouglas Gilbert kt = ktime_set(0, sdebug_ndelay); 3854a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 3855a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 3856a10bc12aSDouglas Gilbert if (NULL == sd_dp) 3857cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3858a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 3859a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 3860cbf67842SDouglas Gilbert HRTIMER_MODE_REL); 3861a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 3862a10bc12aSDouglas Gilbert sd_dp->qa_indx = k; 3863cbf67842SDouglas Gilbert } 3864a10bc12aSDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL); 3865c2206098SDouglas Gilbert } else { /* jdelay < 0 */ 3866a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 3867a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); 3868a10bc12aSDouglas Gilbert if (NULL == sd_dp) 3869cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 3870a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 3871a10bc12aSDouglas Gilbert sd_dp->qa_indx = k; 3872a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 3873cbf67842SDouglas Gilbert } 3874a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 3875cbf67842SDouglas Gilbert } 3876f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 3877f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 3878cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3879cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 3880cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 3881cbf67842SDouglas Gilbert "status: TASK SET FULL"); 38821da177e4SLinus Torvalds return 0; 3883cd62b7daSDouglas Gilbert 3884cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 3885cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 3886cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 3887cd62b7daSDouglas Gilbert return 0; 38881da177e4SLinus Torvalds } 3889cbf67842SDouglas Gilbert 389023183910SDouglas Gilbert /* Note: The following macros create attribute files in the 389123183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 389223183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 389323183910SDouglas Gilbert as it can when the corresponding attribute in the 389423183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 389523183910SDouglas Gilbert */ 3896773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 3897773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 3898773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 3899c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 3900773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 3901773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 3902773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 3903773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 3904773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 3905773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 3906773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 3907773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 3908773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 3909773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 3910773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 3911773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 3912773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 3913773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 3914773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 3915773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 3916773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 3917773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 3918773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 3919773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 3920773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 3921773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 3922773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 3923773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 3924773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 3925773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 3926773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 3927773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 3928773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 3929773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 3930773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 3931773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 3932773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 3933773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 393423183910SDouglas Gilbert S_IRUGO | S_IWUSR); 3935773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 39365b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 39371da177e4SLinus Torvalds 39381da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 39391da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 39401da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 39411da177e4SLinus Torvalds MODULE_VERSION(SCSI_DEBUG_VERSION); 39421da177e4SLinus Torvalds 39431da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 39445b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 39450759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 3946cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 3947c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 39485b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 39495b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 3950c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 3951beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 395223183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 39535b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 3954185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 39555b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 39565b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 39575b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 3958be1dd78dSEric Sandeen MODULE_PARM_DESC(lbprz, "unmapped blocks return 0 on read (def=1)"); 39595b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 3960c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 3961cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 3962cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 3963c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 396478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 39651da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 3966c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 396732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 39686f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 39695b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 39701da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 3971d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 3972e46b0344SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])"); 3973ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 3974c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 39755b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 39765b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 39776014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 39786014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 3979c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 39805b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 39815b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 39821da177e4SLinus Torvalds 39831da177e4SLinus Torvalds static char sdebug_info[256]; 39841da177e4SLinus Torvalds 39851da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 39861da177e4SLinus Torvalds { 39871da177e4SLinus Torvalds sprintf(sdebug_info, "scsi_debug, version %s [%s], " 39881da177e4SLinus Torvalds "dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION, 3989773642d9SDouglas Gilbert sdebug_version_date, sdebug_dev_size_mb, sdebug_opts); 39901da177e4SLinus Torvalds return sdebug_info; 39911da177e4SLinus Torvalds } 39921da177e4SLinus Torvalds 3993cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 3994fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 3995fd32119bSDouglas Gilbert int length) 39961da177e4SLinus Torvalds { 39971da177e4SLinus Torvalds char arr[16]; 3998c8ed555aSAl Viro int opts; 39991da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 40001da177e4SLinus Torvalds 40011da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 40021da177e4SLinus Torvalds return -EACCES; 40031da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 40041da177e4SLinus Torvalds arr[minLen] = '\0'; 4005c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 40061da177e4SLinus Torvalds return -EINVAL; 4007773642d9SDouglas Gilbert sdebug_opts = opts; 4008773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4009773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4010773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4011cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 40121da177e4SLinus Torvalds return length; 40131da177e4SLinus Torvalds } 4014c8ed555aSAl Viro 4015cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4016cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4017cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4018c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4019c8ed555aSAl Viro { 4020cbf67842SDouglas Gilbert int f, l; 4021cbf67842SDouglas Gilbert char b[32]; 4022cbf67842SDouglas Gilbert 4023773642d9SDouglas Gilbert if (sdebug_every_nth > 0) 4024cbf67842SDouglas Gilbert snprintf(b, sizeof(b), " (curr:%d)", 4025773642d9SDouglas Gilbert ((SDEBUG_OPT_RARE_TSF & sdebug_opts) ? 4026cbf67842SDouglas Gilbert atomic_read(&sdebug_a_tsf) : 4027cbf67842SDouglas Gilbert atomic_read(&sdebug_cmnd_count))); 4028cbf67842SDouglas Gilbert else 4029cbf67842SDouglas Gilbert b[0] = '\0'; 4030cbf67842SDouglas Gilbert 4031cbf67842SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n" 40321da177e4SLinus Torvalds "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, " 4033cbf67842SDouglas Gilbert "every_nth=%d%s\n" 4034cbf67842SDouglas Gilbert "delay=%d, ndelay=%d, max_luns=%d, q_completions=%d\n" 40351da177e4SLinus Torvalds "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n" 4036cbf67842SDouglas Gilbert "command aborts=%d; RESETs: device=%d, target=%d, bus=%d, " 4037cbf67842SDouglas Gilbert "host=%d\ndix_reads=%d dix_writes=%d dif_errors=%d " 4038cbf67842SDouglas Gilbert "usec_in_jiffy=%lu\n", 4039773642d9SDouglas Gilbert SCSI_DEBUG_VERSION, sdebug_version_date, 4040773642d9SDouglas Gilbert sdebug_num_tgts, sdebug_dev_size_mb, sdebug_opts, 4041c2206098SDouglas Gilbert sdebug_every_nth, b, sdebug_jdelay, sdebug_ndelay, 4042773642d9SDouglas Gilbert sdebug_max_luns, atomic_read(&sdebug_completions), 4043773642d9SDouglas Gilbert sdebug_sector_size, sdebug_cylinders_per, sdebug_heads, 4044cbf67842SDouglas Gilbert sdebug_sectors_per, num_aborts, num_dev_resets, 4045cbf67842SDouglas Gilbert num_target_resets, num_bus_resets, num_host_resets, 4046cbf67842SDouglas Gilbert dix_reads, dix_writes, dif_errors, TICK_NSEC / 1000); 4047cbf67842SDouglas Gilbert 4048773642d9SDouglas Gilbert f = find_first_bit(queued_in_use_bm, sdebug_max_queue); 4049773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4050773642d9SDouglas Gilbert l = find_last_bit(queued_in_use_bm, sdebug_max_queue); 4051cbf67842SDouglas Gilbert seq_printf(m, " %s BUSY: first,last bits set: %d,%d\n", 4052cbf67842SDouglas Gilbert "queued_in_use_bm", f, l); 4053cbf67842SDouglas Gilbert } 4054c8ed555aSAl Viro return 0; 40551da177e4SLinus Torvalds } 40561da177e4SLinus Torvalds 405782069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 40581da177e4SLinus Torvalds { 4059c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 40601da177e4SLinus Torvalds } 4061c2206098SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued */ 406282069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 406382069379SAkinobu Mita size_t count) 40641da177e4SLinus Torvalds { 4065c2206098SDouglas Gilbert int jdelay, res; 40661da177e4SLinus Torvalds 4067c2206098SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &jdelay))) { 4068cbf67842SDouglas Gilbert res = count; 4069c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4070cbf67842SDouglas Gilbert unsigned long iflags; 4071cbf67842SDouglas Gilbert int k; 4072cbf67842SDouglas Gilbert 4073cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4074773642d9SDouglas Gilbert k = find_first_bit(queued_in_use_bm, sdebug_max_queue); 4075773642d9SDouglas Gilbert if (k != sdebug_max_queue) 4076cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4077cbf67842SDouglas Gilbert else { 4078a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4079a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4080a10bc12aSDouglas Gilbert free_all_queued(); 4081c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4082773642d9SDouglas Gilbert sdebug_ndelay = 0; 40831da177e4SLinus Torvalds } 4084cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4085cbf67842SDouglas Gilbert } 4086cbf67842SDouglas Gilbert return res; 40871da177e4SLinus Torvalds } 40881da177e4SLinus Torvalds return -EINVAL; 40891da177e4SLinus Torvalds } 409082069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 40911da177e4SLinus Torvalds 4092cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4093cbf67842SDouglas Gilbert { 4094773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4095cbf67842SDouglas Gilbert } 4096cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4097c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4098cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4099cbf67842SDouglas Gilbert size_t count) 4100cbf67842SDouglas Gilbert { 4101cbf67842SDouglas Gilbert unsigned long iflags; 4102cbf67842SDouglas Gilbert int ndelay, res, k; 4103cbf67842SDouglas Gilbert 4104cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4105cbf67842SDouglas Gilbert (ndelay >= 0) && (ndelay < 1000000000)) { 4106cbf67842SDouglas Gilbert res = count; 4107773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4108cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4109773642d9SDouglas Gilbert k = find_first_bit(queued_in_use_bm, sdebug_max_queue); 4110773642d9SDouglas Gilbert if (k != sdebug_max_queue) 4111cbf67842SDouglas Gilbert res = -EBUSY; /* have queued commands */ 4112cbf67842SDouglas Gilbert else { 4113a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4114a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4115a10bc12aSDouglas Gilbert free_all_queued(); 4116773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4117c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4118c2206098SDouglas Gilbert : DEF_JDELAY; 4119cbf67842SDouglas Gilbert } 4120cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4121cbf67842SDouglas Gilbert } 4122cbf67842SDouglas Gilbert return res; 4123cbf67842SDouglas Gilbert } 4124cbf67842SDouglas Gilbert return -EINVAL; 4125cbf67842SDouglas Gilbert } 4126cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4127cbf67842SDouglas Gilbert 412882069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 41291da177e4SLinus Torvalds { 4130773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 41311da177e4SLinus Torvalds } 41321da177e4SLinus Torvalds 413382069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 413482069379SAkinobu Mita size_t count) 41351da177e4SLinus Torvalds { 41361da177e4SLinus Torvalds int opts; 41371da177e4SLinus Torvalds char work[20]; 41381da177e4SLinus Torvalds 41391da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 414048a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 41411da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 41421da177e4SLinus Torvalds goto opts_done; 41431da177e4SLinus Torvalds } else { 41441da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 41451da177e4SLinus Torvalds goto opts_done; 41461da177e4SLinus Torvalds } 41471da177e4SLinus Torvalds } 41481da177e4SLinus Torvalds return -EINVAL; 41491da177e4SLinus Torvalds opts_done: 4150773642d9SDouglas Gilbert sdebug_opts = opts; 4151773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4152773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4153cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4154cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 41551da177e4SLinus Torvalds return count; 41561da177e4SLinus Torvalds } 415782069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 41581da177e4SLinus Torvalds 415982069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 41601da177e4SLinus Torvalds { 4161773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 41621da177e4SLinus Torvalds } 416382069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 416482069379SAkinobu Mita size_t count) 41651da177e4SLinus Torvalds { 41661da177e4SLinus Torvalds int n; 41671da177e4SLinus Torvalds 41681da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4169773642d9SDouglas Gilbert sdebug_ptype = n; 41701da177e4SLinus Torvalds return count; 41711da177e4SLinus Torvalds } 41721da177e4SLinus Torvalds return -EINVAL; 41731da177e4SLinus Torvalds } 417482069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 41751da177e4SLinus Torvalds 417682069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 41771da177e4SLinus Torvalds { 4178773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 41791da177e4SLinus Torvalds } 418082069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 418182069379SAkinobu Mita size_t count) 41821da177e4SLinus Torvalds { 41831da177e4SLinus Torvalds int n; 41841da177e4SLinus Torvalds 41851da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4186773642d9SDouglas Gilbert sdebug_dsense = n; 41871da177e4SLinus Torvalds return count; 41881da177e4SLinus Torvalds } 41891da177e4SLinus Torvalds return -EINVAL; 41901da177e4SLinus Torvalds } 419182069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 41921da177e4SLinus Torvalds 419382069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 419423183910SDouglas Gilbert { 4195773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 419623183910SDouglas Gilbert } 419782069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 419882069379SAkinobu Mita size_t count) 419923183910SDouglas Gilbert { 420023183910SDouglas Gilbert int n; 420123183910SDouglas Gilbert 420223183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4203cbf67842SDouglas Gilbert n = (n > 0); 4204773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 4205773642d9SDouglas Gilbert if (sdebug_fake_rw != n) { 4206cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4207cbf67842SDouglas Gilbert unsigned long sz = 4208773642d9SDouglas Gilbert (unsigned long)sdebug_dev_size_mb * 4209cbf67842SDouglas Gilbert 1048576; 4210cbf67842SDouglas Gilbert 4211cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4212cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4213c1287970STomas Winkler pr_err("out of memory, 9\n"); 4214cbf67842SDouglas Gilbert return -ENOMEM; 4215cbf67842SDouglas Gilbert } 4216cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4217cbf67842SDouglas Gilbert } 4218773642d9SDouglas Gilbert sdebug_fake_rw = n; 4219cbf67842SDouglas Gilbert } 422023183910SDouglas Gilbert return count; 422123183910SDouglas Gilbert } 422223183910SDouglas Gilbert return -EINVAL; 422323183910SDouglas Gilbert } 422482069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 422523183910SDouglas Gilbert 422682069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4227c65b1445SDouglas Gilbert { 4228773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 4229c65b1445SDouglas Gilbert } 423082069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 423182069379SAkinobu Mita size_t count) 4232c65b1445SDouglas Gilbert { 4233c65b1445SDouglas Gilbert int n; 4234c65b1445SDouglas Gilbert 4235c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4236773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 4237c65b1445SDouglas Gilbert return count; 4238c65b1445SDouglas Gilbert } 4239c65b1445SDouglas Gilbert return -EINVAL; 4240c65b1445SDouglas Gilbert } 424182069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4242c65b1445SDouglas Gilbert 424382069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 42441da177e4SLinus Torvalds { 4245773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 42461da177e4SLinus Torvalds } 424782069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 424882069379SAkinobu Mita size_t count) 42491da177e4SLinus Torvalds { 42501da177e4SLinus Torvalds int n; 42511da177e4SLinus Torvalds 42521da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4253773642d9SDouglas Gilbert sdebug_num_tgts = n; 42541da177e4SLinus Torvalds sdebug_max_tgts_luns(); 42551da177e4SLinus Torvalds return count; 42561da177e4SLinus Torvalds } 42571da177e4SLinus Torvalds return -EINVAL; 42581da177e4SLinus Torvalds } 425982069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 42601da177e4SLinus Torvalds 426182069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 42621da177e4SLinus Torvalds { 4263773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 42641da177e4SLinus Torvalds } 426582069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 42661da177e4SLinus Torvalds 426782069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 42681da177e4SLinus Torvalds { 4269773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 42701da177e4SLinus Torvalds } 427182069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 42721da177e4SLinus Torvalds 427382069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 42741da177e4SLinus Torvalds { 4275773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 42761da177e4SLinus Torvalds } 427782069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 427882069379SAkinobu Mita size_t count) 42791da177e4SLinus Torvalds { 42801da177e4SLinus Torvalds int nth; 42811da177e4SLinus Torvalds 42821da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 4283773642d9SDouglas Gilbert sdebug_every_nth = nth; 4284cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 42851da177e4SLinus Torvalds return count; 42861da177e4SLinus Torvalds } 42871da177e4SLinus Torvalds return -EINVAL; 42881da177e4SLinus Torvalds } 428982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 42901da177e4SLinus Torvalds 429182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 42921da177e4SLinus Torvalds { 4293773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 42941da177e4SLinus Torvalds } 429582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 429682069379SAkinobu Mita size_t count) 42971da177e4SLinus Torvalds { 42981da177e4SLinus Torvalds int n; 429919c8ead7SEwan D. Milne bool changed; 43001da177e4SLinus Torvalds 43011da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4302773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 4303773642d9SDouglas Gilbert sdebug_max_luns = n; 43041da177e4SLinus Torvalds sdebug_max_tgts_luns(); 4305773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 430619c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 430719c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 430819c8ead7SEwan D. Milne 430919c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 431019c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 431119c8ead7SEwan D. Milne host_list) { 431219c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 431319c8ead7SEwan D. Milne dev_list) { 431419c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 431519c8ead7SEwan D. Milne dp->uas_bm); 431619c8ead7SEwan D. Milne } 431719c8ead7SEwan D. Milne } 431819c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 431919c8ead7SEwan D. Milne } 43201da177e4SLinus Torvalds return count; 43211da177e4SLinus Torvalds } 43221da177e4SLinus Torvalds return -EINVAL; 43231da177e4SLinus Torvalds } 432482069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 43251da177e4SLinus Torvalds 432682069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 432778d4e5a0SDouglas Gilbert { 4328773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 432978d4e5a0SDouglas Gilbert } 4330cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4331cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 433282069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 433382069379SAkinobu Mita size_t count) 433478d4e5a0SDouglas Gilbert { 4335cbf67842SDouglas Gilbert unsigned long iflags; 4336cbf67842SDouglas Gilbert int n, k; 433778d4e5a0SDouglas Gilbert 433878d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 433978d4e5a0SDouglas Gilbert (n <= SCSI_DEBUG_CANQUEUE)) { 4340cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4341cbf67842SDouglas Gilbert k = find_last_bit(queued_in_use_bm, SCSI_DEBUG_CANQUEUE); 4342773642d9SDouglas Gilbert sdebug_max_queue = n; 4343cbf67842SDouglas Gilbert if (SCSI_DEBUG_CANQUEUE == k) 4344cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4345cbf67842SDouglas Gilbert else if (k >= n) 4346cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4347cbf67842SDouglas Gilbert else 4348cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4349cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 435078d4e5a0SDouglas Gilbert return count; 435178d4e5a0SDouglas Gilbert } 435278d4e5a0SDouglas Gilbert return -EINVAL; 435378d4e5a0SDouglas Gilbert } 435482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 435578d4e5a0SDouglas Gilbert 435682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 435778d4e5a0SDouglas Gilbert { 4358773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 435978d4e5a0SDouglas Gilbert } 436082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 436178d4e5a0SDouglas Gilbert 436282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 43631da177e4SLinus Torvalds { 4364773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 43651da177e4SLinus Torvalds } 436682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 43671da177e4SLinus Torvalds 436882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4369c65b1445SDouglas Gilbert { 4370773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 4371c65b1445SDouglas Gilbert } 437282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 437382069379SAkinobu Mita size_t count) 4374c65b1445SDouglas Gilbert { 4375c65b1445SDouglas Gilbert int n; 43760d01c5dfSDouglas Gilbert bool changed; 4377c65b1445SDouglas Gilbert 4378c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4379773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 4380773642d9SDouglas Gilbert sdebug_virtual_gb = n; 438128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 43820d01c5dfSDouglas Gilbert if (changed) { 43830d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 43840d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 438528898873SFUJITA Tomonori 43864bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 43870d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 43880d01c5dfSDouglas Gilbert host_list) { 43890d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 43900d01c5dfSDouglas Gilbert dev_list) { 43910d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 43920d01c5dfSDouglas Gilbert dp->uas_bm); 43930d01c5dfSDouglas Gilbert } 43940d01c5dfSDouglas Gilbert } 43954bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 43960d01c5dfSDouglas Gilbert } 4397c65b1445SDouglas Gilbert return count; 4398c65b1445SDouglas Gilbert } 4399c65b1445SDouglas Gilbert return -EINVAL; 4400c65b1445SDouglas Gilbert } 440182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4402c65b1445SDouglas Gilbert 440382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 44041da177e4SLinus Torvalds { 4405773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host); 44061da177e4SLinus Torvalds } 44071da177e4SLinus Torvalds 4408fd32119bSDouglas Gilbert static int sdebug_add_adapter(void); 4409fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void); 4410fd32119bSDouglas Gilbert 441182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 441282069379SAkinobu Mita size_t count) 44131da177e4SLinus Torvalds { 44141da177e4SLinus Torvalds int delta_hosts; 44151da177e4SLinus Torvalds 4416f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 44171da177e4SLinus Torvalds return -EINVAL; 44181da177e4SLinus Torvalds if (delta_hosts > 0) { 44191da177e4SLinus Torvalds do { 44201da177e4SLinus Torvalds sdebug_add_adapter(); 44211da177e4SLinus Torvalds } while (--delta_hosts); 44221da177e4SLinus Torvalds } else if (delta_hosts < 0) { 44231da177e4SLinus Torvalds do { 44241da177e4SLinus Torvalds sdebug_remove_adapter(); 44251da177e4SLinus Torvalds } while (++delta_hosts); 44261da177e4SLinus Torvalds } 44271da177e4SLinus Torvalds return count; 44281da177e4SLinus Torvalds } 442982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 44301da177e4SLinus Torvalds 443182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 443223183910SDouglas Gilbert { 4433773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 443423183910SDouglas Gilbert } 443582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 443682069379SAkinobu Mita size_t count) 443723183910SDouglas Gilbert { 443823183910SDouglas Gilbert int n; 443923183910SDouglas Gilbert 444023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4441773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 444223183910SDouglas Gilbert return count; 444323183910SDouglas Gilbert } 444423183910SDouglas Gilbert return -EINVAL; 444523183910SDouglas Gilbert } 444682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 444723183910SDouglas Gilbert 444882069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4449597136abSMartin K. Petersen { 4450773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 4451597136abSMartin K. Petersen } 445282069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4453597136abSMartin K. Petersen 445482069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4455c6a44287SMartin K. Petersen { 4456773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 4457c6a44287SMartin K. Petersen } 445882069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4459c6a44287SMartin K. Petersen 446082069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4461c6a44287SMartin K. Petersen { 4462773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 4463c6a44287SMartin K. Petersen } 446482069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4465c6a44287SMartin K. Petersen 446682069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4467c6a44287SMartin K. Petersen { 4468773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 4469c6a44287SMartin K. Petersen } 447082069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4471c6a44287SMartin K. Petersen 447282069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4473c6a44287SMartin K. Petersen { 4474773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 4475c6a44287SMartin K. Petersen } 447682069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4477c6a44287SMartin K. Petersen 447882069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 447944d92694SMartin K. Petersen { 448044d92694SMartin K. Petersen ssize_t count; 448144d92694SMartin K. Petersen 44825b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 448344d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 448444d92694SMartin K. Petersen sdebug_store_sectors); 448544d92694SMartin K. Petersen 4486c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4487c7badc90STejun Heo (int)map_size, map_storep); 448844d92694SMartin K. Petersen buf[count++] = '\n'; 4489c7badc90STejun Heo buf[count] = '\0'; 449044d92694SMartin K. Petersen 449144d92694SMartin K. Petersen return count; 449244d92694SMartin K. Petersen } 449382069379SAkinobu Mita static DRIVER_ATTR_RO(map); 449444d92694SMartin K. Petersen 449582069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4496d986788bSMartin Pitt { 4497773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 4498d986788bSMartin Pitt } 449982069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 450082069379SAkinobu Mita size_t count) 4501d986788bSMartin Pitt { 4502d986788bSMartin Pitt int n; 4503d986788bSMartin Pitt 4504d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4505773642d9SDouglas Gilbert sdebug_removable = (n > 0); 4506d986788bSMartin Pitt return count; 4507d986788bSMartin Pitt } 4508d986788bSMartin Pitt return -EINVAL; 4509d986788bSMartin Pitt } 451082069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4511d986788bSMartin Pitt 4512cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4513cbf67842SDouglas Gilbert { 4514773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 4515cbf67842SDouglas Gilbert } 4516185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 4517cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4518cbf67842SDouglas Gilbert size_t count) 4519cbf67842SDouglas Gilbert { 4520185dd232SDouglas Gilbert int n; 4521cbf67842SDouglas Gilbert 4522cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4523185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 4524185dd232SDouglas Gilbert return count; 4525cbf67842SDouglas Gilbert } 4526cbf67842SDouglas Gilbert return -EINVAL; 4527cbf67842SDouglas Gilbert } 4528cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4529cbf67842SDouglas Gilbert 4530c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4531c2248fc9SDouglas Gilbert { 4532773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 4533c2248fc9SDouglas Gilbert } 4534c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4535c2248fc9SDouglas Gilbert size_t count) 4536c2248fc9SDouglas Gilbert { 4537c2248fc9SDouglas Gilbert int n; 4538c2248fc9SDouglas Gilbert 4539c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4540773642d9SDouglas Gilbert sdebug_strict = (n > 0); 4541c2248fc9SDouglas Gilbert return count; 4542c2248fc9SDouglas Gilbert } 4543c2248fc9SDouglas Gilbert return -EINVAL; 4544c2248fc9SDouglas Gilbert } 4545c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4546c2248fc9SDouglas Gilbert 4547cbf67842SDouglas Gilbert 454882069379SAkinobu Mita /* Note: The following array creates attribute files in the 454923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 455023183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 455123183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 455223183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 455323183910SDouglas Gilbert */ 45546ecaff7fSRandy Dunlap 455582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 455682069379SAkinobu Mita &driver_attr_delay.attr, 455782069379SAkinobu Mita &driver_attr_opts.attr, 455882069379SAkinobu Mita &driver_attr_ptype.attr, 455982069379SAkinobu Mita &driver_attr_dsense.attr, 456082069379SAkinobu Mita &driver_attr_fake_rw.attr, 456182069379SAkinobu Mita &driver_attr_no_lun_0.attr, 456282069379SAkinobu Mita &driver_attr_num_tgts.attr, 456382069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 456482069379SAkinobu Mita &driver_attr_num_parts.attr, 456582069379SAkinobu Mita &driver_attr_every_nth.attr, 456682069379SAkinobu Mita &driver_attr_max_luns.attr, 456782069379SAkinobu Mita &driver_attr_max_queue.attr, 456882069379SAkinobu Mita &driver_attr_no_uld.attr, 456982069379SAkinobu Mita &driver_attr_scsi_level.attr, 457082069379SAkinobu Mita &driver_attr_virtual_gb.attr, 457182069379SAkinobu Mita &driver_attr_add_host.attr, 457282069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 457382069379SAkinobu Mita &driver_attr_sector_size.attr, 457482069379SAkinobu Mita &driver_attr_dix.attr, 457582069379SAkinobu Mita &driver_attr_dif.attr, 457682069379SAkinobu Mita &driver_attr_guard.attr, 457782069379SAkinobu Mita &driver_attr_ato.attr, 457882069379SAkinobu Mita &driver_attr_map.attr, 457982069379SAkinobu Mita &driver_attr_removable.attr, 4580cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4581cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4582c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 458382069379SAkinobu Mita NULL, 458482069379SAkinobu Mita }; 458582069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 45861da177e4SLinus Torvalds 458711ddcecaSAkinobu Mita static struct device *pseudo_primary; 45888dea0d02SFUJITA Tomonori 45891da177e4SLinus Torvalds static int __init scsi_debug_init(void) 45901da177e4SLinus Torvalds { 45915f2578e5SFUJITA Tomonori unsigned long sz; 45921da177e4SLinus Torvalds int host_to_add; 45931da177e4SLinus Torvalds int k; 45946ecaff7fSRandy Dunlap int ret; 45951da177e4SLinus Torvalds 4596cbf67842SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4597cbf67842SDouglas Gilbert atomic_set(&sdebug_completions, 0); 4598cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4599cbf67842SDouglas Gilbert 4600773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 4601c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 4602773642d9SDouglas Gilbert sdebug_ndelay = 0; 4603773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 4604c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 4605cbf67842SDouglas Gilbert 4606773642d9SDouglas Gilbert switch (sdebug_sector_size) { 4607597136abSMartin K. Petersen case 512: 4608597136abSMartin K. Petersen case 1024: 4609597136abSMartin K. Petersen case 2048: 4610597136abSMartin K. Petersen case 4096: 4611597136abSMartin K. Petersen break; 4612597136abSMartin K. Petersen default: 4613773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 4614597136abSMartin K. Petersen return -EINVAL; 4615597136abSMartin K. Petersen } 4616597136abSMartin K. Petersen 4617773642d9SDouglas Gilbert switch (sdebug_dif) { 4618c6a44287SMartin K. Petersen 4619c6a44287SMartin K. Petersen case SD_DIF_TYPE0_PROTECTION: 4620f46eb0e9SDouglas Gilbert break; 4621c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 4622395cef03SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 4623c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 4624f46eb0e9SDouglas Gilbert have_dif_prot = true; 4625c6a44287SMartin K. Petersen break; 4626c6a44287SMartin K. Petersen 4627c6a44287SMartin K. Petersen default: 4628c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 4629c6a44287SMartin K. Petersen return -EINVAL; 4630c6a44287SMartin K. Petersen } 4631c6a44287SMartin K. Petersen 4632773642d9SDouglas Gilbert if (sdebug_guard > 1) { 4633c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 4634c6a44287SMartin K. Petersen return -EINVAL; 4635c6a44287SMartin K. Petersen } 4636c6a44287SMartin K. Petersen 4637773642d9SDouglas Gilbert if (sdebug_ato > 1) { 4638c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 4639c6a44287SMartin K. Petersen return -EINVAL; 4640c6a44287SMartin K. Petersen } 4641c6a44287SMartin K. Petersen 4642773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 4643773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 4644ea61fca5SMartin K. Petersen return -EINVAL; 4645ea61fca5SMartin K. Petersen } 4646ea61fca5SMartin K. Petersen 4647773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 4648773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 4649ea61fca5SMartin K. Petersen return -EINVAL; 4650ea61fca5SMartin K. Petersen } 4651ea61fca5SMartin K. Petersen 4652773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 4653773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 4654773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 4655773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 465628898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 46571da177e4SLinus Torvalds 46581da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 46591da177e4SLinus Torvalds sdebug_heads = 8; 46601da177e4SLinus Torvalds sdebug_sectors_per = 32; 4661773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 46621da177e4SLinus Torvalds sdebug_heads = 64; 4663773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 4664fa785f0aSAndy Shevchenko sdebug_heads = 32; 46651da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 46661da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 46671da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 46681da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 46691da177e4SLinus Torvalds sdebug_heads = 255; 46701da177e4SLinus Torvalds sdebug_sectors_per = 63; 46711da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 46721da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 46731da177e4SLinus Torvalds } 46741da177e4SLinus Torvalds 4675773642d9SDouglas Gilbert if (0 == sdebug_fake_rw) { 46761da177e4SLinus Torvalds fake_storep = vmalloc(sz); 46771da177e4SLinus Torvalds if (NULL == fake_storep) { 4678c1287970STomas Winkler pr_err("out of memory, 1\n"); 46791da177e4SLinus Torvalds return -ENOMEM; 46801da177e4SLinus Torvalds } 46811da177e4SLinus Torvalds memset(fake_storep, 0, sz); 4682773642d9SDouglas Gilbert if (sdebug_num_parts > 0) 4683f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 4684cbf67842SDouglas Gilbert } 46851da177e4SLinus Torvalds 4686773642d9SDouglas Gilbert if (sdebug_dix) { 4687c6a44287SMartin K. Petersen int dif_size; 4688c6a44287SMartin K. Petersen 4689c6a44287SMartin K. Petersen dif_size = sdebug_store_sectors * sizeof(struct sd_dif_tuple); 4690c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 4691c6a44287SMartin K. Petersen 4692c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 4693c6a44287SMartin K. Petersen 4694c6a44287SMartin K. Petersen if (dif_storep == NULL) { 4695c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 4696c6a44287SMartin K. Petersen ret = -ENOMEM; 4697c6a44287SMartin K. Petersen goto free_vm; 4698c6a44287SMartin K. Petersen } 4699c6a44287SMartin K. Petersen 4700c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 4701c6a44287SMartin K. Petersen } 4702c6a44287SMartin K. Petersen 47035b94e232SMartin K. Petersen /* Logical Block Provisioning */ 47045b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 4705773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 4706773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 47076014759cSMartin K. Petersen 4708773642d9SDouglas Gilbert sdebug_unmap_max_desc = 4709773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 47106014759cSMartin K. Petersen 4711773642d9SDouglas Gilbert sdebug_unmap_granularity = 4712773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 47136014759cSMartin K. Petersen 4714773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 4715773642d9SDouglas Gilbert sdebug_unmap_granularity <= 4716773642d9SDouglas Gilbert sdebug_unmap_alignment) { 4717c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 471844d92694SMartin K. Petersen return -EINVAL; 471944d92694SMartin K. Petersen } 472044d92694SMartin K. Petersen 4721b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 4722b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 472344d92694SMartin K. Petersen 4724c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 472544d92694SMartin K. Petersen 472644d92694SMartin K. Petersen if (map_storep == NULL) { 4727c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 472844d92694SMartin K. Petersen ret = -ENOMEM; 472944d92694SMartin K. Petersen goto free_vm; 473044d92694SMartin K. Petersen } 473144d92694SMartin K. Petersen 4732b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 473344d92694SMartin K. Petersen 473444d92694SMartin K. Petersen /* Map first 1KB for partition table */ 4735773642d9SDouglas Gilbert if (sdebug_num_parts) 473644d92694SMartin K. Petersen map_region(0, 2); 473744d92694SMartin K. Petersen } 473844d92694SMartin K. Petersen 47399b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 47409b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 4741c1287970STomas Winkler pr_warn("root_device_register() error\n"); 47429b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 47436ecaff7fSRandy Dunlap goto free_vm; 47446ecaff7fSRandy Dunlap } 47456ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 47466ecaff7fSRandy Dunlap if (ret < 0) { 4747c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 47486ecaff7fSRandy Dunlap goto dev_unreg; 47496ecaff7fSRandy Dunlap } 47506ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 47516ecaff7fSRandy Dunlap if (ret < 0) { 4752c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 47536ecaff7fSRandy Dunlap goto bus_unreg; 47546ecaff7fSRandy Dunlap } 47551da177e4SLinus Torvalds 4756773642d9SDouglas Gilbert host_to_add = sdebug_add_host; 4757773642d9SDouglas Gilbert sdebug_add_host = 0; 47581da177e4SLinus Torvalds 47591da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 47601da177e4SLinus Torvalds if (sdebug_add_adapter()) { 4761c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 47621da177e4SLinus Torvalds break; 47631da177e4SLinus Torvalds } 47641da177e4SLinus Torvalds } 47651da177e4SLinus Torvalds 4766773642d9SDouglas Gilbert if (sdebug_verbose) 4767773642d9SDouglas Gilbert pr_info("built %d host(s)\n", sdebug_add_host); 4768c1287970STomas Winkler 47691da177e4SLinus Torvalds return 0; 47706ecaff7fSRandy Dunlap 47716ecaff7fSRandy Dunlap bus_unreg: 47726ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 47736ecaff7fSRandy Dunlap dev_unreg: 47749b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 47756ecaff7fSRandy Dunlap free_vm: 477644d92694SMartin K. Petersen vfree(map_storep); 4777c6a44287SMartin K. Petersen vfree(dif_storep); 47786ecaff7fSRandy Dunlap vfree(fake_storep); 47796ecaff7fSRandy Dunlap 47806ecaff7fSRandy Dunlap return ret; 47811da177e4SLinus Torvalds } 47821da177e4SLinus Torvalds 47831da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 47841da177e4SLinus Torvalds { 4785773642d9SDouglas Gilbert int k = sdebug_add_host; 47861da177e4SLinus Torvalds 47871da177e4SLinus Torvalds stop_all_queued(); 4788cbf67842SDouglas Gilbert free_all_queued(); 47891da177e4SLinus Torvalds for (; k; k--) 47901da177e4SLinus Torvalds sdebug_remove_adapter(); 47911da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 47921da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 47939b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 47941da177e4SLinus Torvalds 4795c6a44287SMartin K. Petersen vfree(dif_storep); 47961da177e4SLinus Torvalds vfree(fake_storep); 47971da177e4SLinus Torvalds } 47981da177e4SLinus Torvalds 47991da177e4SLinus Torvalds device_initcall(scsi_debug_init); 48001da177e4SLinus Torvalds module_exit(scsi_debug_exit); 48011da177e4SLinus Torvalds 48021da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 48031da177e4SLinus Torvalds { 48041da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 48051da177e4SLinus Torvalds 48061da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 48071da177e4SLinus Torvalds kfree(sdbg_host); 48081da177e4SLinus Torvalds } 48091da177e4SLinus Torvalds 48101da177e4SLinus Torvalds static int sdebug_add_adapter(void) 48111da177e4SLinus Torvalds { 48121da177e4SLinus Torvalds int k, devs_per_host; 48131da177e4SLinus Torvalds int error = 0; 48141da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 48158b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 48161da177e4SLinus Torvalds 481724669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 48181da177e4SLinus Torvalds if (NULL == sdbg_host) { 4819c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 48201da177e4SLinus Torvalds return -ENOMEM; 48211da177e4SLinus Torvalds } 48221da177e4SLinus Torvalds 48231da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 48241da177e4SLinus Torvalds 4825773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 48261da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 48275cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 48285cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 4829c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 48301da177e4SLinus Torvalds error = -ENOMEM; 48311da177e4SLinus Torvalds goto clean; 48321da177e4SLinus Torvalds } 48331da177e4SLinus Torvalds } 48341da177e4SLinus Torvalds 48351da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 48361da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 48371da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 48381da177e4SLinus Torvalds 48391da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 48409b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 48411da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 4842773642d9SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host); 48431da177e4SLinus Torvalds 48441da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 48451da177e4SLinus Torvalds 48461da177e4SLinus Torvalds if (error) 48471da177e4SLinus Torvalds goto clean; 48481da177e4SLinus Torvalds 4849773642d9SDouglas Gilbert ++sdebug_add_host; 48501da177e4SLinus Torvalds return error; 48511da177e4SLinus Torvalds 48521da177e4SLinus Torvalds clean: 48538b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 48548b40228fSFUJITA Tomonori dev_list) { 48551da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 48561da177e4SLinus Torvalds kfree(sdbg_devinfo); 48571da177e4SLinus Torvalds } 48581da177e4SLinus Torvalds 48591da177e4SLinus Torvalds kfree(sdbg_host); 48601da177e4SLinus Torvalds return error; 48611da177e4SLinus Torvalds } 48621da177e4SLinus Torvalds 48631da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 48641da177e4SLinus Torvalds { 48651da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 48661da177e4SLinus Torvalds 48671da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 48681da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 48691da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 48701da177e4SLinus Torvalds struct sdebug_host_info, host_list); 48711da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 48721da177e4SLinus Torvalds } 48731da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 48741da177e4SLinus Torvalds 48751da177e4SLinus Torvalds if (!sdbg_host) 48761da177e4SLinus Torvalds return; 48771da177e4SLinus Torvalds 48781da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 4879773642d9SDouglas Gilbert --sdebug_add_host; 48801da177e4SLinus Torvalds } 48811da177e4SLinus Torvalds 4882fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 4883cbf67842SDouglas Gilbert { 4884cbf67842SDouglas Gilbert int num_in_q = 0; 4885cbf67842SDouglas Gilbert unsigned long iflags; 4886cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 4887cbf67842SDouglas Gilbert 4888cbf67842SDouglas Gilbert spin_lock_irqsave(&queued_arr_lock, iflags); 4889cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 4890cbf67842SDouglas Gilbert if (NULL == devip) { 4891cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4892cbf67842SDouglas Gilbert return -ENODEV; 4893cbf67842SDouglas Gilbert } 4894cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 4895cbf67842SDouglas Gilbert spin_unlock_irqrestore(&queued_arr_lock, iflags); 4896c40ecc12SChristoph Hellwig 4897cbf67842SDouglas Gilbert if (qdepth < 1) 4898cbf67842SDouglas Gilbert qdepth = 1; 4899cbf67842SDouglas Gilbert /* allow to exceed max host queued_arr elements for testing */ 4900cbf67842SDouglas Gilbert if (qdepth > SCSI_DEBUG_CANQUEUE + 10) 4901cbf67842SDouglas Gilbert qdepth = SCSI_DEBUG_CANQUEUE + 10; 4902db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 4903cbf67842SDouglas Gilbert 4904773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 4905cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdev, 4906c40ecc12SChristoph Hellwig "%s: qdepth=%d, num_in_q=%d\n", 4907c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 4908cbf67842SDouglas Gilbert } 4909cbf67842SDouglas Gilbert return sdev->queue_depth; 4910cbf67842SDouglas Gilbert } 4911cbf67842SDouglas Gilbert 4912fd32119bSDouglas Gilbert static int check_inject(struct scsi_cmnd *scp) 4913817fd66bSDouglas Gilbert { 4914817fd66bSDouglas Gilbert struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp); 4915817fd66bSDouglas Gilbert 4916817fd66bSDouglas Gilbert memset(ep, 0, sizeof(struct sdebug_scmd_extra_t)); 4917817fd66bSDouglas Gilbert 4918773642d9SDouglas Gilbert if (atomic_inc_return(&sdebug_cmnd_count) >= abs(sdebug_every_nth)) { 4919817fd66bSDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4920773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 4921773642d9SDouglas Gilbert sdebug_every_nth = -1; 4922773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 4923817fd66bSDouglas Gilbert return 1; /* ignore command causing timeout */ 4924773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 4925817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 4926817fd66bSDouglas Gilbert return 1; /* time out reads and writes */ 4927817fd66bSDouglas Gilbert if (sdebug_any_injecting_opt) { 4928773642d9SDouglas Gilbert if (SDEBUG_OPT_RECOVERED_ERR & sdebug_opts) 4929817fd66bSDouglas Gilbert ep->inj_recovered = true; 4930773642d9SDouglas Gilbert if (SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts) 4931817fd66bSDouglas Gilbert ep->inj_transport = true; 4932773642d9SDouglas Gilbert if (SDEBUG_OPT_DIF_ERR & sdebug_opts) 4933817fd66bSDouglas Gilbert ep->inj_dif = true; 4934773642d9SDouglas Gilbert if (SDEBUG_OPT_DIX_ERR & sdebug_opts) 4935817fd66bSDouglas Gilbert ep->inj_dix = true; 4936773642d9SDouglas Gilbert if (SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts) 4937817fd66bSDouglas Gilbert ep->inj_short = true; 4938817fd66bSDouglas Gilbert } 4939817fd66bSDouglas Gilbert } 4940817fd66bSDouglas Gilbert return 0; 4941817fd66bSDouglas Gilbert } 4942817fd66bSDouglas Gilbert 4943fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 4944fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 4945c2248fc9SDouglas Gilbert { 4946c2248fc9SDouglas Gilbert u8 sdeb_i; 4947c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 4948c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 4949c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 4950c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 4951c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 4952c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 4953c2248fc9SDouglas Gilbert int k, na; 4954c2248fc9SDouglas Gilbert int errsts = 0; 4955c2248fc9SDouglas Gilbert u32 flags; 4956c2248fc9SDouglas Gilbert u16 sa; 4957c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 4958c2248fc9SDouglas Gilbert bool has_wlun_rl; 4959c2248fc9SDouglas Gilbert 4960c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 4961f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 4962f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 4963c2248fc9SDouglas Gilbert char b[120]; 4964c2248fc9SDouglas Gilbert int n, len, sb; 4965c2248fc9SDouglas Gilbert 4966c2248fc9SDouglas Gilbert len = scp->cmd_len; 4967c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 4968c2248fc9SDouglas Gilbert if (len > 32) 4969c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 4970c2248fc9SDouglas Gilbert else { 4971c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 4972c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 4973c2248fc9SDouglas Gilbert (u32)cmd[k]); 4974c2248fc9SDouglas Gilbert } 4975c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b); 4976c2248fc9SDouglas Gilbert } 497734d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 4978f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 4979f46eb0e9SDouglas Gilbert goto err_out; 4980c2248fc9SDouglas Gilbert 4981c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 4982c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 4983c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 4984f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 4985f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 4986c2248fc9SDouglas Gilbert if (NULL == devip) 4987f46eb0e9SDouglas Gilbert goto err_out; 4988c2248fc9SDouglas Gilbert } 4989c2248fc9SDouglas Gilbert na = oip->num_attached; 4990c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 4991c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 4992c2248fc9SDouglas Gilbert r_oip = oip; 4993c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 4994c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 4995c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 4996c2248fc9SDouglas Gilbert else 4997c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 4998c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 4999c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5000c2248fc9SDouglas Gilbert break; 5001c2248fc9SDouglas Gilbert } 5002c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5003c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5004c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5005c2248fc9SDouglas Gilbert break; 5006c2248fc9SDouglas Gilbert } 5007c2248fc9SDouglas Gilbert } 5008c2248fc9SDouglas Gilbert if (k > na) { 5009c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5010c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5011c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5012c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5013c2248fc9SDouglas Gilbert else 5014c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5015c2248fc9SDouglas Gilbert goto check_cond; 5016c2248fc9SDouglas Gilbert } 5017c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5018c2248fc9SDouglas Gilbert flags = oip->flags; 5019f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 5020c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5021c2248fc9SDouglas Gilbert goto check_cond; 5022c2248fc9SDouglas Gilbert } 5023f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 5024773642d9SDouglas Gilbert if (sdebug_verbose) 5025773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 5026773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 5027c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5028c2248fc9SDouglas Gilbert goto check_cond; 5029c2248fc9SDouglas Gilbert } 5030f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 5031c2248fc9SDouglas Gilbert u8 rem; 5032c2248fc9SDouglas Gilbert int j; 5033c2248fc9SDouglas Gilbert 5034c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5035c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5036c2248fc9SDouglas Gilbert if (rem) { 5037c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5038c2248fc9SDouglas Gilbert if (0x80 & rem) 5039c2248fc9SDouglas Gilbert break; 5040c2248fc9SDouglas Gilbert } 5041c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5042c2248fc9SDouglas Gilbert goto check_cond; 5043c2248fc9SDouglas Gilbert } 5044c2248fc9SDouglas Gilbert } 5045c2248fc9SDouglas Gilbert } 5046f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 5047f46eb0e9SDouglas Gilbert SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, 5048f46eb0e9SDouglas Gilbert SDEBUG_NUM_UAS))) { 5049f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 5050c2248fc9SDouglas Gilbert if (errsts) 5051c2248fc9SDouglas Gilbert goto check_cond; 5052c2248fc9SDouglas Gilbert } 5053f46eb0e9SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && devip->stopped)) { 5054c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5055773642d9SDouglas Gilbert if (sdebug_verbose) 5056c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5057c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5058c2248fc9SDouglas Gilbert "required"); 5059c2248fc9SDouglas Gilbert errsts = check_condition_result; 5060c2248fc9SDouglas Gilbert goto fini; 5061c2248fc9SDouglas Gilbert } 5062773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 5063c2248fc9SDouglas Gilbert goto fini; 5064f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 5065c2248fc9SDouglas Gilbert if (check_inject(scp)) 5066c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5067c2248fc9SDouglas Gilbert } 5068f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 5069f46eb0e9SDouglas Gilbert errsts = oip->pfp(scp, devip); /* calls a resp_* function */ 5070c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5071c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5072c2248fc9SDouglas Gilbert 5073c2248fc9SDouglas Gilbert fini: 5074c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5075c2206098SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay)); 5076c2248fc9SDouglas Gilbert check_cond: 5077c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5078f46eb0e9SDouglas Gilbert err_out: 5079f46eb0e9SDouglas Gilbert return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0); 5080c2248fc9SDouglas Gilbert } 5081c2248fc9SDouglas Gilbert 50829e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5083c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5084c8ed555aSAl Viro .write_info = scsi_debug_write_info, 50859e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 50869e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 50879e603ca0SFUJITA Tomonori .info = scsi_debug_info, 50889e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 50899e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 50909e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 50919e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5092185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 5093cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 50949e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 50959e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5096cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5097cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 50989e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 50999e603ca0SFUJITA Tomonori .can_queue = SCSI_DEBUG_CANQUEUE, 51009e603ca0SFUJITA Tomonori .this_id = 7, 510165e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 5102cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 51036bb5e6e7SAkinobu Mita .max_sectors = -1U, 51049e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 51059e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5106c40ecc12SChristoph Hellwig .track_queue_depth = 1, 5107817fd66bSDouglas Gilbert .cmd_size = sizeof(struct sdebug_scmd_extra_t), 51089e603ca0SFUJITA Tomonori }; 51099e603ca0SFUJITA Tomonori 51101da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 51111da177e4SLinus Torvalds { 51121da177e4SLinus Torvalds int error = 0; 51131da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51141da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5115f46eb0e9SDouglas Gilbert int hprot; 51161da177e4SLinus Torvalds 51171da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 51181da177e4SLinus Torvalds 5119773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 5120773642d9SDouglas Gilbert if (sdebug_clustering) 51210759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 51221da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 51231da177e4SLinus Torvalds if (NULL == hpnt) { 5124c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 51251da177e4SLinus Torvalds error = -ENODEV; 51261da177e4SLinus Torvalds return error; 51271da177e4SLinus Torvalds } 51281da177e4SLinus Torvalds 51291da177e4SLinus Torvalds sdbg_host->shost = hpnt; 51301da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 5131773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 5132773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 51331da177e4SLinus Torvalds else 5134773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 5135773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 5136f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 51371da177e4SLinus Torvalds 5138f46eb0e9SDouglas Gilbert hprot = 0; 5139c6a44287SMartin K. Petersen 5140773642d9SDouglas Gilbert switch (sdebug_dif) { 5141c6a44287SMartin K. Petersen 5142c6a44287SMartin K. Petersen case SD_DIF_TYPE1_PROTECTION: 5143f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 5144773642d9SDouglas Gilbert if (sdebug_dix) 5145f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 5146c6a44287SMartin K. Petersen break; 5147c6a44287SMartin K. Petersen 5148c6a44287SMartin K. Petersen case SD_DIF_TYPE2_PROTECTION: 5149f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 5150773642d9SDouglas Gilbert if (sdebug_dix) 5151f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 5152c6a44287SMartin K. Petersen break; 5153c6a44287SMartin K. Petersen 5154c6a44287SMartin K. Petersen case SD_DIF_TYPE3_PROTECTION: 5155f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 5156773642d9SDouglas Gilbert if (sdebug_dix) 5157f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 5158c6a44287SMartin K. Petersen break; 5159c6a44287SMartin K. Petersen 5160c6a44287SMartin K. Petersen default: 5161773642d9SDouglas Gilbert if (sdebug_dix) 5162f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 5163c6a44287SMartin K. Petersen break; 5164c6a44287SMartin K. Petersen } 5165c6a44287SMartin K. Petersen 5166f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 5167c6a44287SMartin K. Petersen 5168f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 5169c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5170f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5171f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5172f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5173f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5174f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5175f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5176f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5177c6a44287SMartin K. Petersen 5178773642d9SDouglas Gilbert if (sdebug_guard == 1) 5179c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5180c6a44287SMartin K. Petersen else 5181c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5182c6a44287SMartin K. Petersen 5183773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 5184773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 51851da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 51861da177e4SLinus Torvalds if (error) { 5187c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 51881da177e4SLinus Torvalds error = -ENODEV; 51891da177e4SLinus Torvalds scsi_host_put(hpnt); 51901da177e4SLinus Torvalds } else 51911da177e4SLinus Torvalds scsi_scan_host(hpnt); 51921da177e4SLinus Torvalds 51931da177e4SLinus Torvalds return error; 51941da177e4SLinus Torvalds } 51951da177e4SLinus Torvalds 51961da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 51971da177e4SLinus Torvalds { 51981da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51998b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 52001da177e4SLinus Torvalds 52011da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 52021da177e4SLinus Torvalds 52031da177e4SLinus Torvalds if (!sdbg_host) { 5204c1287970STomas Winkler pr_err("Unable to locate host info\n"); 52051da177e4SLinus Torvalds return -ENODEV; 52061da177e4SLinus Torvalds } 52071da177e4SLinus Torvalds 52081da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 52091da177e4SLinus Torvalds 52108b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 52118b40228fSFUJITA Tomonori dev_list) { 52121da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 52131da177e4SLinus Torvalds kfree(sdbg_devinfo); 52141da177e4SLinus Torvalds } 52151da177e4SLinus Torvalds 52161da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 52171da177e4SLinus Torvalds return 0; 52181da177e4SLinus Torvalds } 52191da177e4SLinus Torvalds 52208dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 52218dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 52221da177e4SLinus Torvalds { 52238dea0d02SFUJITA Tomonori return 1; 52248dea0d02SFUJITA Tomonori } 52251da177e4SLinus Torvalds 52268dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 52278dea0d02SFUJITA Tomonori .name = "pseudo", 52288dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 52298dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 52308dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 523182069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 52328dea0d02SFUJITA Tomonori }; 5233