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 * 99b760fd8SDouglas Gilbert * Copyright (C) 2001 - 2017 Douglas Gilbert 101da177e4SLinus Torvalds * 11773642d9SDouglas Gilbert * This program is free software; you can redistribute it and/or modify 12773642d9SDouglas Gilbert * it under the terms of the GNU General Public License as published by 13773642d9SDouglas Gilbert * the Free Software Foundation; either version 2, or (at your option) 14773642d9SDouglas Gilbert * any later version. 151da177e4SLinus Torvalds * 1678d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 20c1287970STomas Winkler 21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 22c1287970STomas Winkler 231da177e4SLinus Torvalds #include <linux/module.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/kernel.h> 261da177e4SLinus Torvalds #include <linux/errno.h> 27b333a819SDouglas Gilbert #include <linux/jiffies.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/string.h> 311da177e4SLinus Torvalds #include <linux/genhd.h> 321da177e4SLinus Torvalds #include <linux/fs.h> 331da177e4SLinus Torvalds #include <linux/init.h> 341da177e4SLinus Torvalds #include <linux/proc_fs.h> 351da177e4SLinus Torvalds #include <linux/vmalloc.h> 361da177e4SLinus Torvalds #include <linux/moduleparam.h> 37852e034dSJens Axboe #include <linux/scatterlist.h> 381da177e4SLinus Torvalds #include <linux/blkdev.h> 39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 40cbf67842SDouglas Gilbert #include <linux/spinlock.h> 41cbf67842SDouglas Gilbert #include <linux/interrupt.h> 42cbf67842SDouglas Gilbert #include <linux/atomic.h> 43cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 4409ba24c1SDouglas Gilbert #include <linux/uuid.h> 456ebf105cSChristoph Hellwig #include <linux/t10-pi.h> 46c6a44287SMartin K. Petersen 47c6a44287SMartin K. Petersen #include <net/checksum.h> 489ff26eefSFUJITA Tomonori 4944d92694SMartin K. Petersen #include <asm/unaligned.h> 5044d92694SMartin K. Petersen 519ff26eefSFUJITA Tomonori #include <scsi/scsi.h> 529ff26eefSFUJITA Tomonori #include <scsi/scsi_cmnd.h> 539ff26eefSFUJITA Tomonori #include <scsi/scsi_device.h> 541da177e4SLinus Torvalds #include <scsi/scsi_host.h> 551da177e4SLinus Torvalds #include <scsi/scsicam.h> 56a34c4e98SFUJITA Tomonori #include <scsi/scsi_eh.h> 57cbf67842SDouglas Gilbert #include <scsi/scsi_tcq.h> 58395cef03SMartin K. Petersen #include <scsi/scsi_dbg.h> 591da177e4SLinus Torvalds 60c6a44287SMartin K. Petersen #include "sd.h" 611da177e4SLinus Torvalds #include "scsi_logging.h" 621da177e4SLinus Torvalds 63773642d9SDouglas Gilbert /* make sure inq_product_rev string corresponds to this version */ 649b760fd8SDouglas Gilbert #define SDEBUG_VERSION "0187" /* format to fit INQUIRY revision field */ 659b760fd8SDouglas Gilbert static const char *sdebug_version_date = "20171202"; 66cbf67842SDouglas Gilbert 67cbf67842SDouglas Gilbert #define MY_NAME "scsi_debug" 681da177e4SLinus Torvalds 696f3cbf55SDouglas Gilbert /* Additional Sense Code (ASC) */ 70c65b1445SDouglas Gilbert #define NO_ADDITIONAL_SENSE 0x0 71c65b1445SDouglas Gilbert #define LOGICAL_UNIT_NOT_READY 0x4 72c2248fc9SDouglas Gilbert #define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8 731da177e4SLinus Torvalds #define UNRECOVERED_READ_ERR 0x11 74c65b1445SDouglas Gilbert #define PARAMETER_LIST_LENGTH_ERR 0x1a 751da177e4SLinus Torvalds #define INVALID_OPCODE 0x20 7622017ed2SDouglas Gilbert #define LBA_OUT_OF_RANGE 0x21 771da177e4SLinus Torvalds #define INVALID_FIELD_IN_CDB 0x24 78c65b1445SDouglas Gilbert #define INVALID_FIELD_IN_PARAM_LIST 0x26 79cbf67842SDouglas Gilbert #define UA_RESET_ASC 0x29 80cbf67842SDouglas Gilbert #define UA_CHANGED_ASC 0x2a 8119c8ead7SEwan D. Milne #define TARGET_CHANGED_ASC 0x3f 8219c8ead7SEwan D. Milne #define LUNS_CHANGED_ASCQ 0x0e 8322017ed2SDouglas Gilbert #define INSUFF_RES_ASC 0x55 8422017ed2SDouglas Gilbert #define INSUFF_RES_ASCQ 0x3 85cbf67842SDouglas Gilbert #define POWER_ON_RESET_ASCQ 0x0 86cbf67842SDouglas Gilbert #define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */ 87cbf67842SDouglas Gilbert #define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */ 8822017ed2SDouglas Gilbert #define CAPACITY_CHANGED_ASCQ 0x9 891da177e4SLinus Torvalds #define SAVING_PARAMS_UNSUP 0x39 906f3cbf55SDouglas Gilbert #define TRANSPORT_PROBLEM 0x4b 91c65b1445SDouglas Gilbert #define THRESHOLD_EXCEEDED 0x5d 92c65b1445SDouglas Gilbert #define LOW_POWER_COND_ON 0x5e 9322017ed2SDouglas Gilbert #define MISCOMPARE_VERIFY_ASC 0x1d 94acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */ 95acafd0b9SEwan D. Milne #define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16 961da177e4SLinus Torvalds 976f3cbf55SDouglas Gilbert /* Additional Sense Code Qualifier (ASCQ) */ 986f3cbf55SDouglas Gilbert #define ACK_NAK_TO 0x3 996f3cbf55SDouglas Gilbert 1001da177e4SLinus Torvalds /* Default values for driver parameters */ 1011da177e4SLinus Torvalds #define DEF_NUM_HOST 1 1021da177e4SLinus Torvalds #define DEF_NUM_TGTS 1 1031da177e4SLinus Torvalds #define DEF_MAX_LUNS 1 1041da177e4SLinus Torvalds /* With these defaults, this driver will make 1 host with 1 target 1051da177e4SLinus Torvalds * (id 0) containing 1 logical unit (lun 0). That is 1 device. 1061da177e4SLinus Torvalds */ 1075b94e232SMartin K. Petersen #define DEF_ATO 1 1089b760fd8SDouglas Gilbert #define DEF_CDB_LEN 10 109c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1101da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1115b94e232SMartin K. Petersen #define DEF_DIF 0 1125b94e232SMartin K. Petersen #define DEF_DIX 0 1135b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1141da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1155b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1165b94e232SMartin K. Petersen #define DEF_GUARD 0 117cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1185b94e232SMartin K. Petersen #define DEF_LBPU 0 1195b94e232SMartin K. Petersen #define DEF_LBPWS 0 1205b94e232SMartin K. Petersen #define DEF_LBPWS10 0 121be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1225b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 123cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1245b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1251da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1261da177e4SLinus Torvalds #define DEF_OPTS 0 12732c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1285b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 12986e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 130b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 131d986788bSMartin Pitt #define DEF_REMOVABLE false 132760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1335b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1345b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1355b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1366014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1376014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1385b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1395b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1405b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 141c2248fc9SDouglas Gilbert #define DEF_STRICT 0 142c4837394SDouglas Gilbert #define DEF_STATISTICS false 143c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 14409ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 145c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1461da177e4SLinus Torvalds 147b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 148b01f6f83SDouglas Gilbert 149773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 150773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 151773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 152773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 153773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 154773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 155773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 156773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 157773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 158773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 159773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 160773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 161773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 162773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 163773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 164773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 1657ee6d1b4SBart Van Assche #define SDEBUG_OPT_HOST_BUSY 0x8000 166773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 167773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 168773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 169773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 170773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 1717ee6d1b4SBart Van Assche SDEBUG_OPT_SHORT_TRANSFER | \ 1727ee6d1b4SBart Van Assche SDEBUG_OPT_HOST_BUSY) 1731da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 174fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1751da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 176773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1776f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 178773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1791da177e4SLinus Torvalds * 1801da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 181fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1821da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 183773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1846f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 185773642d9SDouglas Gilbert * commands if _DEBUG_OPT_TRANSPORT_ERR is set. 186773642d9SDouglas Gilbert * This will continue on every subsequent command until some other action 187773642d9SDouglas Gilbert * occurs (e.g. the user * writing a new value (other than -1 or 1) to 188773642d9SDouglas Gilbert * every_nth via sysfs). 1891da177e4SLinus Torvalds */ 1901da177e4SLinus Torvalds 191cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 192cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 193cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 194cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 195cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 196cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 197cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1980d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 19919c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 200acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 201acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 202acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 203cbf67842SDouglas Gilbert 204773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2051da177e4SLinus Torvalds * sector on read commands: */ 2061da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 20732f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2081da177e4SLinus Torvalds 2091da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2101da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2111da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2121da177e4SLinus Torvalds 213c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 214c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 215c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 216c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 217c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 218c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 219c4837394SDouglas Gilbert */ 220c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 221c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 222cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 223cbf67842SDouglas Gilbert 224fd32119bSDouglas Gilbert #define F_D_IN 1 225fd32119bSDouglas Gilbert #define F_D_OUT 2 226fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 227fd32119bSDouglas Gilbert #define F_D_UNKN 8 228fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 229fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 230fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 231fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 232fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 233fd32119bSDouglas Gilbert #define F_INV_OP 0x200 234fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 235fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 236fd32119bSDouglas Gilbert 237fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 238fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 239fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 240fd32119bSDouglas Gilbert 241fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 242fd32119bSDouglas Gilbert 243b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 244fd32119bSDouglas Gilbert 245fd32119bSDouglas Gilbert 246fd32119bSDouglas Gilbert struct sdebug_dev_info { 247fd32119bSDouglas Gilbert struct list_head dev_list; 248fd32119bSDouglas Gilbert unsigned int channel; 249fd32119bSDouglas Gilbert unsigned int target; 250fd32119bSDouglas Gilbert u64 lun; 251bf476433SChristoph Hellwig uuid_t lu_name; 252fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 253fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 254fd32119bSDouglas Gilbert atomic_t num_in_q; 255c4837394SDouglas Gilbert atomic_t stopped; 256fd32119bSDouglas Gilbert bool used; 257fd32119bSDouglas Gilbert }; 258fd32119bSDouglas Gilbert 259fd32119bSDouglas Gilbert struct sdebug_host_info { 260fd32119bSDouglas Gilbert struct list_head host_list; 261fd32119bSDouglas Gilbert struct Scsi_Host *shost; 262fd32119bSDouglas Gilbert struct device dev; 263fd32119bSDouglas Gilbert struct list_head dev_info_list; 264fd32119bSDouglas Gilbert }; 265fd32119bSDouglas Gilbert 266fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 267fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 268fd32119bSDouglas Gilbert 269fd32119bSDouglas Gilbert struct sdebug_defer { 270fd32119bSDouglas Gilbert struct hrtimer hrt; 271fd32119bSDouglas Gilbert struct execute_work ew; 272c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 273c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 274c4837394SDouglas Gilbert int issuing_cpu; 275fd32119bSDouglas Gilbert }; 276fd32119bSDouglas Gilbert 277fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 278c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 279c4837394SDouglas Gilbert * instance indicates this slot is in use. 280c4837394SDouglas Gilbert */ 281fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 282fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 283c4837394SDouglas Gilbert unsigned int inj_recovered:1; 284c4837394SDouglas Gilbert unsigned int inj_transport:1; 285c4837394SDouglas Gilbert unsigned int inj_dif:1; 286c4837394SDouglas Gilbert unsigned int inj_dix:1; 287c4837394SDouglas Gilbert unsigned int inj_short:1; 2887ee6d1b4SBart Van Assche unsigned int inj_host_busy:1; 289fd32119bSDouglas Gilbert }; 290fd32119bSDouglas Gilbert 291c4837394SDouglas Gilbert struct sdebug_queue { 292c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 293c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 294c4837394SDouglas Gilbert spinlock_t qc_lock; 295c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 296fd32119bSDouglas Gilbert }; 297fd32119bSDouglas Gilbert 298c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 299c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 300c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 301c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 302c4837394SDouglas Gilbert 303fd32119bSDouglas Gilbert struct opcode_info_t { 304b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 305b01f6f83SDouglas Gilbert /* for terminating element */ 306fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 307fd32119bSDouglas Gilbert u16 sa; /* service action */ 308fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 309fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 310fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 311fd32119bSDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 312fd32119bSDouglas Gilbert /* ignore cdb bytes after position 15 */ 313fd32119bSDouglas Gilbert }; 314fd32119bSDouglas Gilbert 315fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 316c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 317c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 318c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 319c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 320c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 321c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 322c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 323c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 324c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 325c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 326c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 327c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 328c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 329c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 330c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 331c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 332c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 333c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 334c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 335c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 336c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 337c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 338c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 339c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 340c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 341c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 342c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 343c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 344c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 345c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 346c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 347c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 348c2248fc9SDouglas Gilbert }; 349c2248fc9SDouglas Gilbert 350c4837394SDouglas Gilbert 351c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 352c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 353c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 354c2248fc9SDouglas Gilbert 0, 0, 0, 0, 355c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 356c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 357c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 358c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 359c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 360c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 361c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 362c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 363c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 364c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 365c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 366c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 367c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 368c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 369c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 370c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 371fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 372c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 373c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 374c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 375c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 376c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 377c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 378c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 379c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 380c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 381c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 382c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 383c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 384c2248fc9SDouglas Gilbert 0, 0, 0, 0, 385c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 386c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 387c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 388c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 389c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 390c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 391c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 392c2248fc9SDouglas Gilbert }; 393c2248fc9SDouglas Gilbert 394c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 395c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 396c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 397c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 398c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 399c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 400c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 401c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 402c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 403c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 404c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 405c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 406c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 407c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 40838d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 40938d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 410c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 411c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 412c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 41338d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 414acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 415c2248fc9SDouglas Gilbert 416c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 417c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 418c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 419c2248fc9SDouglas Gilbert }; 420c2248fc9SDouglas Gilbert 421c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 422c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 423c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 424c2248fc9SDouglas Gilbert }; 425c2248fc9SDouglas Gilbert 426c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 427c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 428c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 429c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 430c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 431c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 432c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 433c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 434c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 435c2248fc9SDouglas Gilbert }; 436c2248fc9SDouglas Gilbert 437c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 438c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 439c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 440c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 441c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 442c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 443c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 444c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 445c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 446c2248fc9SDouglas Gilbert }; 447c2248fc9SDouglas Gilbert 448c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 449c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 450c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 451c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 452c2248fc9SDouglas Gilbert }; 453c2248fc9SDouglas Gilbert 454c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 455c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 456c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 457c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 458c2248fc9SDouglas Gilbert }; 459c2248fc9SDouglas Gilbert 460c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 46138d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 462c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 463c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 46438d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 465c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 466c2248fc9SDouglas Gilbert 0, 0} }, 467c2248fc9SDouglas Gilbert }; 468c2248fc9SDouglas Gilbert 469c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 470c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 471c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 472c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 473c2248fc9SDouglas Gilbert }; 474c2248fc9SDouglas Gilbert 475c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 476c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 477c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 478c2248fc9SDouglas Gilbert }; 479c2248fc9SDouglas Gilbert 480c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 481c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 482c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 483c2248fc9SDouglas Gilbert }; 484c2248fc9SDouglas Gilbert 485c2248fc9SDouglas Gilbert 486c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 487c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 488c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 489c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 490c2248fc9SDouglas Gilbert /* 0 */ 491c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 492c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 493c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 494c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 495c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 496c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 497c2248fc9SDouglas Gilbert 0, 0} }, 498c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 499c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 500c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 501c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 502c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 503c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 504c2248fc9SDouglas Gilbert 0} }, 505c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 506c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 507c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 508c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 509c2248fc9SDouglas Gilbert 0, 0, 0} }, 510c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 511c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 512c2248fc9SDouglas Gilbert 0, 0} }, 513c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 514c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 515c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 516c2248fc9SDouglas Gilbert /* 10 */ 517c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 518c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 519c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 520c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 521c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 522c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 523c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 524c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 525c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 526c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 527c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 528c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 529c2248fc9SDouglas Gilbert 0} }, 530c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 531c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 532f7f9f26bSDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ 533f7f9f26bSDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 534f7f9f26bSDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 535c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 536c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 537c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 538c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 539c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 540c2248fc9SDouglas Gilbert 0} }, 541c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 542c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 543c2248fc9SDouglas Gilbert 0} }, 544c2248fc9SDouglas Gilbert /* 20 */ 545f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 546f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 547c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 548c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 549c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 550c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 551c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 552c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 553c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 554c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 555c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 556c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 557c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 558acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 559acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 560acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 561c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 562c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 563c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 564c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 565c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 566c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 56738d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 568c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 569c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 570c2248fc9SDouglas Gilbert 571c2248fc9SDouglas Gilbert /* 30 */ 572c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 573c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 574c2248fc9SDouglas Gilbert }; 575c2248fc9SDouglas Gilbert 576773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; 577773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 5789b760fd8SDouglas Gilbert static int sdebug_cdb_len = DEF_CDB_LEN; 579c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 580773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 581773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 582773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 583773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 584773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 585773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 586773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 587773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 588773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 589c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 590cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 591c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 592773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 593773642d9SDouglas Gilbert static int sdebug_no_uld; 594773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 595773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 596773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 597773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 598773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 59986e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 600b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 601773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 602773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 603773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 604773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 605773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 606773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 607773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 608773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 609773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 610773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 611773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 612773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 613773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 61409ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 615773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 616773642d9SDouglas Gilbert static bool sdebug_clustering; 617773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 618773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 619817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 620773642d9SDouglas Gilbert static bool sdebug_verbose; 621f46eb0e9SDouglas Gilbert static bool have_dif_prot; 622c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 623c4837394SDouglas Gilbert static bool sdebug_mq_active; 6241da177e4SLinus Torvalds 625c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 6261da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 6291da177e4SLinus Torvalds may still need them */ 6301da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 6311da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 6321da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 6331da177e4SLinus Torvalds 6341da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 6351da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 6361da177e4SLinus Torvalds 6371da177e4SLinus Torvalds static unsigned char *fake_storep; /* ramdisk storage */ 6386ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep; /* protection info */ 63944d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6401da177e4SLinus Torvalds 64144d92694SMartin K. Petersen static unsigned long map_size; 642cbf67842SDouglas Gilbert static int num_aborts; 643cbf67842SDouglas Gilbert static int num_dev_resets; 644cbf67842SDouglas Gilbert static int num_target_resets; 645cbf67842SDouglas Gilbert static int num_bus_resets; 646cbf67842SDouglas Gilbert static int num_host_resets; 647c6a44287SMartin K. Petersen static int dix_writes; 648c6a44287SMartin K. Petersen static int dix_reads; 649c6a44287SMartin K. Petersen static int dif_errors; 6501da177e4SLinus Torvalds 651c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 652c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 653fd32119bSDouglas Gilbert 6541da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6551da177e4SLinus Torvalds 656cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 657cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6621da177e4SLinus Torvalds .name = sdebug_proc_name, 6631da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6641da177e4SLinus Torvalds }; 6651da177e4SLinus Torvalds 6661da177e4SLinus Torvalds static const int check_condition_result = 6671da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6681da177e4SLinus Torvalds 669c6a44287SMartin K. Petersen static const int illegal_condition_result = 670c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 671c6a44287SMartin K. Petersen 672cbf67842SDouglas Gilbert static const int device_qfull_result = 673cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 674cbf67842SDouglas Gilbert 675fd32119bSDouglas Gilbert 676760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 677760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 678760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 679760f3b03SDouglas Gilbert */ 680760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 681fd32119bSDouglas Gilbert { 682fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 683fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 684fd32119bSDouglas Gilbert } 685c65b1445SDouglas Gilbert 68614faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 68714faa944SAkinobu Mita { 68814faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 68914faa944SAkinobu Mita 690773642d9SDouglas Gilbert return fake_storep + lba * sdebug_sector_size; 69114faa944SAkinobu Mita } 69214faa944SAkinobu Mita 6936ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector) 69414faa944SAkinobu Mita { 69549413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 69614faa944SAkinobu Mita 69714faa944SAkinobu Mita return dif_storep + sector; 69814faa944SAkinobu Mita } 69914faa944SAkinobu Mita 7008dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 7018dea0d02SFUJITA Tomonori { 7028dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 7038dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 7048dea0d02SFUJITA Tomonori 7058dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 7068dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 7078dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 7088dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 709773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 710773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 7118dea0d02SFUJITA Tomonori else 712773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 713773642d9SDouglas Gilbert /* sdebug_max_luns; */ 714f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 7158dea0d02SFUJITA Tomonori } 7168dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 7178dea0d02SFUJITA Tomonori } 7188dea0d02SFUJITA Tomonori 71922017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 72022017ed2SDouglas Gilbert 72122017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 722fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 723fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 72422017ed2SDouglas Gilbert int in_byte, int in_bit) 72522017ed2SDouglas Gilbert { 72622017ed2SDouglas Gilbert unsigned char *sbuff; 72722017ed2SDouglas Gilbert u8 sks[4]; 72822017ed2SDouglas Gilbert int sl, asc; 72922017ed2SDouglas Gilbert 73022017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 73122017ed2SDouglas Gilbert if (!sbuff) { 73222017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 73322017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 73422017ed2SDouglas Gilbert return; 73522017ed2SDouglas Gilbert } 73622017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 73722017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 738773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 73922017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 74022017ed2SDouglas Gilbert sks[0] = 0x80; 74122017ed2SDouglas Gilbert if (c_d) 74222017ed2SDouglas Gilbert sks[0] |= 0x40; 74322017ed2SDouglas Gilbert if (in_bit >= 0) { 74422017ed2SDouglas Gilbert sks[0] |= 0x8; 74522017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 74622017ed2SDouglas Gilbert } 74722017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 748773642d9SDouglas Gilbert if (sdebug_dsense) { 74922017ed2SDouglas Gilbert sl = sbuff[7] + 8; 75022017ed2SDouglas Gilbert sbuff[7] = sl; 75122017ed2SDouglas Gilbert sbuff[sl] = 0x2; 75222017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 75322017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 75422017ed2SDouglas Gilbert } else 75522017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 756773642d9SDouglas Gilbert if (sdebug_verbose) 75722017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 75822017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 75922017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 76022017ed2SDouglas Gilbert } 76122017ed2SDouglas Gilbert 762cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7638dea0d02SFUJITA Tomonori { 7648dea0d02SFUJITA Tomonori unsigned char *sbuff; 7658dea0d02SFUJITA Tomonori 766cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 767cbf67842SDouglas Gilbert if (!sbuff) { 768cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 769cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 770cbf67842SDouglas Gilbert return; 771cbf67842SDouglas Gilbert } 772cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7738dea0d02SFUJITA Tomonori 774773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 7758dea0d02SFUJITA Tomonori 776773642d9SDouglas Gilbert if (sdebug_verbose) 777cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 778cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 779cbf67842SDouglas Gilbert my_name, key, asc, asq); 7808dea0d02SFUJITA Tomonori } 7811da177e4SLinus Torvalds 782fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 78322017ed2SDouglas Gilbert { 78422017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 78522017ed2SDouglas Gilbert } 78622017ed2SDouglas Gilbert 7871da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7881da177e4SLinus Torvalds { 789773642d9SDouglas Gilbert if (sdebug_verbose) { 790cbf67842SDouglas Gilbert if (0x1261 == cmd) 791cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 792cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 793cbf67842SDouglas Gilbert else if (0x5331 == cmd) 794cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 795cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 796cbf67842SDouglas Gilbert __func__); 797cbf67842SDouglas Gilbert else 798cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 799cbf67842SDouglas Gilbert __func__, cmd); 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds return -EINVAL; 8021da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 8031da177e4SLinus Torvalds } 8041da177e4SLinus Torvalds 8059b760fd8SDouglas Gilbert static void config_cdb_len(struct scsi_device *sdev) 8069b760fd8SDouglas Gilbert { 8079b760fd8SDouglas Gilbert switch (sdebug_cdb_len) { 8089b760fd8SDouglas Gilbert case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */ 8099b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 8109b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 8119b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 8129b760fd8SDouglas Gilbert break; 8139b760fd8SDouglas Gilbert case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */ 8149b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 8159b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 8169b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 8179b760fd8SDouglas Gilbert break; 8189b760fd8SDouglas Gilbert case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */ 8199b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 8209b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 8219b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 8229b760fd8SDouglas Gilbert break; 8239b760fd8SDouglas Gilbert case 16: 8249b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 8259b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 8269b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 8279b760fd8SDouglas Gilbert break; 8289b760fd8SDouglas Gilbert case 32: /* No knobs to suggest this so same as 16 for now */ 8299b760fd8SDouglas Gilbert sdev->use_10_for_rw = false; 8309b760fd8SDouglas Gilbert sdev->use_16_for_rw = true; 8319b760fd8SDouglas Gilbert sdev->use_10_for_ms = true; 8329b760fd8SDouglas Gilbert break; 8339b760fd8SDouglas Gilbert default: 8349b760fd8SDouglas Gilbert pr_warn("unexpected cdb_len=%d, force to 10\n", 8359b760fd8SDouglas Gilbert sdebug_cdb_len); 8369b760fd8SDouglas Gilbert sdev->use_10_for_rw = true; 8379b760fd8SDouglas Gilbert sdev->use_16_for_rw = false; 8389b760fd8SDouglas Gilbert sdev->use_10_for_ms = false; 8399b760fd8SDouglas Gilbert sdebug_cdb_len = 10; 8409b760fd8SDouglas Gilbert break; 8419b760fd8SDouglas Gilbert } 8429b760fd8SDouglas Gilbert } 8439b760fd8SDouglas Gilbert 8449b760fd8SDouglas Gilbert static void all_config_cdb_len(void) 8459b760fd8SDouglas Gilbert { 8469b760fd8SDouglas Gilbert struct sdebug_host_info *sdbg_host; 8479b760fd8SDouglas Gilbert struct Scsi_Host *shost; 8489b760fd8SDouglas Gilbert struct scsi_device *sdev; 8499b760fd8SDouglas Gilbert 8509b760fd8SDouglas Gilbert spin_lock(&sdebug_host_list_lock); 8519b760fd8SDouglas Gilbert list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 8529b760fd8SDouglas Gilbert shost = sdbg_host->shost; 8539b760fd8SDouglas Gilbert shost_for_each_device(sdev, shost) { 8549b760fd8SDouglas Gilbert config_cdb_len(sdev); 8559b760fd8SDouglas Gilbert } 8569b760fd8SDouglas Gilbert } 8579b760fd8SDouglas Gilbert spin_unlock(&sdebug_host_list_lock); 8589b760fd8SDouglas Gilbert } 8599b760fd8SDouglas Gilbert 86019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 86119c8ead7SEwan D. Milne { 86219c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 86319c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 86419c8ead7SEwan D. Milne 86519c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 86619c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 86719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 86819c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 86919c8ead7SEwan D. Milne (devip->target == dp->target)) 87019c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 87119c8ead7SEwan D. Milne } 87219c8ead7SEwan D. Milne } 87319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 87419c8ead7SEwan D. Milne } 87519c8ead7SEwan D. Milne 876f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 8771da177e4SLinus Torvalds { 878cbf67842SDouglas Gilbert int k; 879cbf67842SDouglas Gilbert 880cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 881cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 882cbf67842SDouglas Gilbert const char *cp = NULL; 883cbf67842SDouglas Gilbert 884cbf67842SDouglas Gilbert switch (k) { 885cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 886f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 887f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 888773642d9SDouglas Gilbert if (sdebug_verbose) 889cbf67842SDouglas Gilbert cp = "power on reset"; 890cbf67842SDouglas Gilbert break; 891cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 892f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 893f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 894773642d9SDouglas Gilbert if (sdebug_verbose) 895cbf67842SDouglas Gilbert cp = "bus reset"; 896cbf67842SDouglas Gilbert break; 897cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 898f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 899f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 900773642d9SDouglas Gilbert if (sdebug_verbose) 901cbf67842SDouglas Gilbert cp = "mode parameters changed"; 902cbf67842SDouglas Gilbert break; 9030d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 904f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 905f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 906773642d9SDouglas Gilbert if (sdebug_verbose) 9070d01c5dfSDouglas Gilbert cp = "capacity data changed"; 908f49accf1SEwan D. Milne break; 909acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 910f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 911b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 912b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 913773642d9SDouglas Gilbert if (sdebug_verbose) 914acafd0b9SEwan D. Milne cp = "microcode has been changed"; 915acafd0b9SEwan D. Milne break; 916acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 917f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 918acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 919acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 920773642d9SDouglas Gilbert if (sdebug_verbose) 921acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 922acafd0b9SEwan D. Milne break; 92319c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 92419c8ead7SEwan D. Milne /* 92519c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 92619c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 92719c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 92819c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 929773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 93019c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 93119c8ead7SEwan D. Milne */ 932773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 93319c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 934f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 93519c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 93619c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 937773642d9SDouglas Gilbert if (sdebug_verbose) 93819c8ead7SEwan D. Milne cp = "reported luns data has changed"; 93919c8ead7SEwan D. Milne break; 940cbf67842SDouglas Gilbert default: 941773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 942773642d9SDouglas Gilbert if (sdebug_verbose) 943cbf67842SDouglas Gilbert cp = "unknown"; 944cbf67842SDouglas Gilbert break; 945cbf67842SDouglas Gilbert } 946cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 947773642d9SDouglas Gilbert if (sdebug_verbose) 948f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 949cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 950cbf67842SDouglas Gilbert my_name, cp); 9511da177e4SLinus Torvalds return check_condition_result; 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds return 0; 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 956fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 9571da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 9581da177e4SLinus Torvalds int arr_len) 9591da177e4SLinus Torvalds { 96021a61829SFUJITA Tomonori int act_len; 961072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 9621da177e4SLinus Torvalds 963072d0bb3SFUJITA Tomonori if (!sdb->length) 9641da177e4SLinus Torvalds return 0; 965072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 966773642d9SDouglas Gilbert return DID_ERROR << 16; 96721a61829SFUJITA Tomonori 96821a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 96921a61829SFUJITA Tomonori arr, arr_len); 97021a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 97121a61829SFUJITA Tomonori 9721da177e4SLinus Torvalds return 0; 9731da177e4SLinus Torvalds } 9741da177e4SLinus Torvalds 975fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 976fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 977fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 978fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 979fb0cc8d1SDouglas Gilbert */ 980fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 981fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 982fb0cc8d1SDouglas Gilbert { 983fb0cc8d1SDouglas Gilbert int act_len, n; 984fb0cc8d1SDouglas Gilbert struct scsi_data_buffer *sdb = scsi_in(scp); 985fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 986fb0cc8d1SDouglas Gilbert 987fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 988fb0cc8d1SDouglas Gilbert return 0; 989fb0cc8d1SDouglas Gilbert if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 990fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 991fb0cc8d1SDouglas Gilbert 992fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 993fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 994fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 995fb0cc8d1SDouglas Gilbert __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid); 996fb0cc8d1SDouglas Gilbert n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len); 997fb0cc8d1SDouglas Gilbert sdb->resid = min(sdb->resid, n); 998fb0cc8d1SDouglas Gilbert return 0; 999fb0cc8d1SDouglas Gilbert } 1000fb0cc8d1SDouglas Gilbert 1001fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 1002fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 1003fb0cc8d1SDouglas Gilbert */ 10041da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 100521a61829SFUJITA Tomonori int arr_len) 10061da177e4SLinus Torvalds { 100721a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 10081da177e4SLinus Torvalds return 0; 1009072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 10101da177e4SLinus Torvalds return -1; 101121a61829SFUJITA Tomonori 101221a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 10131da177e4SLinus Torvalds } 10141da177e4SLinus Torvalds 10151da177e4SLinus Torvalds 1016e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 1017e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 10189b760fd8SDouglas Gilbert static char sdebug_inq_product_rev[5] = SDEBUG_VERSION; 10191b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 10201b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 10211b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 10221b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 10231da177e4SLinus Torvalds 1024cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 1025760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 10265a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 102709ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 1028bf476433SChristoph Hellwig const uuid_t *lu_name) 10291da177e4SLinus Torvalds { 1030c65b1445SDouglas Gilbert int num, port_a; 1031c65b1445SDouglas Gilbert char b[32]; 10321da177e4SLinus Torvalds 1033c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 10341da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 10351da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 10361da177e4SLinus Torvalds arr[1] = 0x1; 10371da177e4SLinus Torvalds arr[2] = 0x0; 1038e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 1039e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 10401da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 10411da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 10421da177e4SLinus Torvalds arr[3] = num; 10431da177e4SLinus Torvalds num += 4; 1044c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 104509ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 104609ba24c1SDouglas Gilbert /* Locally assigned UUID */ 104709ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 104809ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 104909ba24c1SDouglas Gilbert arr[num++] = 0x0; 105009ba24c1SDouglas Gilbert arr[num++] = 0x12; 105109ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 105209ba24c1SDouglas Gilbert arr[num++] = 0x0; 105309ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 105409ba24c1SDouglas Gilbert num += 16; 105509ba24c1SDouglas Gilbert } else { 10561b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 1057c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 1058c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 1059c65b1445SDouglas Gilbert arr[num++] = 0x0; 1060c65b1445SDouglas Gilbert arr[num++] = 0x8; 10611b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1062773642d9SDouglas Gilbert num += 8; 106309ba24c1SDouglas Gilbert } 1064c65b1445SDouglas Gilbert /* Target relative port number */ 1065c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1066c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1067c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1068c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1069c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1070c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1071c65b1445SDouglas Gilbert arr[num++] = 0x0; 1072c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1073c65b1445SDouglas Gilbert } 10741b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1075c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1076c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1077c65b1445SDouglas Gilbert arr[num++] = 0x0; 1078c65b1445SDouglas Gilbert arr[num++] = 0x8; 10791b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1080773642d9SDouglas Gilbert num += 8; 10811b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 10825a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 10835a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 10845a09e398SHannes Reinecke arr[num++] = 0x0; 10855a09e398SHannes Reinecke arr[num++] = 0x4; 10865a09e398SHannes Reinecke arr[num++] = 0; 10875a09e398SHannes Reinecke arr[num++] = 0; 1088773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1089773642d9SDouglas Gilbert num += 2; 10901b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1091c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1092c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1093c65b1445SDouglas Gilbert arr[num++] = 0x0; 1094c65b1445SDouglas Gilbert arr[num++] = 0x8; 10951b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1096773642d9SDouglas Gilbert num += 8; 1097c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1098c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1099c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1100c65b1445SDouglas Gilbert arr[num++] = 0x0; 1101c65b1445SDouglas Gilbert arr[num++] = 24; 11021b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1103c65b1445SDouglas Gilbert num += 12; 1104c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1105c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1106c65b1445SDouglas Gilbert num += 8; 1107c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1108c65b1445SDouglas Gilbert num += 4; 1109c65b1445SDouglas Gilbert return num; 1110c65b1445SDouglas Gilbert } 1111c65b1445SDouglas Gilbert 1112c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1113c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1114c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1115c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1116c65b1445SDouglas Gilbert }; 1117c65b1445SDouglas Gilbert 1118cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1119760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1120c65b1445SDouglas Gilbert { 1121c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1122c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1123c65b1445SDouglas Gilbert } 1124c65b1445SDouglas Gilbert 1125cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1126760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1127c65b1445SDouglas Gilbert { 1128c65b1445SDouglas Gilbert int num = 0; 1129c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1130c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1131c65b1445SDouglas Gilbert int plen, olen; 1132c65b1445SDouglas Gilbert 1133c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1134c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1135c65b1445SDouglas Gilbert arr[num++] = 0x0; 1136c65b1445SDouglas Gilbert olen = strlen(na1); 1137c65b1445SDouglas Gilbert plen = olen + 1; 1138c65b1445SDouglas Gilbert if (plen % 4) 1139c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1140c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1141c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1142c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1143c65b1445SDouglas Gilbert num += plen; 1144c65b1445SDouglas Gilbert 1145c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1146c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1147c65b1445SDouglas Gilbert arr[num++] = 0x0; 1148c65b1445SDouglas Gilbert olen = strlen(na2); 1149c65b1445SDouglas Gilbert plen = olen + 1; 1150c65b1445SDouglas Gilbert if (plen % 4) 1151c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1152c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1153c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1154c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1155c65b1445SDouglas Gilbert num += plen; 1156c65b1445SDouglas Gilbert 1157c65b1445SDouglas Gilbert return num; 1158c65b1445SDouglas Gilbert } 1159c65b1445SDouglas Gilbert 1160c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1161760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1162c65b1445SDouglas Gilbert { 1163c65b1445SDouglas Gilbert int num = 0; 1164c65b1445SDouglas Gilbert int port_a, port_b; 1165c65b1445SDouglas Gilbert 1166c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1167c65b1445SDouglas Gilbert port_b = port_a + 1; 1168c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1169c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1170c65b1445SDouglas Gilbert arr[num++] = 0x0; 1171c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1172c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1173c65b1445SDouglas Gilbert num += 6; 1174c65b1445SDouglas Gilbert arr[num++] = 0x0; 1175c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1176c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1177c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1178c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1179c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1180c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 11811b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1182773642d9SDouglas Gilbert num += 8; 1183c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1184c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1185c65b1445SDouglas Gilbert arr[num++] = 0x0; 1186c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1187c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1188c65b1445SDouglas Gilbert num += 6; 1189c65b1445SDouglas Gilbert arr[num++] = 0x0; 1190c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1191c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1192c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1193c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1194c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1195c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 11961b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1197773642d9SDouglas Gilbert num += 8; 1198c65b1445SDouglas Gilbert 1199c65b1445SDouglas Gilbert return num; 1200c65b1445SDouglas Gilbert } 1201c65b1445SDouglas Gilbert 1202c65b1445SDouglas Gilbert 1203c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1204c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1205c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1206c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1207c65b1445SDouglas Gilbert '1','2','3','4', 1208c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1209c65b1445SDouglas Gilbert 0xec,0,0,0, 1210c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1211c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1212c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1213c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1214c65b1445SDouglas Gilbert 0x53,0x41, 1215c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1216c65b1445SDouglas Gilbert 0x20,0x20, 1217c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1218c65b1445SDouglas Gilbert 0x10,0x80, 1219c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1220c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1221c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1222c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1223c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1224c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1225c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1226c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1227c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1228c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1229c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1230c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1231c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1232c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1233c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1234c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1235c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1236c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1237c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1238c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1239c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1240c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1241c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1242c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1243c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1244c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1245c65b1445SDouglas Gilbert }; 1246c65b1445SDouglas Gilbert 1247cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1248760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1249c65b1445SDouglas Gilbert { 1250c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1251c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1252c65b1445SDouglas Gilbert } 1253c65b1445SDouglas Gilbert 1254c65b1445SDouglas Gilbert 1255c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 12561e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 12571e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12581e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 12591e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1260c65b1445SDouglas Gilbert }; 1261c65b1445SDouglas Gilbert 1262cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1263760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1264c65b1445SDouglas Gilbert { 1265ea61fca5SMartin K. Petersen unsigned int gran; 1266ea61fca5SMartin K. Petersen 1267c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1268e308b3d1SMartin K. Petersen 1269e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 127086e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 127186e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 127286e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 127386e6828aSLukas Herbolt else 1274773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1275773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1276e308b3d1SMartin K. Petersen 1277e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1278773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1279773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 128044d92694SMartin K. Petersen 1281e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1282773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1283e308b3d1SMartin K. Petersen 1284773642d9SDouglas Gilbert if (sdebug_lbpu) { 1285e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1286773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1287e308b3d1SMartin K. Petersen 1288e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1289773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 129044d92694SMartin K. Petersen } 129144d92694SMartin K. Petersen 1292e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1293773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1294773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 129544d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 129644d92694SMartin K. Petersen } 129744d92694SMartin K. Petersen 1298e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1299773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 13006014759cSMartin K. Petersen 13015b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1302773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 13035b94e232SMartin K. Petersen 13045b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 130544d92694SMartin K. Petersen 1306c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 13071da177e4SLinus Torvalds } 13081da177e4SLinus Torvalds 13091e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1310760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1311eac6e8e4SMatthew Wilcox { 1312eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1313eac6e8e4SMatthew Wilcox arr[0] = 0; 13141e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 13151e49f785SDouglas Gilbert arr[2] = 0; 13161e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1317eac6e8e4SMatthew Wilcox 1318eac6e8e4SMatthew Wilcox return 0x3c; 1319eac6e8e4SMatthew Wilcox } 13201da177e4SLinus Torvalds 1321760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1322760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 13236014759cSMartin K. Petersen { 13243f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 13256014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1326773642d9SDouglas Gilbert if (sdebug_lbpu) 13276014759cSMartin K. Petersen arr[1] = 1 << 7; 1328773642d9SDouglas Gilbert if (sdebug_lbpws) 13296014759cSMartin K. Petersen arr[1] |= 1 << 6; 1330773642d9SDouglas Gilbert if (sdebug_lbpws10) 13315b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1332760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1333760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1334760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1335760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1336760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 13373f0bc3b3SMartin K. Petersen return 0x4; 13386014759cSMartin K. Petersen } 13396014759cSMartin K. Petersen 13401da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1341c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 13421da177e4SLinus Torvalds 1343c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 13441da177e4SLinus Torvalds { 13451da177e4SLinus Torvalds unsigned char pq_pdt; 13465a09e398SHannes Reinecke unsigned char * arr; 134701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 13485a09e398SHannes Reinecke int alloc_len, n, ret; 1349760f3b03SDouglas Gilbert bool have_wlun, is_disk; 13501da177e4SLinus Torvalds 1351773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 13526f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 13536f3cbf55SDouglas Gilbert if (! arr) 13546f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1355760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1356b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1357c2248fc9SDouglas Gilbert if (have_wlun) 1358b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1359b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1360b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1361c65b1445SDouglas Gilbert else 1362773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 13631da177e4SLinus Torvalds arr[0] = pq_pdt; 13641da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 136522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 13665a09e398SHannes Reinecke kfree(arr); 13671da177e4SLinus Torvalds return check_condition_result; 13681da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 13695a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1370c65b1445SDouglas Gilbert char lu_id_str[6]; 1371c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 13721da177e4SLinus Torvalds 13735a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 13745a09e398SHannes Reinecke (devip->channel & 0x7f); 1375b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 137623183910SDouglas Gilbert host_no = 0; 1377c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1378c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1379c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1380c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1381c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 13821da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1383c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1384c65b1445SDouglas Gilbert n = 4; 1385c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1386c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1387c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1388c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1389c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1390c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1391c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1392c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1393760f3b03SDouglas Gilbert if (is_disk) { /* SBC only */ 1394c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1395760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1396760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1397760f3b03SDouglas Gilbert arr[n++] = 0xb2; /* Logical Block Prov */ 1398760f3b03SDouglas Gilbert } 1399c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 14001da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1401c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 14021da177e4SLinus Torvalds arr[3] = len; 1403c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 14041da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1405c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1406760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 14075a09e398SHannes Reinecke target_dev_id, lu_id_num, 140809ba24c1SDouglas Gilbert lu_id_str, len, 140909ba24c1SDouglas Gilbert &devip->lu_name); 1410c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1411c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1412760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1413c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1414c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1415760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1416c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1417c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1418c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 14198475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1420c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1421760f3b03SDouglas Gilbert else if (have_dif_prot) 1422c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1423c6a44287SMartin K. Petersen else 1424c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1425c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1426c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1427c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1428c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1429c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1430c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1431c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1432c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1433c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1434c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1435760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1436760f3b03SDouglas Gilbert } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ 1437c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1438760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1439773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1440760f3b03SDouglas Gilbert } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ 1441c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1442760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1443760f3b03SDouglas Gilbert } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ 1444eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1445760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1446760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 14476014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1448760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 14491da177e4SLinus Torvalds } else { 145022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 14515a09e398SHannes Reinecke kfree(arr); 14521da177e4SLinus Torvalds return check_condition_result; 14531da177e4SLinus Torvalds } 1454773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 14555a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1456c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 14575a09e398SHannes Reinecke kfree(arr); 14585a09e398SHannes Reinecke return ret; 14591da177e4SLinus Torvalds } 14601da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1461773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1462773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 14631da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 14641da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1465f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1466b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 146770bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1468c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 14691da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1470c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1471e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1472e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1473e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 14749b760fd8SDouglas Gilbert /* Use Vendor Specific area to place driver date in ASCII hex */ 14759b760fd8SDouglas Gilbert memcpy(&arr[36], sdebug_version_date, 8); 14761da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1477760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1478760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1479c65b1445SDouglas Gilbert n = 62; 1480760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1481760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1482760f3b03SDouglas Gilbert n += 2; 1483760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1484760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1485760f3b03SDouglas Gilbert n += 2; 14861da177e4SLinus Torvalds } 1487760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 14885a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 14891da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 14905a09e398SHannes Reinecke kfree(arr); 14915a09e398SHannes Reinecke return ret; 14921da177e4SLinus Torvalds } 14931da177e4SLinus Torvalds 1494fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1495fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1496fd32119bSDouglas Gilbert 14971da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 14981da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14991da177e4SLinus Torvalds { 15001da177e4SLinus Torvalds unsigned char * sbuff; 150101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1502cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 15032492fc09STomas Winkler bool dsense; 15041da177e4SLinus Torvalds int len = 18; 15051da177e4SLinus Torvalds 1506c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1507c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1508cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1509c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1510c2248fc9SDouglas Gilbert if (dsense) { 1511c65b1445SDouglas Gilbert arr[0] = 0x72; 1512c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1513c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1514c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1515c2248fc9SDouglas Gilbert len = 8; 1516c65b1445SDouglas Gilbert } else { 1517c65b1445SDouglas Gilbert arr[0] = 0x70; 1518c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1519c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1520c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1521c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1522c65b1445SDouglas Gilbert } 1523c65b1445SDouglas Gilbert } else { 1524cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1525773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1526c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1527c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1528c2248fc9SDouglas Gilbert if (dsense) { 1529c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1530c2248fc9SDouglas Gilbert arr[0] = 0x72; 1531c2248fc9SDouglas Gilbert len = 8; 1532c2248fc9SDouglas Gilbert } else { 1533c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1534c2248fc9SDouglas Gilbert arr[0] = 0x70; 1535c2248fc9SDouglas Gilbert arr[7] = 0xa; 1536c2248fc9SDouglas Gilbert } 1537c2248fc9SDouglas Gilbert } else if (dsense) { 1538c2248fc9SDouglas Gilbert memset(arr, 0, 8); 15391da177e4SLinus Torvalds arr[0] = 0x72; 15401da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 15411da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 15421da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 15431da177e4SLinus Torvalds len = 8; 1544c2248fc9SDouglas Gilbert } else { 1545c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1546c2248fc9SDouglas Gilbert arr[0] = 0x70; 1547c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1548c2248fc9SDouglas Gilbert arr[7] = 0xa; 1549c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1550c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1551c65b1445SDouglas Gilbert } 1552c2248fc9SDouglas Gilbert 1553c65b1445SDouglas Gilbert } 1554cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 15551da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 15561da177e4SLinus Torvalds } 15571da177e4SLinus Torvalds 1558c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1559c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1560c65b1445SDouglas Gilbert { 156101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1562c4837394SDouglas Gilbert int power_cond, stop; 1563c65b1445SDouglas Gilbert 1564c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1565c65b1445SDouglas Gilbert if (power_cond) { 156622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1567c65b1445SDouglas Gilbert return check_condition_result; 1568c65b1445SDouglas Gilbert } 1569c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 1570c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 1571c65b1445SDouglas Gilbert return 0; 1572c65b1445SDouglas Gilbert } 1573c65b1445SDouglas Gilbert 157428898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 157528898873SFUJITA Tomonori { 1576773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1577773642d9SDouglas Gilbert 1578773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1579773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1580773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 158128898873SFUJITA Tomonori else 158228898873SFUJITA Tomonori return sdebug_store_sectors; 158328898873SFUJITA Tomonori } 158428898873SFUJITA Tomonori 15851da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 15861da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 15871da177e4SLinus Torvalds struct sdebug_dev_info * devip) 15881da177e4SLinus Torvalds { 15891da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1590c65b1445SDouglas Gilbert unsigned int capac; 15911da177e4SLinus Torvalds 1592c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 159328898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 15941da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1595c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1596c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1597773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1598773642d9SDouglas Gilbert } else 1599773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1600773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 16011da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 16021da177e4SLinus Torvalds } 16031da177e4SLinus Torvalds 1604c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1605c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1606c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1607c65b1445SDouglas Gilbert { 160801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1609c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1610773642d9SDouglas Gilbert int alloc_len; 1611c65b1445SDouglas Gilbert 1612773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1613c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 161428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1615c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1616773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1617773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1618773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1619773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 162044d92694SMartin K. Petersen 1621be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 16225b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1623760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1624760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1625760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1626760f3b03SDouglas Gilbert */ 1627760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1628760f3b03SDouglas Gilbert arr[14] |= 0x40; 1629be1dd78dSEric Sandeen } 163044d92694SMartin K. Petersen 1631773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1632c6a44287SMartin K. Petersen 1633760f3b03SDouglas Gilbert if (have_dif_prot) { 1634773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1635c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1636c6a44287SMartin K. Petersen } 1637c6a44287SMartin K. Petersen 1638c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1639c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1640c65b1445SDouglas Gilbert } 1641c65b1445SDouglas Gilbert 16425a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 16435a09e398SHannes Reinecke 16445a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 16455a09e398SHannes Reinecke struct sdebug_dev_info * devip) 16465a09e398SHannes Reinecke { 164701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 16485a09e398SHannes Reinecke unsigned char * arr; 16495a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 16505a09e398SHannes Reinecke int n, ret, alen, rlen; 16515a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 16525a09e398SHannes Reinecke 1653773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 16546f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 16556f3cbf55SDouglas Gilbert if (! arr) 16566f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 16575a09e398SHannes Reinecke /* 16585a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 16595a09e398SHannes Reinecke * real and a fake port with no device connected. 16605a09e398SHannes Reinecke * So we create two port groups with one port each 16615a09e398SHannes Reinecke * and set the group with port B to unavailable. 16625a09e398SHannes Reinecke */ 16635a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 16645a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 16655a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 16665a09e398SHannes Reinecke (devip->channel & 0x7f); 16675a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 16685a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 16695a09e398SHannes Reinecke 16705a09e398SHannes Reinecke /* 16715a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 16725a09e398SHannes Reinecke */ 16735a09e398SHannes Reinecke n = 4; 1674b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 16755a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 16765a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 16775a09e398SHannes Reinecke } else { 16785a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1679773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 16805a09e398SHannes Reinecke } 1681773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1682773642d9SDouglas Gilbert n += 2; 16835a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16845a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16855a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16865a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16875a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16885a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1689773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1690773642d9SDouglas Gilbert n += 2; 16915a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 16925a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1693773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1694773642d9SDouglas Gilbert n += 2; 16955a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16965a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16975a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16985a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16995a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 17005a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1701773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1702773642d9SDouglas Gilbert n += 2; 17035a09e398SHannes Reinecke 17045a09e398SHannes Reinecke rlen = n - 4; 1705773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 17065a09e398SHannes Reinecke 17075a09e398SHannes Reinecke /* 17085a09e398SHannes Reinecke * Return the smallest value of either 17095a09e398SHannes Reinecke * - The allocated length 17105a09e398SHannes Reinecke * - The constructed command length 17115a09e398SHannes Reinecke * - The maximum array size 17125a09e398SHannes Reinecke */ 17135a09e398SHannes Reinecke rlen = min(alen,n); 17145a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 17155a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 17165a09e398SHannes Reinecke kfree(arr); 17175a09e398SHannes Reinecke return ret; 17185a09e398SHannes Reinecke } 17195a09e398SHannes Reinecke 1720fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1721fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 172238d5c833SDouglas Gilbert { 172338d5c833SDouglas Gilbert bool rctd; 172438d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 172538d5c833SDouglas Gilbert u16 req_sa, u; 172638d5c833SDouglas Gilbert u32 alloc_len, a_len; 172738d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 172838d5c833SDouglas Gilbert const struct opcode_info_t *oip; 172938d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 173038d5c833SDouglas Gilbert u8 *arr; 173138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 173238d5c833SDouglas Gilbert 173338d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 173438d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 173538d5c833SDouglas Gilbert req_opcode = cmd[3]; 173638d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 173738d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 17386d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 173938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 174038d5c833SDouglas Gilbert return check_condition_result; 174138d5c833SDouglas Gilbert } 174238d5c833SDouglas Gilbert if (alloc_len > 8192) 174338d5c833SDouglas Gilbert a_len = 8192; 174438d5c833SDouglas Gilbert else 174538d5c833SDouglas Gilbert a_len = alloc_len; 174699531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 174738d5c833SDouglas Gilbert if (NULL == arr) { 174838d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 174938d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 175038d5c833SDouglas Gilbert return check_condition_result; 175138d5c833SDouglas Gilbert } 175238d5c833SDouglas Gilbert switch (reporting_opts) { 175338d5c833SDouglas Gilbert case 0: /* all commands */ 175438d5c833SDouglas Gilbert /* count number of commands */ 175538d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 175638d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 175738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 175838d5c833SDouglas Gilbert continue; 175938d5c833SDouglas Gilbert count += (oip->num_attached + 1); 176038d5c833SDouglas Gilbert } 176138d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 176238d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 176338d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 176438d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 176538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 176638d5c833SDouglas Gilbert continue; 176738d5c833SDouglas Gilbert na = oip->num_attached; 176838d5c833SDouglas Gilbert arr[offset] = oip->opcode; 176938d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 177038d5c833SDouglas Gilbert if (rctd) 177138d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 177238d5c833SDouglas Gilbert if (FF_SA & oip->flags) 177338d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 177438d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 177538d5c833SDouglas Gilbert if (rctd) 177638d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 177738d5c833SDouglas Gilbert r_oip = oip; 177838d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 177938d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 178038d5c833SDouglas Gilbert continue; 178138d5c833SDouglas Gilbert offset += bump; 178238d5c833SDouglas Gilbert arr[offset] = oip->opcode; 178338d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 178438d5c833SDouglas Gilbert if (rctd) 178538d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 178638d5c833SDouglas Gilbert if (FF_SA & oip->flags) 178738d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 178838d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 178938d5c833SDouglas Gilbert arr + offset + 6); 179038d5c833SDouglas Gilbert if (rctd) 179138d5c833SDouglas Gilbert put_unaligned_be16(0xa, 179238d5c833SDouglas Gilbert arr + offset + 8); 179338d5c833SDouglas Gilbert } 179438d5c833SDouglas Gilbert oip = r_oip; 179538d5c833SDouglas Gilbert offset += bump; 179638d5c833SDouglas Gilbert } 179738d5c833SDouglas Gilbert break; 179838d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 179938d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 180038d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 180138d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 180238d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 180338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 180438d5c833SDouglas Gilbert supp = 1; 180538d5c833SDouglas Gilbert offset = 4; 180638d5c833SDouglas Gilbert } else { 180738d5c833SDouglas Gilbert if (1 == reporting_opts) { 180838d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 180938d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 181038d5c833SDouglas Gilbert 2, 2); 181138d5c833SDouglas Gilbert kfree(arr); 181238d5c833SDouglas Gilbert return check_condition_result; 181338d5c833SDouglas Gilbert } 181438d5c833SDouglas Gilbert req_sa = 0; 181538d5c833SDouglas Gilbert } else if (2 == reporting_opts && 181638d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 181738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 181838d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 181938d5c833SDouglas Gilbert return check_condition_result; 182038d5c833SDouglas Gilbert } 182138d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 182238d5c833SDouglas Gilbert req_opcode == oip->opcode) 182338d5c833SDouglas Gilbert supp = 3; 182438d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 182538d5c833SDouglas Gilbert na = oip->num_attached; 182638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 182738d5c833SDouglas Gilbert ++k, ++oip) { 182838d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 182938d5c833SDouglas Gilbert break; 183038d5c833SDouglas Gilbert } 183138d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 183238d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 183338d5c833SDouglas Gilbert na = oip->num_attached; 183438d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 183538d5c833SDouglas Gilbert ++k, ++oip) { 183638d5c833SDouglas Gilbert if (req_sa == oip->sa) 183738d5c833SDouglas Gilbert break; 183838d5c833SDouglas Gilbert } 183938d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 184038d5c833SDouglas Gilbert } else 184138d5c833SDouglas Gilbert supp = 3; 184238d5c833SDouglas Gilbert if (3 == supp) { 184338d5c833SDouglas Gilbert u = oip->len_mask[0]; 184438d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 184538d5c833SDouglas Gilbert arr[4] = oip->opcode; 184638d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 184738d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 184838d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 184938d5c833SDouglas Gilbert offset = 4 + u; 185038d5c833SDouglas Gilbert } else 185138d5c833SDouglas Gilbert offset = 4; 185238d5c833SDouglas Gilbert } 185338d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 185438d5c833SDouglas Gilbert if (rctd) { 185538d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 185638d5c833SDouglas Gilbert offset += 12; 185738d5c833SDouglas Gilbert } 185838d5c833SDouglas Gilbert break; 185938d5c833SDouglas Gilbert default: 186038d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 186138d5c833SDouglas Gilbert kfree(arr); 186238d5c833SDouglas Gilbert return check_condition_result; 186338d5c833SDouglas Gilbert } 186438d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 186538d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 186638d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 186738d5c833SDouglas Gilbert kfree(arr); 186838d5c833SDouglas Gilbert return errsts; 186938d5c833SDouglas Gilbert } 187038d5c833SDouglas Gilbert 1871fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1872fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 187338d5c833SDouglas Gilbert { 187438d5c833SDouglas Gilbert bool repd; 187538d5c833SDouglas Gilbert u32 alloc_len, len; 187638d5c833SDouglas Gilbert u8 arr[16]; 187738d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 187838d5c833SDouglas Gilbert 187938d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 188038d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 188138d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 188238d5c833SDouglas Gilbert if (alloc_len < 4) { 188338d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 188438d5c833SDouglas Gilbert return check_condition_result; 188538d5c833SDouglas Gilbert } 188638d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 188738d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 188838d5c833SDouglas Gilbert if (repd) { 188938d5c833SDouglas Gilbert arr[3] = 0xc; 189038d5c833SDouglas Gilbert len = 16; 189138d5c833SDouglas Gilbert } else 189238d5c833SDouglas Gilbert len = 4; 189338d5c833SDouglas Gilbert 189438d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 189538d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 189638d5c833SDouglas Gilbert } 189738d5c833SDouglas Gilbert 18981da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 18991da177e4SLinus Torvalds 19001da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 19011da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 19021da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 19031da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 19041da177e4SLinus Torvalds 19051da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 19061da177e4SLinus Torvalds if (1 == pcontrol) 19071da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 19081da177e4SLinus Torvalds return sizeof(err_recov_pg); 19091da177e4SLinus Torvalds } 19101da177e4SLinus Torvalds 19111da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 19121da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 19131da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 19141da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 19171da177e4SLinus Torvalds if (1 == pcontrol) 19181da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 19191da177e4SLinus Torvalds return sizeof(disconnect_pg); 19201da177e4SLinus Torvalds } 19211da177e4SLinus Torvalds 19221da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 19231da177e4SLinus Torvalds { /* Format device page for mode_sense */ 19241da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 19251da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 19261da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 19271da177e4SLinus Torvalds 19281da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 1929773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 1930773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 1931773642d9SDouglas Gilbert if (sdebug_removable) 19321da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 19331da177e4SLinus Torvalds if (1 == pcontrol) 19341da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 19351da177e4SLinus Torvalds return sizeof(format_pg); 19361da177e4SLinus Torvalds } 19371da177e4SLinus Torvalds 1938fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 1939fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 1940fd32119bSDouglas Gilbert 0, 0, 0, 0}; 1941fd32119bSDouglas Gilbert 19421da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 19431da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1944cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1945cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1946cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 19471da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 19481da177e4SLinus Torvalds 1949773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 1950cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 19511da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 19521da177e4SLinus Torvalds if (1 == pcontrol) 1953cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1954cbf67842SDouglas Gilbert else if (2 == pcontrol) 1955cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 19561da177e4SLinus Torvalds return sizeof(caching_pg); 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds 1959fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 1960fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 1961fd32119bSDouglas Gilbert 19621da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 19631da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1964c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1965c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1966c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 19671da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 19681da177e4SLinus Torvalds 1969773642d9SDouglas Gilbert if (sdebug_dsense) 19701da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1971c65b1445SDouglas Gilbert else 1972c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1973c6a44287SMartin K. Petersen 1974773642d9SDouglas Gilbert if (sdebug_ato) 1975c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1976c6a44287SMartin K. Petersen 19771da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 19781da177e4SLinus Torvalds if (1 == pcontrol) 1979c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1980c65b1445SDouglas Gilbert else if (2 == pcontrol) 1981c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 19821da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 19831da177e4SLinus Torvalds } 19841da177e4SLinus Torvalds 1985c65b1445SDouglas Gilbert 19861da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 19871da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1988c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 19891da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1990c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1991c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1992c65b1445SDouglas Gilbert 19931da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 19941da177e4SLinus Torvalds if (1 == pcontrol) 1995c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1996c65b1445SDouglas Gilbert else if (2 == pcontrol) 1997c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 19981da177e4SLinus Torvalds return sizeof(iec_m_pg); 19991da177e4SLinus Torvalds } 20001da177e4SLinus Torvalds 2001c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 2002c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 2003c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 2004c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 2005c65b1445SDouglas Gilbert 2006c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 2007c65b1445SDouglas Gilbert if (1 == pcontrol) 2008c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 2009c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 2010c65b1445SDouglas Gilbert } 2011c65b1445SDouglas Gilbert 2012c65b1445SDouglas Gilbert 2013c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 2014c65b1445SDouglas Gilbert int target_dev_id) 2015c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 2016c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 2017c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 2018773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2019773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2020c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 2021c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2022c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2023c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 2024773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2025773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 2026c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 2027c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 2028c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2029c65b1445SDouglas Gilbert }; 2030c65b1445SDouglas Gilbert int port_a, port_b; 2031c65b1445SDouglas Gilbert 20321b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 20331b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 20341b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 20351b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 2036c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 2037c65b1445SDouglas Gilbert port_b = port_a + 1; 2038c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 2039773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 2040773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 2041c65b1445SDouglas Gilbert if (1 == pcontrol) 2042c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 2043c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 2044c65b1445SDouglas Gilbert } 2045c65b1445SDouglas Gilbert 2046c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 2047c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 2048c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 2049c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 2050c65b1445SDouglas Gilbert }; 2051c65b1445SDouglas Gilbert 2052c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 2053c65b1445SDouglas Gilbert if (1 == pcontrol) 2054c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 2055c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 2056c65b1445SDouglas Gilbert } 2057c65b1445SDouglas Gilbert 20581da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 20591da177e4SLinus Torvalds 2060fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 2061fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 20621da177e4SLinus Torvalds { 206323183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 20641da177e4SLinus Torvalds unsigned char dev_spec; 2065760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2066c2248fc9SDouglas Gilbert int target = scp->device->id; 20671da177e4SLinus Torvalds unsigned char * ap; 20681da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 206901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2070760f3b03SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, bad_pcode; 20711da177e4SLinus Torvalds 2072760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 20731da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 20741da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 20751da177e4SLinus Torvalds subpcode = cmd[3]; 20761da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2077760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2078760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 2079760f3b03SDouglas Gilbert if (is_disk && !dbd) 208023183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 208123183910SDouglas Gilbert else 208223183910SDouglas Gilbert bd_len = 0; 2083773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 20841da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 20851da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2086cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 20871da177e4SLinus Torvalds return check_condition_result; 20881da177e4SLinus Torvalds } 2089c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2090c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2091b01f6f83SDouglas Gilbert /* for disks set DPOFUA bit and clear write protect (WP) bit */ 2092760f3b03SDouglas Gilbert if (is_disk) 2093b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 209423183910SDouglas Gilbert else 209523183910SDouglas Gilbert dev_spec = 0x0; 20961da177e4SLinus Torvalds if (msense_6) { 20971da177e4SLinus Torvalds arr[2] = dev_spec; 209823183910SDouglas Gilbert arr[3] = bd_len; 20991da177e4SLinus Torvalds offset = 4; 21001da177e4SLinus Torvalds } else { 21011da177e4SLinus Torvalds arr[3] = dev_spec; 210223183910SDouglas Gilbert if (16 == bd_len) 210323183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 210423183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 21051da177e4SLinus Torvalds offset = 8; 21061da177e4SLinus Torvalds } 21071da177e4SLinus Torvalds ap = arr + offset; 210828898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 210928898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 211028898873SFUJITA Tomonori 211123183910SDouglas Gilbert if (8 == bd_len) { 2112773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2113773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2114773642d9SDouglas Gilbert else 2115773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2116773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 211723183910SDouglas Gilbert offset += bd_len; 211823183910SDouglas Gilbert ap = arr + offset; 211923183910SDouglas Gilbert } else if (16 == bd_len) { 2120773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2121773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 212223183910SDouglas Gilbert offset += bd_len; 212323183910SDouglas Gilbert ap = arr + offset; 212423183910SDouglas Gilbert } 21251da177e4SLinus Torvalds 2126c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2127c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 212822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 21291da177e4SLinus Torvalds return check_condition_result; 21301da177e4SLinus Torvalds } 2131760f3b03SDouglas Gilbert bad_pcode = false; 2132760f3b03SDouglas Gilbert 21331da177e4SLinus Torvalds switch (pcode) { 21341da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 21351da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 21361da177e4SLinus Torvalds offset += len; 21371da177e4SLinus Torvalds break; 21381da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 21391da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 21401da177e4SLinus Torvalds offset += len; 21411da177e4SLinus Torvalds break; 21421da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2143760f3b03SDouglas Gilbert if (is_disk) { 21441da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 21451da177e4SLinus Torvalds offset += len; 2146760f3b03SDouglas Gilbert } else 2147760f3b03SDouglas Gilbert bad_pcode = true; 21481da177e4SLinus Torvalds break; 21491da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2150760f3b03SDouglas Gilbert if (is_disk) { 21511da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 21521da177e4SLinus Torvalds offset += len; 2153760f3b03SDouglas Gilbert } else 2154760f3b03SDouglas Gilbert bad_pcode = true; 21551da177e4SLinus Torvalds break; 21561da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 21571da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 21581da177e4SLinus Torvalds offset += len; 21591da177e4SLinus Torvalds break; 2160c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2161c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 216222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2163c65b1445SDouglas Gilbert return check_condition_result; 2164c65b1445SDouglas Gilbert } 2165c65b1445SDouglas Gilbert len = 0; 2166c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2167c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2168c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2169c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2170c65b1445SDouglas Gilbert target_dev_id); 2171c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2172c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2173c65b1445SDouglas Gilbert offset += len; 2174c65b1445SDouglas Gilbert break; 21751da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 21761da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 21771da177e4SLinus Torvalds offset += len; 21781da177e4SLinus Torvalds break; 21791da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2180c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 21811da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 21821da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2183760f3b03SDouglas Gilbert if (is_disk) { 2184760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2185760f3b03SDouglas Gilbert target); 2186760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2187760f3b03SDouglas Gilbert target); 2188760f3b03SDouglas Gilbert } 21891da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2190c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2191c65b1445SDouglas Gilbert if (0xff == subpcode) { 2192c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2193c65b1445SDouglas Gilbert target, target_dev_id); 2194c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2195c65b1445SDouglas Gilbert } 21961da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2197760f3b03SDouglas Gilbert offset += len; 2198c65b1445SDouglas Gilbert } else { 219922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2200c65b1445SDouglas Gilbert return check_condition_result; 2201c65b1445SDouglas Gilbert } 22021da177e4SLinus Torvalds break; 22031da177e4SLinus Torvalds default: 2204760f3b03SDouglas Gilbert bad_pcode = true; 2205760f3b03SDouglas Gilbert break; 2206760f3b03SDouglas Gilbert } 2207760f3b03SDouglas Gilbert if (bad_pcode) { 220822017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 22091da177e4SLinus Torvalds return check_condition_result; 22101da177e4SLinus Torvalds } 22111da177e4SLinus Torvalds if (msense_6) 22121da177e4SLinus Torvalds arr[0] = offset - 1; 2213773642d9SDouglas Gilbert else 2214773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 22151da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 22161da177e4SLinus Torvalds } 22171da177e4SLinus Torvalds 2218c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2219c65b1445SDouglas Gilbert 2220fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2221fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2222c65b1445SDouglas Gilbert { 2223c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2224c2248fc9SDouglas Gilbert int param_len, res, mpage; 2225c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 222601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2227c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2228c65b1445SDouglas Gilbert 2229c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2230c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2231c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2232773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2233c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 223422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2235c65b1445SDouglas Gilbert return check_condition_result; 2236c65b1445SDouglas Gilbert } 2237c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2238c65b1445SDouglas Gilbert if (-1 == res) 2239773642d9SDouglas Gilbert return DID_ERROR << 16; 2240773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2241cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2242cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2243cbf67842SDouglas Gilbert __func__, param_len, res); 2244773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2245773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 224623183910SDouglas Gilbert if (md_len > 2) { 224722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2248c65b1445SDouglas Gilbert return check_condition_result; 2249c65b1445SDouglas Gilbert } 2250c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2251c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2252c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2253c65b1445SDouglas Gilbert if (ps) { 225422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2255c65b1445SDouglas Gilbert return check_condition_result; 2256c65b1445SDouglas Gilbert } 2257c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2258773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2259c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2260c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2261cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2262c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2263c65b1445SDouglas Gilbert return check_condition_result; 2264c65b1445SDouglas Gilbert } 2265c65b1445SDouglas Gilbert switch (mpage) { 2266cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2267cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2268cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2269cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2270cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2271cbf67842SDouglas Gilbert } 2272cbf67842SDouglas Gilbert break; 2273c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2274c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2275c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2276c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2277773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2278cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2279c65b1445SDouglas Gilbert } 2280c65b1445SDouglas Gilbert break; 2281c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2282c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2283c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2284c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2285cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2286c65b1445SDouglas Gilbert } 2287c65b1445SDouglas Gilbert break; 2288c65b1445SDouglas Gilbert default: 2289c65b1445SDouglas Gilbert break; 2290c65b1445SDouglas Gilbert } 229122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2292c65b1445SDouglas Gilbert return check_condition_result; 2293cbf67842SDouglas Gilbert set_mode_changed_ua: 2294cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2295cbf67842SDouglas Gilbert return 0; 2296c65b1445SDouglas Gilbert } 2297c65b1445SDouglas Gilbert 2298c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2299c65b1445SDouglas Gilbert { 2300c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2301c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2302c65b1445SDouglas Gilbert }; 2303c65b1445SDouglas Gilbert 2304c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2305c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2306c65b1445SDouglas Gilbert } 2307c65b1445SDouglas Gilbert 2308c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2309c65b1445SDouglas Gilbert { 2310c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2311c65b1445SDouglas Gilbert }; 2312c65b1445SDouglas Gilbert 2313c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2314c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2315c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2316c65b1445SDouglas Gilbert arr[5] = 0xff; 2317c65b1445SDouglas Gilbert } 2318c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2319c65b1445SDouglas Gilbert } 2320c65b1445SDouglas Gilbert 2321c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2322c65b1445SDouglas Gilbert 2323c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2324c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2325c65b1445SDouglas Gilbert { 2326ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2327c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 232801123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2329c65b1445SDouglas Gilbert 2330c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2331c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2332c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2333c65b1445SDouglas Gilbert if (ppc || sp) { 233422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2335c65b1445SDouglas Gilbert return check_condition_result; 2336c65b1445SDouglas Gilbert } 2337c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 233823183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2339773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2340c65b1445SDouglas Gilbert arr[0] = pcode; 234123183910SDouglas Gilbert if (0 == subpcode) { 2342c65b1445SDouglas Gilbert switch (pcode) { 2343c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2344c65b1445SDouglas Gilbert n = 4; 2345c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2346c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2347c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2348c65b1445SDouglas Gilbert arr[3] = n - 4; 2349c65b1445SDouglas Gilbert break; 2350c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2351c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2352c65b1445SDouglas Gilbert break; 2353c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2354c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2355c65b1445SDouglas Gilbert break; 2356c65b1445SDouglas Gilbert default: 235722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2358c65b1445SDouglas Gilbert return check_condition_result; 2359c65b1445SDouglas Gilbert } 236023183910SDouglas Gilbert } else if (0xff == subpcode) { 236123183910SDouglas Gilbert arr[0] |= 0x40; 236223183910SDouglas Gilbert arr[1] = subpcode; 236323183910SDouglas Gilbert switch (pcode) { 236423183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 236523183910SDouglas Gilbert n = 4; 236623183910SDouglas Gilbert arr[n++] = 0x0; 236723183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 236823183910SDouglas Gilbert arr[n++] = 0x0; 236923183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 237023183910SDouglas Gilbert arr[n++] = 0xd; 237123183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 237223183910SDouglas Gilbert arr[n++] = 0x2f; 237323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 237423183910SDouglas Gilbert arr[3] = n - 4; 237523183910SDouglas Gilbert break; 237623183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 237723183910SDouglas Gilbert n = 4; 237823183910SDouglas Gilbert arr[n++] = 0xd; 237923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 238023183910SDouglas Gilbert arr[3] = n - 4; 238123183910SDouglas Gilbert break; 238223183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 238323183910SDouglas Gilbert n = 4; 238423183910SDouglas Gilbert arr[n++] = 0x2f; 238523183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 238623183910SDouglas Gilbert arr[3] = n - 4; 238723183910SDouglas Gilbert break; 238823183910SDouglas Gilbert default: 238922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 239023183910SDouglas Gilbert return check_condition_result; 239123183910SDouglas Gilbert } 239223183910SDouglas Gilbert } else { 239322017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 239423183910SDouglas Gilbert return check_condition_result; 239523183910SDouglas Gilbert } 2396773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 2397c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2398c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2399c65b1445SDouglas Gilbert } 2400c65b1445SDouglas Gilbert 2401cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 240219789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 24031da177e4SLinus Torvalds { 2404c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 240522017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 24061da177e4SLinus Torvalds return check_condition_result; 24071da177e4SLinus Torvalds } 2408c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2409c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 241022017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2411cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2412c65b1445SDouglas Gilbert return check_condition_result; 2413c65b1445SDouglas Gilbert } 241419789100SFUJITA Tomonori return 0; 241519789100SFUJITA Tomonori } 241619789100SFUJITA Tomonori 2417a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2418fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, 2419fd32119bSDouglas Gilbert bool do_write) 242019789100SFUJITA Tomonori { 242119789100SFUJITA Tomonori int ret; 2422c2248fc9SDouglas Gilbert u64 block, rest = 0; 2423a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2424a4517511SAkinobu Mita enum dma_data_direction dir; 242519789100SFUJITA Tomonori 2426c2248fc9SDouglas Gilbert if (do_write) { 2427a4517511SAkinobu Mita sdb = scsi_out(scmd); 2428a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2429a4517511SAkinobu Mita } else { 2430a4517511SAkinobu Mita sdb = scsi_in(scmd); 2431a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2432a4517511SAkinobu Mita } 2433a4517511SAkinobu Mita 2434a4517511SAkinobu Mita if (!sdb->length) 2435a4517511SAkinobu Mita return 0; 2436a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2437a4517511SAkinobu Mita return -1; 243819789100SFUJITA Tomonori 243919789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 244019789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 244119789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 244219789100SFUJITA Tomonori 2443386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2444773642d9SDouglas Gilbert fake_storep + (block * sdebug_sector_size), 2445773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, 0, do_write); 2446773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2447a4517511SAkinobu Mita return ret; 2448a4517511SAkinobu Mita 2449a4517511SAkinobu Mita if (rest) { 2450386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2451773642d9SDouglas Gilbert fake_storep, rest * sdebug_sector_size, 2452773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, do_write); 2453a4517511SAkinobu Mita } 245419789100SFUJITA Tomonori 245519789100SFUJITA Tomonori return ret; 245619789100SFUJITA Tomonori } 245719789100SFUJITA Tomonori 245838d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 245938d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 246038d5c833SDouglas Gilbert * return false. */ 2461fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr) 246238d5c833SDouglas Gilbert { 246338d5c833SDouglas Gilbert bool res; 246438d5c833SDouglas Gilbert u64 block, rest = 0; 246538d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2466773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 246738d5c833SDouglas Gilbert 246838d5c833SDouglas Gilbert block = do_div(lba, store_blks); 246938d5c833SDouglas Gilbert if (block + num > store_blks) 247038d5c833SDouglas Gilbert rest = block + num - store_blks; 247138d5c833SDouglas Gilbert 247238d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 247338d5c833SDouglas Gilbert (num - rest) * lb_size); 247438d5c833SDouglas Gilbert if (!res) 247538d5c833SDouglas Gilbert return res; 247638d5c833SDouglas Gilbert if (rest) 247738d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 247838d5c833SDouglas Gilbert rest * lb_size); 247938d5c833SDouglas Gilbert if (!res) 248038d5c833SDouglas Gilbert return res; 248138d5c833SDouglas Gilbert arr += num * lb_size; 248238d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 248338d5c833SDouglas Gilbert if (rest) 248438d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 248538d5c833SDouglas Gilbert rest * lb_size); 248638d5c833SDouglas Gilbert return res; 248738d5c833SDouglas Gilbert } 248838d5c833SDouglas Gilbert 248951d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2490beb40ea4SAkinobu Mita { 249151d648afSAkinobu Mita __be16 csum; 2492beb40ea4SAkinobu Mita 2493773642d9SDouglas Gilbert if (sdebug_guard) 249451d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 249551d648afSAkinobu Mita else 2496beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 249751d648afSAkinobu Mita 2498beb40ea4SAkinobu Mita return csum; 2499beb40ea4SAkinobu Mita } 2500beb40ea4SAkinobu Mita 25016ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 2502beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2503beb40ea4SAkinobu Mita { 2504773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2505beb40ea4SAkinobu Mita 2506beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2507c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2508beb40ea4SAkinobu Mita (unsigned long)sector, 2509beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2510beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2511beb40ea4SAkinobu Mita return 0x01; 2512beb40ea4SAkinobu Mita } 25138475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 2514beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2515c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2516c1287970STomas Winkler (unsigned long)sector); 2517beb40ea4SAkinobu Mita return 0x03; 2518beb40ea4SAkinobu Mita } 25198475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2520beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2521c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2522c1287970STomas Winkler (unsigned long)sector); 2523beb40ea4SAkinobu Mita return 0x03; 2524beb40ea4SAkinobu Mita } 2525beb40ea4SAkinobu Mita return 0; 2526beb40ea4SAkinobu Mita } 2527beb40ea4SAkinobu Mita 2528bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 252965f72f2aSAkinobu Mita unsigned int sectors, bool read) 2530c6a44287SMartin K. Petersen { 2531be4e11beSAkinobu Mita size_t resid; 2532c6a44287SMartin K. Petersen void *paddr; 253314faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2534be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2535c6a44287SMartin K. Petersen 2536e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2537e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2538c6a44287SMartin K. Petersen 2539be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2540be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2541be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2542be4e11beSAkinobu Mita 2543be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2544be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 254514faa944SAkinobu Mita void *start = dif_store(sector); 2546be4e11beSAkinobu Mita size_t rest = 0; 254714faa944SAkinobu Mita 254814faa944SAkinobu Mita if (dif_store_end < start + len) 254914faa944SAkinobu Mita rest = start + len - dif_store_end; 2550c6a44287SMartin K. Petersen 2551be4e11beSAkinobu Mita paddr = miter.addr; 255214faa944SAkinobu Mita 255365f72f2aSAkinobu Mita if (read) 255465f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 255565f72f2aSAkinobu Mita else 255665f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 255765f72f2aSAkinobu Mita 255865f72f2aSAkinobu Mita if (rest) { 255965f72f2aSAkinobu Mita if (read) 256014faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 256165f72f2aSAkinobu Mita else 256265f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 256365f72f2aSAkinobu Mita } 2564c6a44287SMartin K. Petersen 2565e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2566c6a44287SMartin K. Petersen resid -= len; 2567c6a44287SMartin K. Petersen } 2568be4e11beSAkinobu Mita sg_miter_stop(&miter); 2569bb8c063cSAkinobu Mita } 2570c6a44287SMartin K. Petersen 2571bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2572bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2573bb8c063cSAkinobu Mita { 2574bb8c063cSAkinobu Mita unsigned int i; 25756ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 2576bb8c063cSAkinobu Mita sector_t sector; 2577bb8c063cSAkinobu Mita 2578c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2579bb8c063cSAkinobu Mita int ret; 2580bb8c063cSAkinobu Mita 2581bb8c063cSAkinobu Mita sector = start_sec + i; 2582bb8c063cSAkinobu Mita sdt = dif_store(sector); 2583bb8c063cSAkinobu Mita 258451d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2585bb8c063cSAkinobu Mita continue; 2586bb8c063cSAkinobu Mita 2587bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2588bb8c063cSAkinobu Mita if (ret) { 2589bb8c063cSAkinobu Mita dif_errors++; 2590bb8c063cSAkinobu Mita return ret; 2591bb8c063cSAkinobu Mita } 2592bb8c063cSAkinobu Mita } 2593bb8c063cSAkinobu Mita 259465f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2595c6a44287SMartin K. Petersen dix_reads++; 2596c6a44287SMartin K. Petersen 2597c6a44287SMartin K. Petersen return 0; 2598c6a44287SMartin K. Petersen } 2599c6a44287SMartin K. Petersen 2600fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 260119789100SFUJITA Tomonori { 2602c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2603c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 2604c2248fc9SDouglas Gilbert u64 lba; 2605c2248fc9SDouglas Gilbert u32 num; 2606c2248fc9SDouglas Gilbert u32 ei_lba; 260719789100SFUJITA Tomonori unsigned long iflags; 260819789100SFUJITA Tomonori int ret; 2609c2248fc9SDouglas Gilbert bool check_prot; 261019789100SFUJITA Tomonori 2611c2248fc9SDouglas Gilbert switch (cmd[0]) { 2612c2248fc9SDouglas Gilbert case READ_16: 2613c2248fc9SDouglas Gilbert ei_lba = 0; 2614c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2615c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2616c2248fc9SDouglas Gilbert check_prot = true; 2617c2248fc9SDouglas Gilbert break; 2618c2248fc9SDouglas Gilbert case READ_10: 2619c2248fc9SDouglas Gilbert ei_lba = 0; 2620c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2621c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2622c2248fc9SDouglas Gilbert check_prot = true; 2623c2248fc9SDouglas Gilbert break; 2624c2248fc9SDouglas Gilbert case READ_6: 2625c2248fc9SDouglas Gilbert ei_lba = 0; 2626c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2627c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2628c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2629c2248fc9SDouglas Gilbert check_prot = true; 2630c2248fc9SDouglas Gilbert break; 2631c2248fc9SDouglas Gilbert case READ_12: 2632c2248fc9SDouglas Gilbert ei_lba = 0; 2633c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2634c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2635c2248fc9SDouglas Gilbert check_prot = true; 2636c2248fc9SDouglas Gilbert break; 2637c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2638c2248fc9SDouglas Gilbert ei_lba = 0; 2639c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2640c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2641c2248fc9SDouglas Gilbert check_prot = false; 2642c2248fc9SDouglas Gilbert break; 2643c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2644c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2645c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2646c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2647c2248fc9SDouglas Gilbert check_prot = false; 2648c2248fc9SDouglas Gilbert break; 2649c2248fc9SDouglas Gilbert } 2650f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 26518475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2652c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2653c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2654c2248fc9SDouglas Gilbert return check_condition_result; 2655c2248fc9SDouglas Gilbert } 26568475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 26578475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 2658c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2659c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2660c2248fc9SDouglas Gilbert "to DIF device\n"); 2661c2248fc9SDouglas Gilbert } 2662f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2663c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 2664c2248fc9SDouglas Gilbert 2665c4837394SDouglas Gilbert if (sqcp) { 2666c4837394SDouglas Gilbert if (sqcp->inj_short) 2667c2248fc9SDouglas Gilbert num /= 2; 2668c2248fc9SDouglas Gilbert } 2669c4837394SDouglas Gilbert } else 2670c4837394SDouglas Gilbert sqcp = NULL; 2671c2248fc9SDouglas Gilbert 2672c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2673f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2674c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2675c2248fc9SDouglas Gilbert return check_condition_result; 2676c2248fc9SDouglas Gilbert } 2677c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2678f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2679c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2680c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2681c2248fc9SDouglas Gilbert return check_condition_result; 2682c2248fc9SDouglas Gilbert } 268319789100SFUJITA Tomonori 2684f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 268532f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2686f46eb0e9SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { 2687c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2688c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2689c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2690c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2691c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 269232f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 269332f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2694c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2695c65b1445SDouglas Gilbert } 2696c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 26971da177e4SLinus Torvalds return check_condition_result; 26981da177e4SLinus Torvalds } 2699c6a44287SMartin K. Petersen 27006c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 27016c78cc06SAkinobu Mita 2702c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2703f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2704c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2705c6a44287SMartin K. Petersen 2706c6a44287SMartin K. Petersen if (prot_ret) { 27076c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2708c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2709c6a44287SMartin K. Petersen return illegal_condition_result; 2710c6a44287SMartin K. Petersen } 2711c6a44287SMartin K. Petersen } 2712c6a44287SMartin K. Petersen 2713c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 27141da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2715f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2716a4517511SAkinobu Mita return DID_ERROR << 16; 2717a4517511SAkinobu Mita 2718c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2719a4517511SAkinobu Mita 2720c4837394SDouglas Gilbert if (unlikely(sqcp)) { 2721c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2722c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2723c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2724c2248fc9SDouglas Gilbert return check_condition_result; 2725c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 2726c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2727c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2728c2248fc9SDouglas Gilbert return check_condition_result; 2729c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2730c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2731c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2732c2248fc9SDouglas Gilbert return illegal_condition_result; 2733c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2734c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2735c2248fc9SDouglas Gilbert return illegal_condition_result; 2736c2248fc9SDouglas Gilbert } 2737c2248fc9SDouglas Gilbert } 2738a4517511SAkinobu Mita return 0; 27391da177e4SLinus Torvalds } 27401da177e4SLinus Torvalds 274158a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2742c6a44287SMartin K. Petersen { 2743cbf67842SDouglas Gilbert int i, j, n; 2744c6a44287SMartin K. Petersen 2745cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2746c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2747cbf67842SDouglas Gilbert char b[128]; 2748c6a44287SMartin K. Petersen 2749cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2750c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2751c6a44287SMartin K. Petersen 2752cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2753cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2754cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2755cbf67842SDouglas Gilbert else 2756cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2757cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2758cbf67842SDouglas Gilbert } 2759cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2760c6a44287SMartin K. Petersen } 2761c6a44287SMartin K. Petersen } 2762c6a44287SMartin K. Petersen 2763c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2764395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2765c6a44287SMartin K. Petersen { 2766be4e11beSAkinobu Mita int ret; 27676ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 2768be4e11beSAkinobu Mita void *daddr; 276965f72f2aSAkinobu Mita sector_t sector = start_sec; 2770c6a44287SMartin K. Petersen int ppage_offset; 2771be4e11beSAkinobu Mita int dpage_offset; 2772be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2773be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2774c6a44287SMartin K. Petersen 2775c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2776c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2777c6a44287SMartin K. Petersen 2778be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2779be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2780be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2781be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2782be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2783c6a44287SMartin K. Petersen 2784be4e11beSAkinobu Mita /* For each protection page */ 2785be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2786be4e11beSAkinobu Mita dpage_offset = 0; 2787be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2788be4e11beSAkinobu Mita ret = 0x01; 2789be4e11beSAkinobu Mita goto out; 2790c6a44287SMartin K. Petersen } 2791c6a44287SMartin K. Petersen 2792be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 27936ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 2794be4e11beSAkinobu Mita /* If we're at the end of the current 2795be4e11beSAkinobu Mita * data page advance to the next one 2796be4e11beSAkinobu Mita */ 2797be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2798be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2799be4e11beSAkinobu Mita ret = 0x01; 2800be4e11beSAkinobu Mita goto out; 2801be4e11beSAkinobu Mita } 2802be4e11beSAkinobu Mita dpage_offset = 0; 2803be4e11beSAkinobu Mita } 2804c6a44287SMartin K. Petersen 2805be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2806be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2807be4e11beSAkinobu Mita 2808be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2809beb40ea4SAkinobu Mita if (ret) { 2810773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2811395cef03SMartin K. Petersen goto out; 2812395cef03SMartin K. Petersen } 2813395cef03SMartin K. Petersen 2814c6a44287SMartin K. Petersen sector++; 2815395cef03SMartin K. Petersen ei_lba++; 2816773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2817c6a44287SMartin K. Petersen } 2818be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2819be4e11beSAkinobu Mita sg_miter_stop(&diter); 2820c6a44287SMartin K. Petersen } 2821be4e11beSAkinobu Mita sg_miter_stop(&piter); 2822c6a44287SMartin K. Petersen 282365f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2824c6a44287SMartin K. Petersen dix_writes++; 2825c6a44287SMartin K. Petersen 2826c6a44287SMartin K. Petersen return 0; 2827c6a44287SMartin K. Petersen 2828c6a44287SMartin K. Petersen out: 2829c6a44287SMartin K. Petersen dif_errors++; 2830be4e11beSAkinobu Mita sg_miter_stop(&diter); 2831be4e11beSAkinobu Mita sg_miter_stop(&piter); 2832c6a44287SMartin K. Petersen return ret; 2833c6a44287SMartin K. Petersen } 2834c6a44287SMartin K. Petersen 2835b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2836b90ebc3dSAkinobu Mita { 2837773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2838773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2839773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2840b90ebc3dSAkinobu Mita return lba; 2841b90ebc3dSAkinobu Mita } 2842b90ebc3dSAkinobu Mita 2843b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2844b90ebc3dSAkinobu Mita { 2845773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2846a027b5b9SAkinobu Mita 2847773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2848773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2849a027b5b9SAkinobu Mita return lba; 2850a027b5b9SAkinobu Mita } 2851a027b5b9SAkinobu Mita 285244d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 285344d92694SMartin K. Petersen { 2854b90ebc3dSAkinobu Mita sector_t end; 2855b90ebc3dSAkinobu Mita unsigned int mapped; 2856b90ebc3dSAkinobu Mita unsigned long index; 2857b90ebc3dSAkinobu Mita unsigned long next; 285844d92694SMartin K. Petersen 2859b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2860b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 286144d92694SMartin K. Petersen 286244d92694SMartin K. Petersen if (mapped) 2863b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 286444d92694SMartin K. Petersen else 2865b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 286644d92694SMartin K. Petersen 2867b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 286844d92694SMartin K. Petersen *num = end - lba; 286944d92694SMartin K. Petersen return mapped; 287044d92694SMartin K. Petersen } 287144d92694SMartin K. Petersen 287244d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 287344d92694SMartin K. Petersen { 287444d92694SMartin K. Petersen sector_t end = lba + len; 287544d92694SMartin K. Petersen 287644d92694SMartin K. Petersen while (lba < end) { 2877b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 287844d92694SMartin K. Petersen 2879b90ebc3dSAkinobu Mita if (index < map_size) 2880b90ebc3dSAkinobu Mita set_bit(index, map_storep); 288144d92694SMartin K. Petersen 2882b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 288344d92694SMartin K. Petersen } 288444d92694SMartin K. Petersen } 288544d92694SMartin K. Petersen 288644d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 288744d92694SMartin K. Petersen { 288844d92694SMartin K. Petersen sector_t end = lba + len; 288944d92694SMartin K. Petersen 289044d92694SMartin K. Petersen while (lba < end) { 2891b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 289244d92694SMartin K. Petersen 2893b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2894773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 2895b90ebc3dSAkinobu Mita index < map_size) { 2896b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2897760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 2898be1dd78dSEric Sandeen memset(fake_storep + 2899760f3b03SDouglas Gilbert lba * sdebug_sector_size, 2900760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 2901773642d9SDouglas Gilbert sdebug_sector_size * 2902773642d9SDouglas Gilbert sdebug_unmap_granularity); 2903be1dd78dSEric Sandeen } 2904e9926b43SAkinobu Mita if (dif_storep) { 2905e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2906e9926b43SAkinobu Mita sizeof(*dif_storep) * 2907773642d9SDouglas Gilbert sdebug_unmap_granularity); 2908e9926b43SAkinobu Mita } 2909b90ebc3dSAkinobu Mita } 2910b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 291144d92694SMartin K. Petersen } 291244d92694SMartin K. Petersen } 291344d92694SMartin K. Petersen 2914fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 29151da177e4SLinus Torvalds { 2916c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2917c2248fc9SDouglas Gilbert u64 lba; 2918c2248fc9SDouglas Gilbert u32 num; 2919c2248fc9SDouglas Gilbert u32 ei_lba; 29201da177e4SLinus Torvalds unsigned long iflags; 292119789100SFUJITA Tomonori int ret; 2922c2248fc9SDouglas Gilbert bool check_prot; 29231da177e4SLinus Torvalds 2924c2248fc9SDouglas Gilbert switch (cmd[0]) { 2925c2248fc9SDouglas Gilbert case WRITE_16: 2926c2248fc9SDouglas Gilbert ei_lba = 0; 2927c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2928c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2929c2248fc9SDouglas Gilbert check_prot = true; 2930c2248fc9SDouglas Gilbert break; 2931c2248fc9SDouglas Gilbert case WRITE_10: 2932c2248fc9SDouglas Gilbert ei_lba = 0; 2933c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2934c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2935c2248fc9SDouglas Gilbert check_prot = true; 2936c2248fc9SDouglas Gilbert break; 2937c2248fc9SDouglas Gilbert case WRITE_6: 2938c2248fc9SDouglas Gilbert ei_lba = 0; 2939c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2940c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2941c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2942c2248fc9SDouglas Gilbert check_prot = true; 2943c2248fc9SDouglas Gilbert break; 2944c2248fc9SDouglas Gilbert case WRITE_12: 2945c2248fc9SDouglas Gilbert ei_lba = 0; 2946c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2947c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2948c2248fc9SDouglas Gilbert check_prot = true; 2949c2248fc9SDouglas Gilbert break; 2950c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2951c2248fc9SDouglas Gilbert ei_lba = 0; 2952c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2953c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2954c2248fc9SDouglas Gilbert check_prot = false; 2955c2248fc9SDouglas Gilbert break; 2956c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2957c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2958c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2959c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2960c2248fc9SDouglas Gilbert check_prot = false; 2961c2248fc9SDouglas Gilbert break; 2962c2248fc9SDouglas Gilbert } 2963f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 29648475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2965c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2966c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2967c2248fc9SDouglas Gilbert return check_condition_result; 2968c2248fc9SDouglas Gilbert } 29698475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 29708475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 2971c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2972c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2973c2248fc9SDouglas Gilbert "to DIF device\n"); 2974c2248fc9SDouglas Gilbert } 2975c2248fc9SDouglas Gilbert 2976c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2977f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2978c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2979c2248fc9SDouglas Gilbert return check_condition_result; 2980c2248fc9SDouglas Gilbert } 2981c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2982f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2983c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2984c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2985c2248fc9SDouglas Gilbert return check_condition_result; 2986c2248fc9SDouglas Gilbert } 29871da177e4SLinus Torvalds 29886c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 29896c78cc06SAkinobu Mita 2990c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2991f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2992c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2993c6a44287SMartin K. Petersen 2994c6a44287SMartin K. Petersen if (prot_ret) { 29956c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2996c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2997c6a44287SMartin K. Petersen return illegal_condition_result; 2998c6a44287SMartin K. Petersen } 2999c6a44287SMartin K. Petersen } 3000c6a44287SMartin K. Petersen 3001c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 3002f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 300344d92694SMartin K. Petersen map_region(lba, num); 30041da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 3005f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 3006773642d9SDouglas Gilbert return DID_ERROR << 16; 3007c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 3008c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 3009c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3010cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 3011773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 301244d92694SMartin K. Petersen 3013f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 3014c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 3015c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 3016c2248fc9SDouglas Gilbert 3017c4837394SDouglas Gilbert if (sqcp) { 3018c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 3019c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 3020c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 3021c2248fc9SDouglas Gilbert return check_condition_result; 3022c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 3023c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 3024c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 3025c2248fc9SDouglas Gilbert return illegal_condition_result; 3026c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 3027c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 3028c2248fc9SDouglas Gilbert return illegal_condition_result; 3029c2248fc9SDouglas Gilbert } 3030c2248fc9SDouglas Gilbert } 3031c4837394SDouglas Gilbert } 30321da177e4SLinus Torvalds return 0; 30331da177e4SLinus Torvalds } 30341da177e4SLinus Torvalds 3035fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 3036fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 303744d92694SMartin K. Petersen { 303844d92694SMartin K. Petersen unsigned long iflags; 303944d92694SMartin K. Petersen unsigned long long i; 304044d92694SMartin K. Petersen int ret; 3041773642d9SDouglas Gilbert u64 lba_off; 304244d92694SMartin K. Petersen 3043c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 304444d92694SMartin K. Petersen if (ret) 304544d92694SMartin K. Petersen return ret; 304644d92694SMartin K. Petersen 304744d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 304844d92694SMartin K. Petersen 30499ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 305044d92694SMartin K. Petersen unmap_region(lba, num); 305144d92694SMartin K. Petersen goto out; 305244d92694SMartin K. Petersen } 305344d92694SMartin K. Petersen 3054773642d9SDouglas Gilbert lba_off = lba * sdebug_sector_size; 3055c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 3056c2248fc9SDouglas Gilbert if (ndob) { 3057773642d9SDouglas Gilbert memset(fake_storep + lba_off, 0, sdebug_sector_size); 3058c2248fc9SDouglas Gilbert ret = 0; 3059c2248fc9SDouglas Gilbert } else 3060773642d9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + lba_off, 3061773642d9SDouglas Gilbert sdebug_sector_size); 306244d92694SMartin K. Petersen 306344d92694SMartin K. Petersen if (-1 == ret) { 306444d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 3065773642d9SDouglas Gilbert return DID_ERROR << 16; 3066e33d7c56SDouglas Gilbert } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size)) 3067c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3068e33d7c56SDouglas Gilbert "%s: %s: lb size=%u, IO sent=%d bytes\n", 3069cbf67842SDouglas Gilbert my_name, "write same", 3070e33d7c56SDouglas Gilbert sdebug_sector_size, ret); 307144d92694SMartin K. Petersen 307244d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 307344d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 3074773642d9SDouglas Gilbert memcpy(fake_storep + ((lba + i) * sdebug_sector_size), 3075773642d9SDouglas Gilbert fake_storep + lba_off, 3076773642d9SDouglas Gilbert sdebug_sector_size); 307744d92694SMartin K. Petersen 30789ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 307944d92694SMartin K. Petersen map_region(lba, num); 308044d92694SMartin K. Petersen out: 308144d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 308244d92694SMartin K. Petersen 308344d92694SMartin K. Petersen return 0; 308444d92694SMartin K. Petersen } 308544d92694SMartin K. Petersen 3086fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3087fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3088c2248fc9SDouglas Gilbert { 3089c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3090c2248fc9SDouglas Gilbert u32 lba; 3091c2248fc9SDouglas Gilbert u16 num; 3092c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3093c2248fc9SDouglas Gilbert bool unmap = false; 3094c2248fc9SDouglas Gilbert 3095c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3096773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3097c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3098c2248fc9SDouglas Gilbert return check_condition_result; 3099c2248fc9SDouglas Gilbert } else 3100c2248fc9SDouglas Gilbert unmap = true; 3101c2248fc9SDouglas Gilbert } 3102c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3103c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3104773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3105c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3106c2248fc9SDouglas Gilbert return check_condition_result; 3107c2248fc9SDouglas Gilbert } 3108c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3109c2248fc9SDouglas Gilbert } 3110c2248fc9SDouglas Gilbert 3111fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3112fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3113c2248fc9SDouglas Gilbert { 3114c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3115c2248fc9SDouglas Gilbert u64 lba; 3116c2248fc9SDouglas Gilbert u32 num; 3117c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3118c2248fc9SDouglas Gilbert bool unmap = false; 3119c2248fc9SDouglas Gilbert bool ndob = false; 3120c2248fc9SDouglas Gilbert 3121c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3122773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3123c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3124c2248fc9SDouglas Gilbert return check_condition_result; 3125c2248fc9SDouglas Gilbert } else 3126c2248fc9SDouglas Gilbert unmap = true; 3127c2248fc9SDouglas Gilbert } 3128c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3129c2248fc9SDouglas Gilbert ndob = true; 3130c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3131c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3132773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3133c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3134c2248fc9SDouglas Gilbert return check_condition_result; 3135c2248fc9SDouglas Gilbert } 3136c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3137c2248fc9SDouglas Gilbert } 3138c2248fc9SDouglas Gilbert 3139acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3140acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3141acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3142fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3143fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3144acafd0b9SEwan D. Milne { 3145acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3146acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3147acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3148acafd0b9SEwan D. Milne u8 mode; 3149acafd0b9SEwan D. Milne 3150acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3151acafd0b9SEwan D. Milne switch (mode) { 3152acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3153acafd0b9SEwan D. Milne /* set UAs on this device only */ 3154acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3155acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3156acafd0b9SEwan D. Milne break; 3157acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3158acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3159acafd0b9SEwan D. Milne break; 3160acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3161acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3162acafd0b9SEwan D. Milne list_for_each_entry(dp, 3163acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3164acafd0b9SEwan D. Milne dev_list) 3165acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3166acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3167acafd0b9SEwan D. Milne if (devip != dp) 3168acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3169acafd0b9SEwan D. Milne dp->uas_bm); 3170acafd0b9SEwan D. Milne } 3171acafd0b9SEwan D. Milne break; 3172acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3173acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3174acafd0b9SEwan D. Milne list_for_each_entry(dp, 3175acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3176acafd0b9SEwan D. Milne dev_list) 3177acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3178acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3179acafd0b9SEwan D. Milne dp->uas_bm); 3180acafd0b9SEwan D. Milne break; 3181acafd0b9SEwan D. Milne default: 3182acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3183acafd0b9SEwan D. Milne break; 3184acafd0b9SEwan D. Milne } 3185acafd0b9SEwan D. Milne return 0; 3186acafd0b9SEwan D. Milne } 3187acafd0b9SEwan D. Milne 3188fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3189fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 319038d5c833SDouglas Gilbert { 319138d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 319238d5c833SDouglas Gilbert u8 *arr; 319338d5c833SDouglas Gilbert u8 *fake_storep_hold; 319438d5c833SDouglas Gilbert u64 lba; 319538d5c833SDouglas Gilbert u32 dnum; 3196773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 319738d5c833SDouglas Gilbert u8 num; 319838d5c833SDouglas Gilbert unsigned long iflags; 319938d5c833SDouglas Gilbert int ret; 3200d467d31fSDouglas Gilbert int retval = 0; 320138d5c833SDouglas Gilbert 3202d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 320338d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 320438d5c833SDouglas Gilbert if (0 == num) 320538d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 32068475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 320738d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 320838d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 320938d5c833SDouglas Gilbert return check_condition_result; 321038d5c833SDouglas Gilbert } 32118475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 32128475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 321338d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 321438d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 321538d5c833SDouglas Gilbert "to DIF device\n"); 321638d5c833SDouglas Gilbert 321738d5c833SDouglas Gilbert /* inline check_device_access_params() */ 321838d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 321938d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 322038d5c833SDouglas Gilbert return check_condition_result; 322138d5c833SDouglas Gilbert } 322238d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 322338d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 322438d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 322538d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 322638d5c833SDouglas Gilbert return check_condition_result; 322738d5c833SDouglas Gilbert } 3228d467d31fSDouglas Gilbert dnum = 2 * num; 3229d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3230d467d31fSDouglas Gilbert if (NULL == arr) { 3231d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3232d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3233d467d31fSDouglas Gilbert return check_condition_result; 3234d467d31fSDouglas Gilbert } 323538d5c833SDouglas Gilbert 323638d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 323738d5c833SDouglas Gilbert 323838d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 323938d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 324038d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 324138d5c833SDouglas Gilbert fake_storep = arr; 324238d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 324338d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 324438d5c833SDouglas Gilbert if (ret == -1) { 3245d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3246d467d31fSDouglas Gilbert goto cleanup; 3247773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 324838d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 324938d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 325038d5c833SDouglas Gilbert dnum * lb_size, ret); 325138d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 325238d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3253d467d31fSDouglas Gilbert retval = check_condition_result; 3254d467d31fSDouglas Gilbert goto cleanup; 325538d5c833SDouglas Gilbert } 325638d5c833SDouglas Gilbert if (scsi_debug_lbp()) 325738d5c833SDouglas Gilbert map_region(lba, num); 3258d467d31fSDouglas Gilbert cleanup: 325938d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3260d467d31fSDouglas Gilbert kfree(arr); 3261d467d31fSDouglas Gilbert return retval; 326238d5c833SDouglas Gilbert } 326338d5c833SDouglas Gilbert 326444d92694SMartin K. Petersen struct unmap_block_desc { 326544d92694SMartin K. Petersen __be64 lba; 326644d92694SMartin K. Petersen __be32 blocks; 326744d92694SMartin K. Petersen __be32 __reserved; 326844d92694SMartin K. Petersen }; 326944d92694SMartin K. Petersen 3270fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 327144d92694SMartin K. Petersen { 327244d92694SMartin K. Petersen unsigned char *buf; 327344d92694SMartin K. Petersen struct unmap_block_desc *desc; 327444d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 327544d92694SMartin K. Petersen int ret; 32766c78cc06SAkinobu Mita unsigned long iflags; 327744d92694SMartin K. Petersen 327844d92694SMartin K. Petersen 3279c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3280c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3281c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3282c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 328344d92694SMartin K. Petersen 328444d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3285773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3286c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 328744d92694SMartin K. Petersen return check_condition_result; 3288c2248fc9SDouglas Gilbert } 328944d92694SMartin K. Petersen 3290b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3291c2248fc9SDouglas Gilbert if (!buf) { 3292c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3293c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3294c2248fc9SDouglas Gilbert return check_condition_result; 3295c2248fc9SDouglas Gilbert } 3296c2248fc9SDouglas Gilbert 3297c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 329844d92694SMartin K. Petersen 329944d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 330044d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 330144d92694SMartin K. Petersen 330244d92694SMartin K. Petersen desc = (void *)&buf[8]; 330344d92694SMartin K. Petersen 33046c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 33056c78cc06SAkinobu Mita 330644d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 330744d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 330844d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 330944d92694SMartin K. Petersen 3310c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 331144d92694SMartin K. Petersen if (ret) 331244d92694SMartin K. Petersen goto out; 331344d92694SMartin K. Petersen 331444d92694SMartin K. Petersen unmap_region(lba, num); 331544d92694SMartin K. Petersen } 331644d92694SMartin K. Petersen 331744d92694SMartin K. Petersen ret = 0; 331844d92694SMartin K. Petersen 331944d92694SMartin K. Petersen out: 33206c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 332144d92694SMartin K. Petersen kfree(buf); 332244d92694SMartin K. Petersen 332344d92694SMartin K. Petersen return ret; 332444d92694SMartin K. Petersen } 332544d92694SMartin K. Petersen 332644d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 332744d92694SMartin K. Petersen 3328fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3329fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 333044d92694SMartin K. Petersen { 3331c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3332c2248fc9SDouglas Gilbert u64 lba; 3333c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3334c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 333544d92694SMartin K. Petersen int ret; 333644d92694SMartin K. Petersen 3337c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3338c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 333944d92694SMartin K. Petersen 334044d92694SMartin K. Petersen if (alloc_len < 24) 334144d92694SMartin K. Petersen return 0; 334244d92694SMartin K. Petersen 3343c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 334444d92694SMartin K. Petersen if (ret) 334544d92694SMartin K. Petersen return ret; 334644d92694SMartin K. Petersen 3347c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 334844d92694SMartin K. Petersen mapped = map_state(lba, &num); 3349c2248fc9SDouglas Gilbert else { 3350c2248fc9SDouglas Gilbert mapped = 1; 3351c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3352c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3353c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3354c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3355c2248fc9SDouglas Gilbert else 3356c2248fc9SDouglas Gilbert num = 0xffffffff; 3357c2248fc9SDouglas Gilbert } 335844d92694SMartin K. Petersen 335944d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3360c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3361c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3362c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3363c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 336444d92694SMartin K. Petersen 3365c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 336644d92694SMartin K. Petersen } 336744d92694SMartin K. Petersen 3368fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 3369fb0cc8d1SDouglas Gilbert 33708d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 33718d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 33728d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 33738d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 33748d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 33758d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 33768d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 33778d039e22SDouglas Gilbert */ 33781da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 33791da177e4SLinus Torvalds struct sdebug_dev_info *devip) 33801da177e4SLinus Torvalds { 338101123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 33828d039e22SDouglas Gilbert unsigned int alloc_len; 33838d039e22SDouglas Gilbert unsigned char select_report; 33848d039e22SDouglas Gilbert u64 lun; 33858d039e22SDouglas Gilbert struct scsi_lun *lun_p; 3386fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 33878d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 33888d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 33898d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 33908d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 3391fb0cc8d1SDouglas Gilbert int k, j, n, res; 3392fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 3393fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 33941da177e4SLinus Torvalds 339519c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 33968d039e22SDouglas Gilbert 33978d039e22SDouglas Gilbert select_report = cmd[2]; 33988d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 33998d039e22SDouglas Gilbert 34008d039e22SDouglas Gilbert if (alloc_len < 4) { 34018d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 34028d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 34031da177e4SLinus Torvalds return check_condition_result; 34041da177e4SLinus Torvalds } 34058d039e22SDouglas Gilbert 34068d039e22SDouglas Gilbert switch (select_report) { 34078d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 3408773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 34098d039e22SDouglas Gilbert wlun_cnt = 0; 34108d039e22SDouglas Gilbert break; 34118d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 3412c65b1445SDouglas Gilbert lun_cnt = 0; 34138d039e22SDouglas Gilbert wlun_cnt = 1; 34148d039e22SDouglas Gilbert break; 34158d039e22SDouglas Gilbert case 2: /* all LUNs */ 34168d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 34178d039e22SDouglas Gilbert wlun_cnt = 1; 34188d039e22SDouglas Gilbert break; 34198d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 34208d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 34218d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 34228d039e22SDouglas Gilbert default: 34238d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 34248d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 34258d039e22SDouglas Gilbert return check_condition_result; 34268d039e22SDouglas Gilbert } 34278d039e22SDouglas Gilbert 34288d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 3429c65b1445SDouglas Gilbert --lun_cnt; 34308d039e22SDouglas Gilbert 34318d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 3432fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 3433fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 34348d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 34358d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 34368d039e22SDouglas Gilbert 3437fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 34388d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 3439fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 3440fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 3441fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 3442fb0cc8d1SDouglas Gilbert if (k == 0) { 3443fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 3444fb0cc8d1SDouglas Gilbert ++lun_p; 3445fb0cc8d1SDouglas Gilbert j = 1; 3446fb0cc8d1SDouglas Gilbert } 3447fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 3448fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 3449fb0cc8d1SDouglas Gilbert break; 3450fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 3451fb0cc8d1SDouglas Gilbert } 3452fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 3453fb0cc8d1SDouglas Gilbert break; 3454fb0cc8d1SDouglas Gilbert n = j * sz_lun; 3455fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 3456fb0cc8d1SDouglas Gilbert if (res) 3457fb0cc8d1SDouglas Gilbert return res; 3458fb0cc8d1SDouglas Gilbert off_rsp += n; 3459fb0cc8d1SDouglas Gilbert } 3460fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 3461fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 3462fb0cc8d1SDouglas Gilbert ++j; 3463fb0cc8d1SDouglas Gilbert } 3464fb0cc8d1SDouglas Gilbert if (j > 0) 3465fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 34668d039e22SDouglas Gilbert return res; 34671da177e4SLinus Torvalds } 34681da177e4SLinus Torvalds 3469c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3470c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3471c639d14eSFUJITA Tomonori { 3472be4e11beSAkinobu Mita int j; 3473c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3474c639d14eSFUJITA Tomonori unsigned int offset; 3475c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3476be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3477c639d14eSFUJITA Tomonori 3478c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3479b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3480c5af0db9SAkinobu Mita if (!buf) { 348122017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 348222017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3483c5af0db9SAkinobu Mita return check_condition_result; 3484c5af0db9SAkinobu Mita } 3485c639d14eSFUJITA Tomonori 348621a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3487c639d14eSFUJITA Tomonori 3488c639d14eSFUJITA Tomonori offset = 0; 3489be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3490be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3491c639d14eSFUJITA Tomonori 3492be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3493be4e11beSAkinobu Mita kaddr = miter.addr; 3494be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3495be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3496c639d14eSFUJITA Tomonori 3497be4e11beSAkinobu Mita offset += miter.length; 3498c639d14eSFUJITA Tomonori } 3499be4e11beSAkinobu Mita sg_miter_stop(&miter); 3500c639d14eSFUJITA Tomonori kfree(buf); 3501c639d14eSFUJITA Tomonori 3502be4e11beSAkinobu Mita return 0; 3503c639d14eSFUJITA Tomonori } 3504c639d14eSFUJITA Tomonori 3505fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp, 3506fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3507c2248fc9SDouglas Gilbert { 3508c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3509c2248fc9SDouglas Gilbert u64 lba; 3510c2248fc9SDouglas Gilbert u32 num; 3511c2248fc9SDouglas Gilbert int errsts; 3512c2248fc9SDouglas Gilbert 3513c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3514c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3515c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3516c2248fc9SDouglas Gilbert return check_condition_result; 3517c2248fc9SDouglas Gilbert } 3518c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3519c2248fc9SDouglas Gilbert if (errsts) 3520c2248fc9SDouglas Gilbert return errsts; 3521c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3522c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3523c2248fc9SDouglas Gilbert if (errsts) 3524c2248fc9SDouglas Gilbert return errsts; 3525c2248fc9SDouglas Gilbert } 3526c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3527c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3528c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3529c2248fc9SDouglas Gilbert } 3530c2248fc9SDouglas Gilbert 3531c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 3532c4837394SDouglas Gilbert { 3533c4837394SDouglas Gilbert struct sdebug_queue *sqp = sdebug_q_arr; 3534c4837394SDouglas Gilbert 3535c4837394SDouglas Gilbert if (sdebug_mq_active) { 3536c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 3537c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 3538c4837394SDouglas Gilbert 3539c4837394SDouglas Gilbert if (unlikely(hwq >= submit_queues)) { 3540c4837394SDouglas Gilbert pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); 3541c4837394SDouglas Gilbert hwq %= submit_queues; 3542c4837394SDouglas Gilbert } 3543c4837394SDouglas Gilbert pr_debug("tag=%u, hwq=%d\n", tag, hwq); 3544c4837394SDouglas Gilbert return sqp + hwq; 3545c4837394SDouglas Gilbert } else 3546c4837394SDouglas Gilbert return sqp; 3547c4837394SDouglas Gilbert } 3548c4837394SDouglas Gilbert 3549c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 3550fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 35511da177e4SLinus Torvalds { 3552c4837394SDouglas Gilbert int qc_idx; 3553cbf67842SDouglas Gilbert int retiring = 0; 35541da177e4SLinus Torvalds unsigned long iflags; 3555c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3556cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3557cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3558cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 35591da177e4SLinus Torvalds 3560c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 3561c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 3562c4837394SDouglas Gilbert if (sdebug_statistics) { 3563cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3564c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 3565c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 3566c4837394SDouglas Gilbert } 3567c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 3568c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 35691da177e4SLinus Torvalds return; 35701da177e4SLinus Torvalds } 3571c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3572c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 3573cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3574b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 3575c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3576c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 3577c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 35781da177e4SLinus Torvalds return; 35791da177e4SLinus Torvalds } 3580cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3581f46eb0e9SDouglas Gilbert if (likely(devip)) 3582cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3583cbf67842SDouglas Gilbert else 3584c1287970STomas Winkler pr_err("devip=NULL\n"); 3585f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3586cbf67842SDouglas Gilbert retiring = 1; 3587cbf67842SDouglas Gilbert 3588cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3589c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 3590c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3591c1287970STomas Winkler pr_err("Unexpected completion\n"); 3592cbf67842SDouglas Gilbert return; 35931da177e4SLinus Torvalds } 35941da177e4SLinus Torvalds 3595cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3596cbf67842SDouglas Gilbert int k, retval; 3597cbf67842SDouglas Gilbert 3598cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3599c4837394SDouglas Gilbert if (qc_idx >= retval) { 3600c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3601c1287970STomas Winkler pr_err("index %d too large\n", retval); 3602cbf67842SDouglas Gilbert return; 3603cbf67842SDouglas Gilbert } 3604c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 3605773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3606cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3607cbf67842SDouglas Gilbert else 3608cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3609cbf67842SDouglas Gilbert } 3610c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3611cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3612cbf67842SDouglas Gilbert } 3613cbf67842SDouglas Gilbert 3614cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3615fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3616cbf67842SDouglas Gilbert { 3617a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 3618a10bc12aSDouglas Gilbert hrt); 3619a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3620cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3621cbf67842SDouglas Gilbert } 36221da177e4SLinus Torvalds 3623a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 3624fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 3625a10bc12aSDouglas Gilbert { 3626a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 3627a10bc12aSDouglas Gilbert ew.work); 3628a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3629a10bc12aSDouglas Gilbert } 3630a10bc12aSDouglas Gilbert 363109ba24c1SDouglas Gilbert static bool got_shared_uuid; 3632bf476433SChristoph Hellwig static uuid_t shared_uuid; 363309ba24c1SDouglas Gilbert 3634fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 3635fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 36365cb2fc06SFUJITA Tomonori { 36375cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 36385cb2fc06SFUJITA Tomonori 36395cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 36405cb2fc06SFUJITA Tomonori if (devip) { 364109ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 3642bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 364309ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 364409ba24c1SDouglas Gilbert if (got_shared_uuid) 364509ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 364609ba24c1SDouglas Gilbert else { 3647bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 364809ba24c1SDouglas Gilbert got_shared_uuid = true; 364909ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 365009ba24c1SDouglas Gilbert } 365109ba24c1SDouglas Gilbert } 36525cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 36535cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 36545cb2fc06SFUJITA Tomonori } 36555cb2fc06SFUJITA Tomonori return devip; 36565cb2fc06SFUJITA Tomonori } 36575cb2fc06SFUJITA Tomonori 3658f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 36591da177e4SLinus Torvalds { 36601da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 36611da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 3662f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 36631da177e4SLinus Torvalds 3664d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 36651da177e4SLinus Torvalds if (!sdbg_host) { 3666c1287970STomas Winkler pr_err("Host info NULL\n"); 36671da177e4SLinus Torvalds return NULL; 36681da177e4SLinus Torvalds } 36691da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 36701da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 36711da177e4SLinus Torvalds (devip->target == sdev->id) && 36721da177e4SLinus Torvalds (devip->lun == sdev->lun)) 36731da177e4SLinus Torvalds return devip; 36741da177e4SLinus Torvalds else { 36751da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 36761da177e4SLinus Torvalds open_devip = devip; 36771da177e4SLinus Torvalds } 36781da177e4SLinus Torvalds } 36795cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 36805cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 36815cb2fc06SFUJITA Tomonori if (!open_devip) { 3682c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 36831da177e4SLinus Torvalds return NULL; 36841da177e4SLinus Torvalds } 36851da177e4SLinus Torvalds } 3686a75869d1SFUJITA Tomonori 36871da177e4SLinus Torvalds open_devip->channel = sdev->channel; 36881da177e4SLinus Torvalds open_devip->target = sdev->id; 36891da177e4SLinus Torvalds open_devip->lun = sdev->lun; 36901da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3691cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3692cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3693c2248fc9SDouglas Gilbert open_devip->used = true; 36941da177e4SLinus Torvalds return open_devip; 36951da177e4SLinus Torvalds } 36961da177e4SLinus Torvalds 36978dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 36981da177e4SLinus Torvalds { 3699773642d9SDouglas Gilbert if (sdebug_verbose) 3700c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 37018dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 370275ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 37038dea0d02SFUJITA Tomonori return 0; 37048dea0d02SFUJITA Tomonori } 37051da177e4SLinus Torvalds 37068dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 37078dea0d02SFUJITA Tomonori { 3708f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3709f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3710a34c4e98SFUJITA Tomonori 3711773642d9SDouglas Gilbert if (sdebug_verbose) 3712c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 37138dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 3714b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 3715b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 3716b01f6f83SDouglas Gilbert if (devip == NULL) { 3717f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 3718b01f6f83SDouglas Gilbert if (devip == NULL) 37198dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3720f46eb0e9SDouglas Gilbert } 3721c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 37226bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 3723773642d9SDouglas Gilbert if (sdebug_no_uld) 372478d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 37259b760fd8SDouglas Gilbert config_cdb_len(sdp); 37268dea0d02SFUJITA Tomonori return 0; 37278dea0d02SFUJITA Tomonori } 37288dea0d02SFUJITA Tomonori 37298dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 37308dea0d02SFUJITA Tomonori { 37318dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 37328dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 37338dea0d02SFUJITA Tomonori 3734773642d9SDouglas Gilbert if (sdebug_verbose) 3735c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 37368dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 37378dea0d02SFUJITA Tomonori if (devip) { 373825985edcSLucas De Marchi /* make this slot available for re-use */ 3739c2248fc9SDouglas Gilbert devip->used = false; 37408dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 37418dea0d02SFUJITA Tomonori } 37428dea0d02SFUJITA Tomonori } 37438dea0d02SFUJITA Tomonori 3744c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp) 3745c4837394SDouglas Gilbert { 3746c4837394SDouglas Gilbert if (!sd_dp) 3747c4837394SDouglas Gilbert return; 3748c4837394SDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) 3749c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3750c4837394SDouglas Gilbert else if (sdebug_jdelay < 0) 3751c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3752c4837394SDouglas Gilbert } 3753c4837394SDouglas Gilbert 3754a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 3755a10bc12aSDouglas Gilbert returns false */ 3756a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 37578dea0d02SFUJITA Tomonori { 37588dea0d02SFUJITA Tomonori unsigned long iflags; 3759c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 3760c4837394SDouglas Gilbert struct sdebug_queue *sqp; 37618dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3762cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3763a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 37648dea0d02SFUJITA Tomonori 3765c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3766c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3767773642d9SDouglas Gilbert qmax = sdebug_max_queue; 3768cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3769cbf67842SDouglas Gilbert if (r_qmax > qmax) 3770cbf67842SDouglas Gilbert qmax = r_qmax; 3771cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3772c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3773c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3774a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 3775a10bc12aSDouglas Gilbert continue; 3776c4837394SDouglas Gilbert /* found */ 3777db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3778db525fceSDouglas Gilbert cmnd->device->hostdata; 3779db525fceSDouglas Gilbert if (devip) 3780db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3781db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3782a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3783c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3784c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3785c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3786a10bc12aSDouglas Gilbert return true; 37878dea0d02SFUJITA Tomonori } 3788cbf67842SDouglas Gilbert } 3789c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3790c4837394SDouglas Gilbert } 3791a10bc12aSDouglas Gilbert return false; 37928dea0d02SFUJITA Tomonori } 37938dea0d02SFUJITA Tomonori 3794a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 37958dea0d02SFUJITA Tomonori static void stop_all_queued(void) 37968dea0d02SFUJITA Tomonori { 37978dea0d02SFUJITA Tomonori unsigned long iflags; 3798c4837394SDouglas Gilbert int j, k; 3799c4837394SDouglas Gilbert struct sdebug_queue *sqp; 38008dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3801cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3802a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 38038dea0d02SFUJITA Tomonori 3804c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3805c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3806c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3807c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3808c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3809c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 3810a10bc12aSDouglas Gilbert continue; 3811db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3812db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3813db525fceSDouglas Gilbert if (devip) 3814db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3815db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3816a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3817c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3818c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3819c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3820c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 38218dea0d02SFUJITA Tomonori } 38228dea0d02SFUJITA Tomonori } 3823c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3824c4837394SDouglas Gilbert } 3825cbf67842SDouglas Gilbert } 3826cbf67842SDouglas Gilbert 3827cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3828cbf67842SDouglas Gilbert static void free_all_queued(void) 3829cbf67842SDouglas Gilbert { 3830c4837394SDouglas Gilbert int j, k; 3831c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3832cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3833cbf67842SDouglas Gilbert 3834c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3835c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3836c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3837a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 3838a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 3839cbf67842SDouglas Gilbert } 38401da177e4SLinus Torvalds } 3841c4837394SDouglas Gilbert } 38421da177e4SLinus Torvalds 38431da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 38441da177e4SLinus Torvalds { 3845a10bc12aSDouglas Gilbert bool ok; 3846a10bc12aSDouglas Gilbert 38471da177e4SLinus Torvalds ++num_aborts; 3848cbf67842SDouglas Gilbert if (SCpnt) { 3849a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 3850a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3851a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3852a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 3853a10bc12aSDouglas Gilbert ok ? "" : " not"); 3854cbf67842SDouglas Gilbert } 38551da177e4SLinus Torvalds return SUCCESS; 38561da177e4SLinus Torvalds } 38571da177e4SLinus Torvalds 38581da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 38591da177e4SLinus Torvalds { 38601da177e4SLinus Torvalds ++num_dev_resets; 3861cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3862cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3863f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3864f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3865cbf67842SDouglas Gilbert 3866773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3867cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 38681da177e4SLinus Torvalds if (devip) 3869cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 38701da177e4SLinus Torvalds } 38711da177e4SLinus Torvalds return SUCCESS; 38721da177e4SLinus Torvalds } 38731da177e4SLinus Torvalds 3874cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3875cbf67842SDouglas Gilbert { 3876cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3877cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3878cbf67842SDouglas Gilbert struct scsi_device *sdp; 3879cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3880cbf67842SDouglas Gilbert int k = 0; 3881cbf67842SDouglas Gilbert 3882cbf67842SDouglas Gilbert ++num_target_resets; 3883cbf67842SDouglas Gilbert if (!SCpnt) 3884cbf67842SDouglas Gilbert goto lie; 3885cbf67842SDouglas Gilbert sdp = SCpnt->device; 3886cbf67842SDouglas Gilbert if (!sdp) 3887cbf67842SDouglas Gilbert goto lie; 3888773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3889cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3890cbf67842SDouglas Gilbert hp = sdp->host; 3891cbf67842SDouglas Gilbert if (!hp) 3892cbf67842SDouglas Gilbert goto lie; 3893cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3894cbf67842SDouglas Gilbert if (sdbg_host) { 3895cbf67842SDouglas Gilbert list_for_each_entry(devip, 3896cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3897cbf67842SDouglas Gilbert dev_list) 3898cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3899cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3900cbf67842SDouglas Gilbert ++k; 3901cbf67842SDouglas Gilbert } 3902cbf67842SDouglas Gilbert } 3903773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3904cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3905cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3906cbf67842SDouglas Gilbert lie: 3907cbf67842SDouglas Gilbert return SUCCESS; 3908cbf67842SDouglas Gilbert } 3909cbf67842SDouglas Gilbert 39101da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 39111da177e4SLinus Torvalds { 39121da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3913cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 39141da177e4SLinus Torvalds struct scsi_device * sdp; 39151da177e4SLinus Torvalds struct Scsi_Host * hp; 3916cbf67842SDouglas Gilbert int k = 0; 39171da177e4SLinus Torvalds 39181da177e4SLinus Torvalds ++num_bus_resets; 3919cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3920cbf67842SDouglas Gilbert goto lie; 3921cbf67842SDouglas Gilbert sdp = SCpnt->device; 3922773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3923cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3924cbf67842SDouglas Gilbert hp = sdp->host; 3925cbf67842SDouglas Gilbert if (hp) { 3926d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 39271da177e4SLinus Torvalds if (sdbg_host) { 3928cbf67842SDouglas Gilbert list_for_each_entry(devip, 39291da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3930cbf67842SDouglas Gilbert dev_list) { 3931cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3932cbf67842SDouglas Gilbert ++k; 39331da177e4SLinus Torvalds } 39341da177e4SLinus Torvalds } 3935cbf67842SDouglas Gilbert } 3936773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3937cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3938cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3939cbf67842SDouglas Gilbert lie: 39401da177e4SLinus Torvalds return SUCCESS; 39411da177e4SLinus Torvalds } 39421da177e4SLinus Torvalds 39431da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 39441da177e4SLinus Torvalds { 39451da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3946cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3947cbf67842SDouglas Gilbert int k = 0; 39481da177e4SLinus Torvalds 39491da177e4SLinus Torvalds ++num_host_resets; 3950773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3951cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 39521da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 39531da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3954cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3955cbf67842SDouglas Gilbert dev_list) { 3956cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3957cbf67842SDouglas Gilbert ++k; 3958cbf67842SDouglas Gilbert } 39591da177e4SLinus Torvalds } 39601da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 39611da177e4SLinus Torvalds stop_all_queued(); 3962773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3963cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3964cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 39651da177e4SLinus Torvalds return SUCCESS; 39661da177e4SLinus Torvalds } 39671da177e4SLinus Torvalds 3968f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 39695f2578e5SFUJITA Tomonori unsigned long store_size) 39701da177e4SLinus Torvalds { 39711da177e4SLinus Torvalds struct partition * pp; 39721da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 39731da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 39741da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 39751da177e4SLinus Torvalds 39761da177e4SLinus Torvalds /* assume partition table already zeroed */ 3977773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 39781da177e4SLinus Torvalds return; 3979773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 3980773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 3981c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 39821da177e4SLinus Torvalds } 3983c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 39841da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 3985773642d9SDouglas Gilbert / sdebug_num_parts; 39861da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 39871da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 3988773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 39891da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 39901da177e4SLinus Torvalds * heads_by_sects; 3991773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 3992773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 39931da177e4SLinus Torvalds 39941da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 39951da177e4SLinus Torvalds ramp[511] = 0xAA; 39961da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 39971da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 39981da177e4SLinus Torvalds start_sec = starts[k]; 39991da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 40001da177e4SLinus Torvalds pp->boot_ind = 0; 40011da177e4SLinus Torvalds 40021da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 40031da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 40041da177e4SLinus Torvalds / sdebug_sectors_per; 40051da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 40061da177e4SLinus Torvalds 40071da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 40081da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 40091da177e4SLinus Torvalds / sdebug_sectors_per; 40101da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 40111da177e4SLinus Torvalds 4012150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 4013150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 40141da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 40151da177e4SLinus Torvalds } 40161da177e4SLinus Torvalds } 40171da177e4SLinus Torvalds 4018c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 4019c4837394SDouglas Gilbert { 4020c4837394SDouglas Gilbert int j; 4021c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4022c4837394SDouglas Gilbert 4023c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 4024c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 4025c4837394SDouglas Gilbert } 4026c4837394SDouglas Gilbert 4027c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 4028c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 4029c4837394SDouglas Gilbert */ 4030c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 4031c4837394SDouglas Gilbert { 4032c4837394SDouglas Gilbert int count, modulo; 4033c4837394SDouglas Gilbert 4034c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 4035c4837394SDouglas Gilbert if (modulo < 2) 4036c4837394SDouglas Gilbert return; 4037c4837394SDouglas Gilbert block_unblock_all_queues(true); 4038c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 4039c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 4040c4837394SDouglas Gilbert block_unblock_all_queues(false); 4041c4837394SDouglas Gilbert } 4042c4837394SDouglas Gilbert 4043c4837394SDouglas Gilbert static void clear_queue_stats(void) 4044c4837394SDouglas Gilbert { 4045c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 4046c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 4047c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 4048c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4049c4837394SDouglas Gilbert } 4050c4837394SDouglas Gilbert 4051c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 4052c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 4053c4837394SDouglas Gilbert { 4054c4837394SDouglas Gilbert if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) 4055c4837394SDouglas Gilbert return; 4056c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 4057c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 4058c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 4059c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 4060c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 40617ee6d1b4SBart Van Assche sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts); 4062c4837394SDouglas Gilbert } 4063c4837394SDouglas Gilbert 4064c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 4065c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 4066c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 4067c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 4068c4837394SDouglas Gilbert */ 4069fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 4070cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 40711da177e4SLinus Torvalds { 4072cbf67842SDouglas Gilbert unsigned long iflags; 4073cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 4074c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4075c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4076299b6c07STomas Winkler struct scsi_device *sdp; 4077a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 40781da177e4SLinus Torvalds 4079b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 4080b01f6f83SDouglas Gilbert if (scsi_result == 0) 4081f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 4082f46eb0e9SDouglas Gilbert goto respond_in_thread; 40831da177e4SLinus Torvalds } 4084299b6c07STomas Winkler sdp = cmnd->device; 4085299b6c07STomas Winkler 4086f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && scsi_result)) 4087cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 4088cbf67842SDouglas Gilbert __func__, scsi_result); 4089cd62b7daSDouglas Gilbert if (delta_jiff == 0) 4090cd62b7daSDouglas Gilbert goto respond_in_thread; 40911da177e4SLinus Torvalds 4092cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 4093c4837394SDouglas Gilbert sqp = get_queue(cmnd); 4094c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4095c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 4096c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4097c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4098c4837394SDouglas Gilbert } 4099cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 4100cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 4101cbf67842SDouglas Gilbert inject = 0; 4102f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 4103cd62b7daSDouglas Gilbert if (scsi_result) { 4104c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4105cd62b7daSDouglas Gilbert goto respond_in_thread; 4106cd62b7daSDouglas Gilbert } else 4107cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4108c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 4109773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 4110f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 4111cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 4112cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 4113773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 4114cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4115cbf67842SDouglas Gilbert inject = 1; 4116cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 41171da177e4SLinus Torvalds } 4118cbf67842SDouglas Gilbert } 4119cbf67842SDouglas Gilbert 4120c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 4121f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 4122c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4123cd62b7daSDouglas Gilbert if (scsi_result) 4124cd62b7daSDouglas Gilbert goto respond_in_thread; 4125773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 4126cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4127773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 4128cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4129cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 4130773642d9SDouglas Gilbert __func__, sdebug_max_queue, 4131cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 4132cbf67842SDouglas Gilbert "report: host busy")); 4133cd62b7daSDouglas Gilbert if (scsi_result) 4134cd62b7daSDouglas Gilbert goto respond_in_thread; 4135cd62b7daSDouglas Gilbert else 4136cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 41371da177e4SLinus Torvalds } 4138c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 4139cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4140c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 41411da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4142c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 4143cbf67842SDouglas Gilbert cmnd->result = scsi_result; 4144a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 4145c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4146c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 4147c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 4148b01f6f83SDouglas Gilbert if (delta_jiff > 0 || sdebug_ndelay > 0) { 4149b333a819SDouglas Gilbert ktime_t kt; 4150cbf67842SDouglas Gilbert 4151b333a819SDouglas Gilbert if (delta_jiff > 0) { 415213f6b610SArnd Bergmann kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ)); 4153b333a819SDouglas Gilbert } else 41548b0e1953SThomas Gleixner kt = sdebug_ndelay; 4155a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4156a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 4157a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4158cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4159a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4160a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 4161c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 4162a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 4163c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4164c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4165cbf67842SDouglas Gilbert } 4166c4837394SDouglas Gilbert if (sdebug_statistics) 4167c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4168c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 4169c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 4170a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4171a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); 4172a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4173cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4174a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4175c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4176c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4177a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 4178cbf67842SDouglas Gilbert } 4179c4837394SDouglas Gilbert if (sdebug_statistics) 4180c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4181a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 4182cbf67842SDouglas Gilbert } 4183f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 4184f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 4185cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4186cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4187cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4188cbf67842SDouglas Gilbert "status: TASK SET FULL"); 41891da177e4SLinus Torvalds return 0; 4190cd62b7daSDouglas Gilbert 4191cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4192cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4193cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4194cd62b7daSDouglas Gilbert return 0; 41951da177e4SLinus Torvalds } 4196cbf67842SDouglas Gilbert 419723183910SDouglas Gilbert /* Note: The following macros create attribute files in the 419823183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 419923183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 420023183910SDouglas Gilbert as it can when the corresponding attribute in the 420123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 420223183910SDouglas Gilbert */ 4203773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 4204773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 42059b760fd8SDouglas Gilbert module_param_named(cdb_len, sdebug_cdb_len, int, 0644); 4206773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 4207c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 4208773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 4209773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 4210773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 4211773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 4212773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 4213773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 4214773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 4215773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 4216e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id, 4217e5203cf0SHannes Reinecke sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR); 4218e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 4219e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR); 4220e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 4221e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR); 4222773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 4223773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 4224773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 4225773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 4226773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 4227773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 4228773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 4229773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 4230773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 4231773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 4232773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 4233773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 4234773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 4235773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 4236773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 423786e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 4238773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 4239773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 4240773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 4241773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 4242c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 4243773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 4244c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 4245773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 4246773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 4247773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 4248773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 4249773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 425009ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 4251773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 425223183910SDouglas Gilbert S_IRUGO | S_IWUSR); 4253773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 42545b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 42551da177e4SLinus Torvalds 42561da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 42571da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 42581da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4259b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 42601da177e4SLinus Torvalds 42611da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 42625b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 42639b760fd8SDouglas Gilbert MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)"); 42640759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4265cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4266c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 42675b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 42685b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4269c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4270beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 427123183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 42725b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4273185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 4274e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 4275e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 42769b760fd8SDouglas Gilbert MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"" 42779b760fd8SDouglas Gilbert SDEBUG_VERSION "\")"); 42785b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 42795b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 42805b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4281760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz, 4282760f3b03SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 42835b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4284c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4285cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4286cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4287c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 428878d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 42891da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4290c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 429132c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 42926f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 42935b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 429486e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 42951da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4296d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4297760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 4298ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4299c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 4300c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 4301c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 43025b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 43035b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 43046014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 43056014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 430609ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 430709ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 4308c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 43095b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 43105b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 43111da177e4SLinus Torvalds 4312760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 4313760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 43141da177e4SLinus Torvalds 43151da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 43161da177e4SLinus Torvalds { 4317c4837394SDouglas Gilbert int k; 4318c4837394SDouglas Gilbert 4319760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 4320760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 4321760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 4322c4837394SDouglas Gilbert return sdebug_info; 4323760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 4324760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 4325760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 4326760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 43271da177e4SLinus Torvalds return sdebug_info; 43281da177e4SLinus Torvalds } 43291da177e4SLinus Torvalds 4330cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4331fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 4332fd32119bSDouglas Gilbert int length) 43331da177e4SLinus Torvalds { 43341da177e4SLinus Torvalds char arr[16]; 4335c8ed555aSAl Viro int opts; 43361da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 43371da177e4SLinus Torvalds 43381da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 43391da177e4SLinus Torvalds return -EACCES; 43401da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 43411da177e4SLinus Torvalds arr[minLen] = '\0'; 4342c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 43431da177e4SLinus Torvalds return -EINVAL; 4344773642d9SDouglas Gilbert sdebug_opts = opts; 4345773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4346773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4347773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4348c4837394SDouglas Gilbert tweak_cmnd_count(); 43491da177e4SLinus Torvalds return length; 43501da177e4SLinus Torvalds } 4351c8ed555aSAl Viro 4352cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4353cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4354cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4355c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4356c8ed555aSAl Viro { 4357c4837394SDouglas Gilbert int f, j, l; 4358c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4359cbf67842SDouglas Gilbert 4360c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 4361c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 4362c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 4363c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 4364c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 4365c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 4366c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 4367c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 4368c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 4369c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 4370c4837394SDouglas Gilbert num_aborts); 4371c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 4372c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 4373c4837394SDouglas Gilbert num_host_resets); 4374c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 4375c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 4376c4837394SDouglas Gilbert seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", 4377c4837394SDouglas Gilbert TICK_NSEC / 1000, "statistics", sdebug_statistics, 4378c4837394SDouglas Gilbert sdebug_mq_active); 4379c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 4380c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 4381c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 4382c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 4383c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 4384cbf67842SDouglas Gilbert 4385c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 4386c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4387c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 4388c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 4389773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4390c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 4391c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 4392c4837394SDouglas Gilbert "first,last bits", f, l); 4393c4837394SDouglas Gilbert } 4394cbf67842SDouglas Gilbert } 4395c8ed555aSAl Viro return 0; 43961da177e4SLinus Torvalds } 43971da177e4SLinus Torvalds 439882069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 43991da177e4SLinus Torvalds { 4400c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 44011da177e4SLinus Torvalds } 4402c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 4403c4837394SDouglas Gilbert * of delay is jiffies. 4404c4837394SDouglas Gilbert */ 440582069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 440682069379SAkinobu Mita size_t count) 44071da177e4SLinus Torvalds { 4408c2206098SDouglas Gilbert int jdelay, res; 44091da177e4SLinus Torvalds 4410b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 4411cbf67842SDouglas Gilbert res = count; 4412c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4413c4837394SDouglas Gilbert int j, k; 4414c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4415cbf67842SDouglas Gilbert 4416c4837394SDouglas Gilbert block_unblock_all_queues(true); 4417c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4418c4837394SDouglas Gilbert ++j, ++sqp) { 4419c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4420c4837394SDouglas Gilbert sdebug_max_queue); 4421c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4422c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4423c4837394SDouglas Gilbert break; 4424c4837394SDouglas Gilbert } 4425c4837394SDouglas Gilbert } 4426c4837394SDouglas Gilbert if (res > 0) { 4427a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4428a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4429a10bc12aSDouglas Gilbert free_all_queued(); 4430c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4431773642d9SDouglas Gilbert sdebug_ndelay = 0; 44321da177e4SLinus Torvalds } 4433c4837394SDouglas Gilbert block_unblock_all_queues(false); 4434cbf67842SDouglas Gilbert } 4435cbf67842SDouglas Gilbert return res; 44361da177e4SLinus Torvalds } 44371da177e4SLinus Torvalds return -EINVAL; 44381da177e4SLinus Torvalds } 443982069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 44401da177e4SLinus Torvalds 4441cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4442cbf67842SDouglas Gilbert { 4443773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4444cbf67842SDouglas Gilbert } 4445cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4446c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4447cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4448cbf67842SDouglas Gilbert size_t count) 4449cbf67842SDouglas Gilbert { 4450c4837394SDouglas Gilbert int ndelay, res; 4451cbf67842SDouglas Gilbert 4452cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4453c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 4454cbf67842SDouglas Gilbert res = count; 4455773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4456c4837394SDouglas Gilbert int j, k; 4457c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4458c4837394SDouglas Gilbert 4459c4837394SDouglas Gilbert block_unblock_all_queues(true); 4460c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4461c4837394SDouglas Gilbert ++j, ++sqp) { 4462c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4463c4837394SDouglas Gilbert sdebug_max_queue); 4464c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4465c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4466c4837394SDouglas Gilbert break; 4467c4837394SDouglas Gilbert } 4468c4837394SDouglas Gilbert } 4469c4837394SDouglas Gilbert if (res > 0) { 4470a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4471a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4472a10bc12aSDouglas Gilbert free_all_queued(); 4473773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4474c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4475c2206098SDouglas Gilbert : DEF_JDELAY; 4476cbf67842SDouglas Gilbert } 4477c4837394SDouglas Gilbert block_unblock_all_queues(false); 4478cbf67842SDouglas Gilbert } 4479cbf67842SDouglas Gilbert return res; 4480cbf67842SDouglas Gilbert } 4481cbf67842SDouglas Gilbert return -EINVAL; 4482cbf67842SDouglas Gilbert } 4483cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4484cbf67842SDouglas Gilbert 448582069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 44861da177e4SLinus Torvalds { 4487773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 44881da177e4SLinus Torvalds } 44891da177e4SLinus Torvalds 449082069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 449182069379SAkinobu Mita size_t count) 44921da177e4SLinus Torvalds { 44931da177e4SLinus Torvalds int opts; 44941da177e4SLinus Torvalds char work[20]; 44951da177e4SLinus Torvalds 44961da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 449748a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 44981da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 44991da177e4SLinus Torvalds goto opts_done; 45001da177e4SLinus Torvalds } else { 45011da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 45021da177e4SLinus Torvalds goto opts_done; 45031da177e4SLinus Torvalds } 45041da177e4SLinus Torvalds } 45051da177e4SLinus Torvalds return -EINVAL; 45061da177e4SLinus Torvalds opts_done: 4507773642d9SDouglas Gilbert sdebug_opts = opts; 4508773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4509773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4510c4837394SDouglas Gilbert tweak_cmnd_count(); 45111da177e4SLinus Torvalds return count; 45121da177e4SLinus Torvalds } 451382069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 45141da177e4SLinus Torvalds 451582069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 45161da177e4SLinus Torvalds { 4517773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 45181da177e4SLinus Torvalds } 451982069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 452082069379SAkinobu Mita size_t count) 45211da177e4SLinus Torvalds { 45221da177e4SLinus Torvalds int n; 45231da177e4SLinus Torvalds 45241da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4525773642d9SDouglas Gilbert sdebug_ptype = n; 45261da177e4SLinus Torvalds return count; 45271da177e4SLinus Torvalds } 45281da177e4SLinus Torvalds return -EINVAL; 45291da177e4SLinus Torvalds } 453082069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 45311da177e4SLinus Torvalds 453282069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 45331da177e4SLinus Torvalds { 4534773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 45351da177e4SLinus Torvalds } 453682069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 453782069379SAkinobu Mita size_t count) 45381da177e4SLinus Torvalds { 45391da177e4SLinus Torvalds int n; 45401da177e4SLinus Torvalds 45411da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4542773642d9SDouglas Gilbert sdebug_dsense = n; 45431da177e4SLinus Torvalds return count; 45441da177e4SLinus Torvalds } 45451da177e4SLinus Torvalds return -EINVAL; 45461da177e4SLinus Torvalds } 454782069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 45481da177e4SLinus Torvalds 454982069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 455023183910SDouglas Gilbert { 4551773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 455223183910SDouglas Gilbert } 455382069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 455482069379SAkinobu Mita size_t count) 455523183910SDouglas Gilbert { 455623183910SDouglas Gilbert int n; 455723183910SDouglas Gilbert 455823183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4559cbf67842SDouglas Gilbert n = (n > 0); 4560773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 4561773642d9SDouglas Gilbert if (sdebug_fake_rw != n) { 4562cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4563cbf67842SDouglas Gilbert unsigned long sz = 4564773642d9SDouglas Gilbert (unsigned long)sdebug_dev_size_mb * 4565cbf67842SDouglas Gilbert 1048576; 4566cbf67842SDouglas Gilbert 4567cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4568cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4569c1287970STomas Winkler pr_err("out of memory, 9\n"); 4570cbf67842SDouglas Gilbert return -ENOMEM; 4571cbf67842SDouglas Gilbert } 4572cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4573cbf67842SDouglas Gilbert } 4574773642d9SDouglas Gilbert sdebug_fake_rw = n; 4575cbf67842SDouglas Gilbert } 457623183910SDouglas Gilbert return count; 457723183910SDouglas Gilbert } 457823183910SDouglas Gilbert return -EINVAL; 457923183910SDouglas Gilbert } 458082069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 458123183910SDouglas Gilbert 458282069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4583c65b1445SDouglas Gilbert { 4584773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 4585c65b1445SDouglas Gilbert } 458682069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 458782069379SAkinobu Mita size_t count) 4588c65b1445SDouglas Gilbert { 4589c65b1445SDouglas Gilbert int n; 4590c65b1445SDouglas Gilbert 4591c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4592773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 4593c65b1445SDouglas Gilbert return count; 4594c65b1445SDouglas Gilbert } 4595c65b1445SDouglas Gilbert return -EINVAL; 4596c65b1445SDouglas Gilbert } 459782069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4598c65b1445SDouglas Gilbert 459982069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 46001da177e4SLinus Torvalds { 4601773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 46021da177e4SLinus Torvalds } 460382069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 460482069379SAkinobu Mita size_t count) 46051da177e4SLinus Torvalds { 46061da177e4SLinus Torvalds int n; 46071da177e4SLinus Torvalds 46081da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4609773642d9SDouglas Gilbert sdebug_num_tgts = n; 46101da177e4SLinus Torvalds sdebug_max_tgts_luns(); 46111da177e4SLinus Torvalds return count; 46121da177e4SLinus Torvalds } 46131da177e4SLinus Torvalds return -EINVAL; 46141da177e4SLinus Torvalds } 461582069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 46161da177e4SLinus Torvalds 461782069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 46181da177e4SLinus Torvalds { 4619773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 46201da177e4SLinus Torvalds } 462182069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 46221da177e4SLinus Torvalds 462382069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 46241da177e4SLinus Torvalds { 4625773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 46261da177e4SLinus Torvalds } 462782069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 46281da177e4SLinus Torvalds 462982069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 46301da177e4SLinus Torvalds { 4631773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 46321da177e4SLinus Torvalds } 463382069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 463482069379SAkinobu Mita size_t count) 46351da177e4SLinus Torvalds { 46361da177e4SLinus Torvalds int nth; 46371da177e4SLinus Torvalds 46381da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 4639773642d9SDouglas Gilbert sdebug_every_nth = nth; 4640c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 4641c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 4642c4837394SDouglas Gilbert sdebug_statistics = true; 4643c4837394SDouglas Gilbert } 4644c4837394SDouglas Gilbert tweak_cmnd_count(); 46451da177e4SLinus Torvalds return count; 46461da177e4SLinus Torvalds } 46471da177e4SLinus Torvalds return -EINVAL; 46481da177e4SLinus Torvalds } 464982069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 46501da177e4SLinus Torvalds 465182069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 46521da177e4SLinus Torvalds { 4653773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 46541da177e4SLinus Torvalds } 465582069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 465682069379SAkinobu Mita size_t count) 46571da177e4SLinus Torvalds { 46581da177e4SLinus Torvalds int n; 465919c8ead7SEwan D. Milne bool changed; 46601da177e4SLinus Torvalds 46611da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 46628d039e22SDouglas Gilbert if (n > 256) { 46638d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 46648d039e22SDouglas Gilbert return -EINVAL; 46658d039e22SDouglas Gilbert } 4666773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 4667773642d9SDouglas Gilbert sdebug_max_luns = n; 46681da177e4SLinus Torvalds sdebug_max_tgts_luns(); 4669773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 467019c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 467119c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 467219c8ead7SEwan D. Milne 467319c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 467419c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 467519c8ead7SEwan D. Milne host_list) { 467619c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 467719c8ead7SEwan D. Milne dev_list) { 467819c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 467919c8ead7SEwan D. Milne dp->uas_bm); 468019c8ead7SEwan D. Milne } 468119c8ead7SEwan D. Milne } 468219c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 468319c8ead7SEwan D. Milne } 46841da177e4SLinus Torvalds return count; 46851da177e4SLinus Torvalds } 46861da177e4SLinus Torvalds return -EINVAL; 46871da177e4SLinus Torvalds } 468882069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 46891da177e4SLinus Torvalds 469082069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 469178d4e5a0SDouglas Gilbert { 4692773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 469378d4e5a0SDouglas Gilbert } 4694cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4695cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 469682069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 469782069379SAkinobu Mita size_t count) 469878d4e5a0SDouglas Gilbert { 4699c4837394SDouglas Gilbert int j, n, k, a; 4700c4837394SDouglas Gilbert struct sdebug_queue *sqp; 470178d4e5a0SDouglas Gilbert 470278d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 4703c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 4704c4837394SDouglas Gilbert block_unblock_all_queues(true); 4705c4837394SDouglas Gilbert k = 0; 4706c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4707c4837394SDouglas Gilbert ++j, ++sqp) { 4708c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 4709c4837394SDouglas Gilbert if (a > k) 4710c4837394SDouglas Gilbert k = a; 4711c4837394SDouglas Gilbert } 4712773642d9SDouglas Gilbert sdebug_max_queue = n; 4713c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 4714cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4715cbf67842SDouglas Gilbert else if (k >= n) 4716cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4717cbf67842SDouglas Gilbert else 4718cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4719c4837394SDouglas Gilbert block_unblock_all_queues(false); 472078d4e5a0SDouglas Gilbert return count; 472178d4e5a0SDouglas Gilbert } 472278d4e5a0SDouglas Gilbert return -EINVAL; 472378d4e5a0SDouglas Gilbert } 472482069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 472578d4e5a0SDouglas Gilbert 472682069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 472778d4e5a0SDouglas Gilbert { 4728773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 472978d4e5a0SDouglas Gilbert } 473082069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 473178d4e5a0SDouglas Gilbert 473282069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 47331da177e4SLinus Torvalds { 4734773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 47351da177e4SLinus Torvalds } 473682069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 47371da177e4SLinus Torvalds 473882069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4739c65b1445SDouglas Gilbert { 4740773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 4741c65b1445SDouglas Gilbert } 474282069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 474382069379SAkinobu Mita size_t count) 4744c65b1445SDouglas Gilbert { 4745c65b1445SDouglas Gilbert int n; 47460d01c5dfSDouglas Gilbert bool changed; 4747c65b1445SDouglas Gilbert 4748c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4749773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 4750773642d9SDouglas Gilbert sdebug_virtual_gb = n; 475128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 47520d01c5dfSDouglas Gilbert if (changed) { 47530d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 47540d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 475528898873SFUJITA Tomonori 47564bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 47570d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 47580d01c5dfSDouglas Gilbert host_list) { 47590d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 47600d01c5dfSDouglas Gilbert dev_list) { 47610d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 47620d01c5dfSDouglas Gilbert dp->uas_bm); 47630d01c5dfSDouglas Gilbert } 47640d01c5dfSDouglas Gilbert } 47654bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 47660d01c5dfSDouglas Gilbert } 4767c65b1445SDouglas Gilbert return count; 4768c65b1445SDouglas Gilbert } 4769c65b1445SDouglas Gilbert return -EINVAL; 4770c65b1445SDouglas Gilbert } 477182069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4772c65b1445SDouglas Gilbert 477382069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 47741da177e4SLinus Torvalds { 4775773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host); 47761da177e4SLinus Torvalds } 47771da177e4SLinus Torvalds 4778fd32119bSDouglas Gilbert static int sdebug_add_adapter(void); 4779fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void); 4780fd32119bSDouglas Gilbert 478182069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 478282069379SAkinobu Mita size_t count) 47831da177e4SLinus Torvalds { 47841da177e4SLinus Torvalds int delta_hosts; 47851da177e4SLinus Torvalds 4786f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 47871da177e4SLinus Torvalds return -EINVAL; 47881da177e4SLinus Torvalds if (delta_hosts > 0) { 47891da177e4SLinus Torvalds do { 47901da177e4SLinus Torvalds sdebug_add_adapter(); 47911da177e4SLinus Torvalds } while (--delta_hosts); 47921da177e4SLinus Torvalds } else if (delta_hosts < 0) { 47931da177e4SLinus Torvalds do { 47941da177e4SLinus Torvalds sdebug_remove_adapter(); 47951da177e4SLinus Torvalds } while (++delta_hosts); 47961da177e4SLinus Torvalds } 47971da177e4SLinus Torvalds return count; 47981da177e4SLinus Torvalds } 479982069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 48001da177e4SLinus Torvalds 480182069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 480223183910SDouglas Gilbert { 4803773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 480423183910SDouglas Gilbert } 480582069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 480682069379SAkinobu Mita size_t count) 480723183910SDouglas Gilbert { 480823183910SDouglas Gilbert int n; 480923183910SDouglas Gilbert 481023183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4811773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 481223183910SDouglas Gilbert return count; 481323183910SDouglas Gilbert } 481423183910SDouglas Gilbert return -EINVAL; 481523183910SDouglas Gilbert } 481682069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 481723183910SDouglas Gilbert 4818c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 4819c4837394SDouglas Gilbert { 4820c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 4821c4837394SDouglas Gilbert } 4822c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 4823c4837394SDouglas Gilbert size_t count) 4824c4837394SDouglas Gilbert { 4825c4837394SDouglas Gilbert int n; 4826c4837394SDouglas Gilbert 4827c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 4828c4837394SDouglas Gilbert if (n > 0) 4829c4837394SDouglas Gilbert sdebug_statistics = true; 4830c4837394SDouglas Gilbert else { 4831c4837394SDouglas Gilbert clear_queue_stats(); 4832c4837394SDouglas Gilbert sdebug_statistics = false; 4833c4837394SDouglas Gilbert } 4834c4837394SDouglas Gilbert return count; 4835c4837394SDouglas Gilbert } 4836c4837394SDouglas Gilbert return -EINVAL; 4837c4837394SDouglas Gilbert } 4838c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 4839c4837394SDouglas Gilbert 484082069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4841597136abSMartin K. Petersen { 4842773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 4843597136abSMartin K. Petersen } 484482069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4845597136abSMartin K. Petersen 4846c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 4847c4837394SDouglas Gilbert { 4848c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 4849c4837394SDouglas Gilbert } 4850c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 4851c4837394SDouglas Gilbert 485282069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4853c6a44287SMartin K. Petersen { 4854773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 4855c6a44287SMartin K. Petersen } 485682069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4857c6a44287SMartin K. Petersen 485882069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4859c6a44287SMartin K. Petersen { 4860773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 4861c6a44287SMartin K. Petersen } 486282069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4863c6a44287SMartin K. Petersen 486482069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4865c6a44287SMartin K. Petersen { 4866773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 4867c6a44287SMartin K. Petersen } 486882069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4869c6a44287SMartin K. Petersen 487082069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4871c6a44287SMartin K. Petersen { 4872773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 4873c6a44287SMartin K. Petersen } 487482069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4875c6a44287SMartin K. Petersen 487682069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 487744d92694SMartin K. Petersen { 487844d92694SMartin K. Petersen ssize_t count; 487944d92694SMartin K. Petersen 48805b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 488144d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 488244d92694SMartin K. Petersen sdebug_store_sectors); 488344d92694SMartin K. Petersen 4884c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4885c7badc90STejun Heo (int)map_size, map_storep); 488644d92694SMartin K. Petersen buf[count++] = '\n'; 4887c7badc90STejun Heo buf[count] = '\0'; 488844d92694SMartin K. Petersen 488944d92694SMartin K. Petersen return count; 489044d92694SMartin K. Petersen } 489182069379SAkinobu Mita static DRIVER_ATTR_RO(map); 489244d92694SMartin K. Petersen 489382069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4894d986788bSMartin Pitt { 4895773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 4896d986788bSMartin Pitt } 489782069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 489882069379SAkinobu Mita size_t count) 4899d986788bSMartin Pitt { 4900d986788bSMartin Pitt int n; 4901d986788bSMartin Pitt 4902d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4903773642d9SDouglas Gilbert sdebug_removable = (n > 0); 4904d986788bSMartin Pitt return count; 4905d986788bSMartin Pitt } 4906d986788bSMartin Pitt return -EINVAL; 4907d986788bSMartin Pitt } 490882069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4909d986788bSMartin Pitt 4910cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4911cbf67842SDouglas Gilbert { 4912773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 4913cbf67842SDouglas Gilbert } 4914185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 4915cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4916cbf67842SDouglas Gilbert size_t count) 4917cbf67842SDouglas Gilbert { 4918185dd232SDouglas Gilbert int n; 4919cbf67842SDouglas Gilbert 4920cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4921185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 4922185dd232SDouglas Gilbert return count; 4923cbf67842SDouglas Gilbert } 4924cbf67842SDouglas Gilbert return -EINVAL; 4925cbf67842SDouglas Gilbert } 4926cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4927cbf67842SDouglas Gilbert 4928c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4929c2248fc9SDouglas Gilbert { 4930773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 4931c2248fc9SDouglas Gilbert } 4932c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4933c2248fc9SDouglas Gilbert size_t count) 4934c2248fc9SDouglas Gilbert { 4935c2248fc9SDouglas Gilbert int n; 4936c2248fc9SDouglas Gilbert 4937c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4938773642d9SDouglas Gilbert sdebug_strict = (n > 0); 4939c2248fc9SDouglas Gilbert return count; 4940c2248fc9SDouglas Gilbert } 4941c2248fc9SDouglas Gilbert return -EINVAL; 4942c2248fc9SDouglas Gilbert } 4943c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4944c2248fc9SDouglas Gilbert 494509ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 494609ba24c1SDouglas Gilbert { 494709ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 494809ba24c1SDouglas Gilbert } 494909ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 495009ba24c1SDouglas Gilbert 49519b760fd8SDouglas Gilbert static ssize_t cdb_len_show(struct device_driver *ddp, char *buf) 49529b760fd8SDouglas Gilbert { 49539b760fd8SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len); 49549b760fd8SDouglas Gilbert } 49559b760fd8SDouglas Gilbert static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf, 49569b760fd8SDouglas Gilbert size_t count) 49579b760fd8SDouglas Gilbert { 49589b760fd8SDouglas Gilbert int ret, n; 49599b760fd8SDouglas Gilbert 49609b760fd8SDouglas Gilbert ret = kstrtoint(buf, 0, &n); 49619b760fd8SDouglas Gilbert if (ret) 49629b760fd8SDouglas Gilbert return ret; 49639b760fd8SDouglas Gilbert sdebug_cdb_len = n; 49649b760fd8SDouglas Gilbert all_config_cdb_len(); 49659b760fd8SDouglas Gilbert return count; 49669b760fd8SDouglas Gilbert } 49679b760fd8SDouglas Gilbert static DRIVER_ATTR_RW(cdb_len); 49689b760fd8SDouglas Gilbert 4969cbf67842SDouglas Gilbert 497082069379SAkinobu Mita /* Note: The following array creates attribute files in the 497123183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 497223183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 497323183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 497423183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 497523183910SDouglas Gilbert */ 49766ecaff7fSRandy Dunlap 497782069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 497882069379SAkinobu Mita &driver_attr_delay.attr, 497982069379SAkinobu Mita &driver_attr_opts.attr, 498082069379SAkinobu Mita &driver_attr_ptype.attr, 498182069379SAkinobu Mita &driver_attr_dsense.attr, 498282069379SAkinobu Mita &driver_attr_fake_rw.attr, 498382069379SAkinobu Mita &driver_attr_no_lun_0.attr, 498482069379SAkinobu Mita &driver_attr_num_tgts.attr, 498582069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 498682069379SAkinobu Mita &driver_attr_num_parts.attr, 498782069379SAkinobu Mita &driver_attr_every_nth.attr, 498882069379SAkinobu Mita &driver_attr_max_luns.attr, 498982069379SAkinobu Mita &driver_attr_max_queue.attr, 499082069379SAkinobu Mita &driver_attr_no_uld.attr, 499182069379SAkinobu Mita &driver_attr_scsi_level.attr, 499282069379SAkinobu Mita &driver_attr_virtual_gb.attr, 499382069379SAkinobu Mita &driver_attr_add_host.attr, 499482069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 499582069379SAkinobu Mita &driver_attr_sector_size.attr, 4996c4837394SDouglas Gilbert &driver_attr_statistics.attr, 4997c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 499882069379SAkinobu Mita &driver_attr_dix.attr, 499982069379SAkinobu Mita &driver_attr_dif.attr, 500082069379SAkinobu Mita &driver_attr_guard.attr, 500182069379SAkinobu Mita &driver_attr_ato.attr, 500282069379SAkinobu Mita &driver_attr_map.attr, 500382069379SAkinobu Mita &driver_attr_removable.attr, 5004cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 5005cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 5006c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 500709ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 50089b760fd8SDouglas Gilbert &driver_attr_cdb_len.attr, 500982069379SAkinobu Mita NULL, 501082069379SAkinobu Mita }; 501182069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 50121da177e4SLinus Torvalds 501311ddcecaSAkinobu Mita static struct device *pseudo_primary; 50148dea0d02SFUJITA Tomonori 50151da177e4SLinus Torvalds static int __init scsi_debug_init(void) 50161da177e4SLinus Torvalds { 50175f2578e5SFUJITA Tomonori unsigned long sz; 50181da177e4SLinus Torvalds int host_to_add; 50191da177e4SLinus Torvalds int k; 50206ecaff7fSRandy Dunlap int ret; 50211da177e4SLinus Torvalds 5022cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 5023cbf67842SDouglas Gilbert 5024773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 5025c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 5026773642d9SDouglas Gilbert sdebug_ndelay = 0; 5027773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 5028c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 5029cbf67842SDouglas Gilbert 5030773642d9SDouglas Gilbert switch (sdebug_sector_size) { 5031597136abSMartin K. Petersen case 512: 5032597136abSMartin K. Petersen case 1024: 5033597136abSMartin K. Petersen case 2048: 5034597136abSMartin K. Petersen case 4096: 5035597136abSMartin K. Petersen break; 5036597136abSMartin K. Petersen default: 5037773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 5038597136abSMartin K. Petersen return -EINVAL; 5039597136abSMartin K. Petersen } 5040597136abSMartin K. Petersen 5041773642d9SDouglas Gilbert switch (sdebug_dif) { 50428475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 5043f46eb0e9SDouglas Gilbert break; 50448475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 50458475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 50468475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 5047f46eb0e9SDouglas Gilbert have_dif_prot = true; 5048c6a44287SMartin K. Petersen break; 5049c6a44287SMartin K. Petersen 5050c6a44287SMartin K. Petersen default: 5051c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 5052c6a44287SMartin K. Petersen return -EINVAL; 5053c6a44287SMartin K. Petersen } 5054c6a44287SMartin K. Petersen 5055773642d9SDouglas Gilbert if (sdebug_guard > 1) { 5056c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 5057c6a44287SMartin K. Petersen return -EINVAL; 5058c6a44287SMartin K. Petersen } 5059c6a44287SMartin K. Petersen 5060773642d9SDouglas Gilbert if (sdebug_ato > 1) { 5061c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 5062c6a44287SMartin K. Petersen return -EINVAL; 5063c6a44287SMartin K. Petersen } 5064c6a44287SMartin K. Petersen 5065773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 5066773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 5067ea61fca5SMartin K. Petersen return -EINVAL; 5068ea61fca5SMartin K. Petersen } 50698d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 50708d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 50718d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 50728d039e22SDouglas Gilbert } 5073ea61fca5SMartin K. Petersen 5074773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 5075773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 5076ea61fca5SMartin K. Petersen return -EINVAL; 5077ea61fca5SMartin K. Petersen } 5078ea61fca5SMartin K. Petersen 5079c4837394SDouglas Gilbert if (submit_queues < 1) { 5080c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 5081c4837394SDouglas Gilbert return -EINVAL; 5082c4837394SDouglas Gilbert } 5083c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 5084c4837394SDouglas Gilbert GFP_KERNEL); 5085c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 5086c4837394SDouglas Gilbert return -ENOMEM; 5087c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 5088c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 5089c4837394SDouglas Gilbert 5090773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 5091773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 5092773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 5093773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 509428898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 50951da177e4SLinus Torvalds 50961da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 50971da177e4SLinus Torvalds sdebug_heads = 8; 50981da177e4SLinus Torvalds sdebug_sectors_per = 32; 5099773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 51001da177e4SLinus Torvalds sdebug_heads = 64; 5101773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 5102fa785f0aSAndy Shevchenko sdebug_heads = 32; 51031da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 51041da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 51051da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 51061da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 51071da177e4SLinus Torvalds sdebug_heads = 255; 51081da177e4SLinus Torvalds sdebug_sectors_per = 63; 51091da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 51101da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 51111da177e4SLinus Torvalds } 51121da177e4SLinus Torvalds 5113b01f6f83SDouglas Gilbert if (sdebug_fake_rw == 0) { 51141da177e4SLinus Torvalds fake_storep = vmalloc(sz); 51151da177e4SLinus Torvalds if (NULL == fake_storep) { 5116c1287970STomas Winkler pr_err("out of memory, 1\n"); 5117c4837394SDouglas Gilbert ret = -ENOMEM; 5118c4837394SDouglas Gilbert goto free_q_arr; 51191da177e4SLinus Torvalds } 51201da177e4SLinus Torvalds memset(fake_storep, 0, sz); 5121773642d9SDouglas Gilbert if (sdebug_num_parts > 0) 5122f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 5123cbf67842SDouglas Gilbert } 51241da177e4SLinus Torvalds 5125773642d9SDouglas Gilbert if (sdebug_dix) { 5126c6a44287SMartin K. Petersen int dif_size; 5127c6a44287SMartin K. Petersen 51286ebf105cSChristoph Hellwig dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 5129c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 5130c6a44287SMartin K. Petersen 5131c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 5132c6a44287SMartin K. Petersen 5133c6a44287SMartin K. Petersen if (dif_storep == NULL) { 5134c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 5135c6a44287SMartin K. Petersen ret = -ENOMEM; 5136c6a44287SMartin K. Petersen goto free_vm; 5137c6a44287SMartin K. Petersen } 5138c6a44287SMartin K. Petersen 5139c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 5140c6a44287SMartin K. Petersen } 5141c6a44287SMartin K. Petersen 51425b94e232SMartin K. Petersen /* Logical Block Provisioning */ 51435b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 5144773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 5145773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 51466014759cSMartin K. Petersen 5147773642d9SDouglas Gilbert sdebug_unmap_max_desc = 5148773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 51496014759cSMartin K. Petersen 5150773642d9SDouglas Gilbert sdebug_unmap_granularity = 5151773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 51526014759cSMartin K. Petersen 5153773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 5154773642d9SDouglas Gilbert sdebug_unmap_granularity <= 5155773642d9SDouglas Gilbert sdebug_unmap_alignment) { 5156c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 5157c4837394SDouglas Gilbert ret = -EINVAL; 5158c4837394SDouglas Gilbert goto free_vm; 515944d92694SMartin K. Petersen } 516044d92694SMartin K. Petersen 5161b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 5162b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 516344d92694SMartin K. Petersen 5164c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 516544d92694SMartin K. Petersen 516644d92694SMartin K. Petersen if (map_storep == NULL) { 5167c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 516844d92694SMartin K. Petersen ret = -ENOMEM; 516944d92694SMartin K. Petersen goto free_vm; 517044d92694SMartin K. Petersen } 517144d92694SMartin K. Petersen 5172b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 517344d92694SMartin K. Petersen 517444d92694SMartin K. Petersen /* Map first 1KB for partition table */ 5175773642d9SDouglas Gilbert if (sdebug_num_parts) 517644d92694SMartin K. Petersen map_region(0, 2); 517744d92694SMartin K. Petersen } 517844d92694SMartin K. Petersen 51799b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 51809b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 5181c1287970STomas Winkler pr_warn("root_device_register() error\n"); 51829b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 51836ecaff7fSRandy Dunlap goto free_vm; 51846ecaff7fSRandy Dunlap } 51856ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 51866ecaff7fSRandy Dunlap if (ret < 0) { 5187c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 51886ecaff7fSRandy Dunlap goto dev_unreg; 51896ecaff7fSRandy Dunlap } 51906ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 51916ecaff7fSRandy Dunlap if (ret < 0) { 5192c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 51936ecaff7fSRandy Dunlap goto bus_unreg; 51946ecaff7fSRandy Dunlap } 51951da177e4SLinus Torvalds 5196773642d9SDouglas Gilbert host_to_add = sdebug_add_host; 5197773642d9SDouglas Gilbert sdebug_add_host = 0; 51981da177e4SLinus Torvalds 51991da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 52001da177e4SLinus Torvalds if (sdebug_add_adapter()) { 5201c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 52021da177e4SLinus Torvalds break; 52031da177e4SLinus Torvalds } 52041da177e4SLinus Torvalds } 52051da177e4SLinus Torvalds 5206773642d9SDouglas Gilbert if (sdebug_verbose) 5207773642d9SDouglas Gilbert pr_info("built %d host(s)\n", sdebug_add_host); 5208c1287970STomas Winkler 52091da177e4SLinus Torvalds return 0; 52106ecaff7fSRandy Dunlap 52116ecaff7fSRandy Dunlap bus_unreg: 52126ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 52136ecaff7fSRandy Dunlap dev_unreg: 52149b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 52156ecaff7fSRandy Dunlap free_vm: 521644d92694SMartin K. Petersen vfree(map_storep); 5217c6a44287SMartin K. Petersen vfree(dif_storep); 52186ecaff7fSRandy Dunlap vfree(fake_storep); 5219c4837394SDouglas Gilbert free_q_arr: 5220c4837394SDouglas Gilbert kfree(sdebug_q_arr); 52216ecaff7fSRandy Dunlap return ret; 52221da177e4SLinus Torvalds } 52231da177e4SLinus Torvalds 52241da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 52251da177e4SLinus Torvalds { 5226773642d9SDouglas Gilbert int k = sdebug_add_host; 52271da177e4SLinus Torvalds 52281da177e4SLinus Torvalds stop_all_queued(); 5229cbf67842SDouglas Gilbert free_all_queued(); 52301da177e4SLinus Torvalds for (; k; k--) 52311da177e4SLinus Torvalds sdebug_remove_adapter(); 52321da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 52331da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 52349b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 52351da177e4SLinus Torvalds 52364d2b496fSEwan D. Milne vfree(map_storep); 5237c6a44287SMartin K. Petersen vfree(dif_storep); 52381da177e4SLinus Torvalds vfree(fake_storep); 5239c4837394SDouglas Gilbert kfree(sdebug_q_arr); 52401da177e4SLinus Torvalds } 52411da177e4SLinus Torvalds 52421da177e4SLinus Torvalds device_initcall(scsi_debug_init); 52431da177e4SLinus Torvalds module_exit(scsi_debug_exit); 52441da177e4SLinus Torvalds 52451da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 52461da177e4SLinus Torvalds { 52471da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 52481da177e4SLinus Torvalds 52491da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 52501da177e4SLinus Torvalds kfree(sdbg_host); 52511da177e4SLinus Torvalds } 52521da177e4SLinus Torvalds 52531da177e4SLinus Torvalds static int sdebug_add_adapter(void) 52541da177e4SLinus Torvalds { 52551da177e4SLinus Torvalds int k, devs_per_host; 52561da177e4SLinus Torvalds int error = 0; 52571da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 52588b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 52591da177e4SLinus Torvalds 526024669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 52611da177e4SLinus Torvalds if (NULL == sdbg_host) { 5262c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 52631da177e4SLinus Torvalds return -ENOMEM; 52641da177e4SLinus Torvalds } 52651da177e4SLinus Torvalds 52661da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 52671da177e4SLinus Torvalds 5268773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 52691da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 52705cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 52715cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 5272c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 52731da177e4SLinus Torvalds error = -ENOMEM; 52741da177e4SLinus Torvalds goto clean; 52751da177e4SLinus Torvalds } 52761da177e4SLinus Torvalds } 52771da177e4SLinus Torvalds 52781da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 52791da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 52801da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 52811da177e4SLinus Torvalds 52821da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 52839b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 52841da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 5285773642d9SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host); 52861da177e4SLinus Torvalds 52871da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 52881da177e4SLinus Torvalds 52891da177e4SLinus Torvalds if (error) 52901da177e4SLinus Torvalds goto clean; 52911da177e4SLinus Torvalds 5292773642d9SDouglas Gilbert ++sdebug_add_host; 52931da177e4SLinus Torvalds return error; 52941da177e4SLinus Torvalds 52951da177e4SLinus Torvalds clean: 52968b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 52978b40228fSFUJITA Tomonori dev_list) { 52981da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 52991da177e4SLinus Torvalds kfree(sdbg_devinfo); 53001da177e4SLinus Torvalds } 53011da177e4SLinus Torvalds 53021da177e4SLinus Torvalds kfree(sdbg_host); 53031da177e4SLinus Torvalds return error; 53041da177e4SLinus Torvalds } 53051da177e4SLinus Torvalds 53061da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 53071da177e4SLinus Torvalds { 53081da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 53091da177e4SLinus Torvalds 53101da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 53111da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 53121da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 53131da177e4SLinus Torvalds struct sdebug_host_info, host_list); 53141da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 53151da177e4SLinus Torvalds } 53161da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 53171da177e4SLinus Torvalds 53181da177e4SLinus Torvalds if (!sdbg_host) 53191da177e4SLinus Torvalds return; 53201da177e4SLinus Torvalds 53211da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 5322773642d9SDouglas Gilbert --sdebug_add_host; 53231da177e4SLinus Torvalds } 53241da177e4SLinus Torvalds 5325fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 5326cbf67842SDouglas Gilbert { 5327cbf67842SDouglas Gilbert int num_in_q = 0; 5328cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5329cbf67842SDouglas Gilbert 5330c4837394SDouglas Gilbert block_unblock_all_queues(true); 5331cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 5332cbf67842SDouglas Gilbert if (NULL == devip) { 5333c4837394SDouglas Gilbert block_unblock_all_queues(false); 5334cbf67842SDouglas Gilbert return -ENODEV; 5335cbf67842SDouglas Gilbert } 5336cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5337c40ecc12SChristoph Hellwig 5338cbf67842SDouglas Gilbert if (qdepth < 1) 5339cbf67842SDouglas Gilbert qdepth = 1; 5340c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 5341c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 5342c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 5343db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 5344cbf67842SDouglas Gilbert 5345773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 5346c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 5347c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 5348cbf67842SDouglas Gilbert } 5349c4837394SDouglas Gilbert block_unblock_all_queues(false); 5350cbf67842SDouglas Gilbert return sdev->queue_depth; 5351cbf67842SDouglas Gilbert } 5352cbf67842SDouglas Gilbert 5353c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 5354817fd66bSDouglas Gilbert { 5355c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 5356773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 5357773642d9SDouglas Gilbert sdebug_every_nth = -1; 5358773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 5359c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 5360773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 5361817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5362c4837394SDouglas Gilbert return true; /* time out reads and writes */ 5363817fd66bSDouglas Gilbert } 5364c4837394SDouglas Gilbert return false; 5365817fd66bSDouglas Gilbert } 5366817fd66bSDouglas Gilbert 53677ee6d1b4SBart Van Assche static bool fake_host_busy(struct scsi_cmnd *scp) 53687ee6d1b4SBart Van Assche { 53697ee6d1b4SBart Van Assche return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) && 53707ee6d1b4SBart Van Assche (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0; 53717ee6d1b4SBart Van Assche } 53727ee6d1b4SBart Van Assche 5373fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 5374fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 5375c2248fc9SDouglas Gilbert { 5376c2248fc9SDouglas Gilbert u8 sdeb_i; 5377c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5378c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5379c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5380c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5381c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5382c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5383c2248fc9SDouglas Gilbert int k, na; 5384c2248fc9SDouglas Gilbert int errsts = 0; 5385c2248fc9SDouglas Gilbert u32 flags; 5386c2248fc9SDouglas Gilbert u16 sa; 5387c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5388c2248fc9SDouglas Gilbert bool has_wlun_rl; 5389c2248fc9SDouglas Gilbert 5390c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5391c4837394SDouglas Gilbert if (sdebug_statistics) 5392c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 5393f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 5394f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 5395c2248fc9SDouglas Gilbert char b[120]; 5396c2248fc9SDouglas Gilbert int n, len, sb; 5397c2248fc9SDouglas Gilbert 5398c2248fc9SDouglas Gilbert len = scp->cmd_len; 5399c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5400c2248fc9SDouglas Gilbert if (len > 32) 5401c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5402c2248fc9SDouglas Gilbert else { 5403c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5404c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5405c2248fc9SDouglas Gilbert (u32)cmd[k]); 5406c2248fc9SDouglas Gilbert } 5407c4837394SDouglas Gilbert if (sdebug_mq_active) 5408c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", 5409c4837394SDouglas Gilbert my_name, blk_mq_unique_tag(scp->request), 5410c4837394SDouglas Gilbert b); 5411c4837394SDouglas Gilbert else 5412c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, 5413c4837394SDouglas Gilbert b); 5414c2248fc9SDouglas Gilbert } 54157ee6d1b4SBart Van Assche if (fake_host_busy(scp)) 54167ee6d1b4SBart Van Assche return SCSI_MLQUEUE_HOST_BUSY; 541734d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 5418f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 5419f46eb0e9SDouglas Gilbert goto err_out; 5420c2248fc9SDouglas Gilbert 5421c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5422c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5423c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5424f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 5425f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5426c2248fc9SDouglas Gilbert if (NULL == devip) 5427f46eb0e9SDouglas Gilbert goto err_out; 5428c2248fc9SDouglas Gilbert } 5429c2248fc9SDouglas Gilbert na = oip->num_attached; 5430c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5431c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5432c2248fc9SDouglas Gilbert r_oip = oip; 5433c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5434c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5435c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5436c2248fc9SDouglas Gilbert else 5437c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5438c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5439c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5440c2248fc9SDouglas Gilbert break; 5441c2248fc9SDouglas Gilbert } 5442c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5443c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5444c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5445c2248fc9SDouglas Gilbert break; 5446c2248fc9SDouglas Gilbert } 5447c2248fc9SDouglas Gilbert } 5448c2248fc9SDouglas Gilbert if (k > na) { 5449c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5450c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5451c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5452c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5453c2248fc9SDouglas Gilbert else 5454c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5455c2248fc9SDouglas Gilbert goto check_cond; 5456c2248fc9SDouglas Gilbert } 5457c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5458c2248fc9SDouglas Gilbert flags = oip->flags; 5459f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 5460c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5461c2248fc9SDouglas Gilbert goto check_cond; 5462c2248fc9SDouglas Gilbert } 5463f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 5464773642d9SDouglas Gilbert if (sdebug_verbose) 5465773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 5466773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 5467c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5468c2248fc9SDouglas Gilbert goto check_cond; 5469c2248fc9SDouglas Gilbert } 5470f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 5471c2248fc9SDouglas Gilbert u8 rem; 5472c2248fc9SDouglas Gilbert int j; 5473c2248fc9SDouglas Gilbert 5474c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5475c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5476c2248fc9SDouglas Gilbert if (rem) { 5477c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5478c2248fc9SDouglas Gilbert if (0x80 & rem) 5479c2248fc9SDouglas Gilbert break; 5480c2248fc9SDouglas Gilbert } 5481c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5482c2248fc9SDouglas Gilbert goto check_cond; 5483c2248fc9SDouglas Gilbert } 5484c2248fc9SDouglas Gilbert } 5485c2248fc9SDouglas Gilbert } 5486f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 5487b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 5488b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 5489f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 5490c2248fc9SDouglas Gilbert if (errsts) 5491c2248fc9SDouglas Gilbert goto check_cond; 5492c2248fc9SDouglas Gilbert } 5493c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 5494c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5495773642d9SDouglas Gilbert if (sdebug_verbose) 5496c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5497c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5498c2248fc9SDouglas Gilbert "required"); 5499c2248fc9SDouglas Gilbert errsts = check_condition_result; 5500c2248fc9SDouglas Gilbert goto fini; 5501c2248fc9SDouglas Gilbert } 5502773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 5503c2248fc9SDouglas Gilbert goto fini; 5504f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 5505c4837394SDouglas Gilbert if (fake_timeout(scp)) 5506c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5507c2248fc9SDouglas Gilbert } 5508f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 5509f46eb0e9SDouglas Gilbert errsts = oip->pfp(scp, devip); /* calls a resp_* function */ 5510c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5511c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5512c2248fc9SDouglas Gilbert 5513c2248fc9SDouglas Gilbert fini: 5514c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5515c2206098SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay)); 5516c2248fc9SDouglas Gilbert check_cond: 5517c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5518f46eb0e9SDouglas Gilbert err_out: 5519f46eb0e9SDouglas Gilbert return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0); 5520c2248fc9SDouglas Gilbert } 5521c2248fc9SDouglas Gilbert 55229e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5523c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5524c8ed555aSAl Viro .write_info = scsi_debug_write_info, 55259e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 55269e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 55279e603ca0SFUJITA Tomonori .info = scsi_debug_info, 55289e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 55299e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 55309e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 55319e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5532185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 5533cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 55349e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 55359e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5536cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5537cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 55389e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 5539c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 55409e603ca0SFUJITA Tomonori .this_id = 7, 554165e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 5542cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 55436bb5e6e7SAkinobu Mita .max_sectors = -1U, 55449e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 55459e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5546c40ecc12SChristoph Hellwig .track_queue_depth = 1, 55479e603ca0SFUJITA Tomonori }; 55489e603ca0SFUJITA Tomonori 55491da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 55501da177e4SLinus Torvalds { 55511da177e4SLinus Torvalds int error = 0; 55521da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 55531da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5554f46eb0e9SDouglas Gilbert int hprot; 55551da177e4SLinus Torvalds 55561da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 55571da177e4SLinus Torvalds 5558773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 5559773642d9SDouglas Gilbert if (sdebug_clustering) 55600759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 55611da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 55621da177e4SLinus Torvalds if (NULL == hpnt) { 5563c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 55641da177e4SLinus Torvalds error = -ENODEV; 55651da177e4SLinus Torvalds return error; 55661da177e4SLinus Torvalds } 5567c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 55689b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 5569c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 5570c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 5571c4837394SDouglas Gilbert } 5572c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 5573c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 5574c4837394SDouglas Gilbert sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); 5575c4837394SDouglas Gilbert if (sdebug_mq_active) 5576c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 55771da177e4SLinus Torvalds 55781da177e4SLinus Torvalds sdbg_host->shost = hpnt; 55791da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 5580773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 5581773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 55821da177e4SLinus Torvalds else 5583773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 5584773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 5585f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 55861da177e4SLinus Torvalds 5587f46eb0e9SDouglas Gilbert hprot = 0; 5588c6a44287SMartin K. Petersen 5589773642d9SDouglas Gilbert switch (sdebug_dif) { 5590c6a44287SMartin K. Petersen 55918475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 5592f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 5593773642d9SDouglas Gilbert if (sdebug_dix) 5594f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 5595c6a44287SMartin K. Petersen break; 5596c6a44287SMartin K. Petersen 55978475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 5598f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 5599773642d9SDouglas Gilbert if (sdebug_dix) 5600f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 5601c6a44287SMartin K. Petersen break; 5602c6a44287SMartin K. Petersen 56038475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 5604f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 5605773642d9SDouglas Gilbert if (sdebug_dix) 5606f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 5607c6a44287SMartin K. Petersen break; 5608c6a44287SMartin K. Petersen 5609c6a44287SMartin K. Petersen default: 5610773642d9SDouglas Gilbert if (sdebug_dix) 5611f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 5612c6a44287SMartin K. Petersen break; 5613c6a44287SMartin K. Petersen } 5614c6a44287SMartin K. Petersen 5615f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 5616c6a44287SMartin K. Petersen 5617f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 5618c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5619f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5620f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5621f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5622f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5623f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5624f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5625f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5626c6a44287SMartin K. Petersen 5627773642d9SDouglas Gilbert if (sdebug_guard == 1) 5628c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5629c6a44287SMartin K. Petersen else 5630c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5631c6a44287SMartin K. Petersen 5632773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 5633773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 5634c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 5635c4837394SDouglas Gilbert sdebug_statistics = true; 56361da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 56371da177e4SLinus Torvalds if (error) { 5638c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 56391da177e4SLinus Torvalds error = -ENODEV; 56401da177e4SLinus Torvalds scsi_host_put(hpnt); 56411da177e4SLinus Torvalds } else 56421da177e4SLinus Torvalds scsi_scan_host(hpnt); 56431da177e4SLinus Torvalds 56441da177e4SLinus Torvalds return error; 56451da177e4SLinus Torvalds } 56461da177e4SLinus Torvalds 56471da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 56481da177e4SLinus Torvalds { 56491da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 56508b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 56511da177e4SLinus Torvalds 56521da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 56531da177e4SLinus Torvalds 56541da177e4SLinus Torvalds if (!sdbg_host) { 5655c1287970STomas Winkler pr_err("Unable to locate host info\n"); 56561da177e4SLinus Torvalds return -ENODEV; 56571da177e4SLinus Torvalds } 56581da177e4SLinus Torvalds 56591da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 56601da177e4SLinus Torvalds 56618b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 56628b40228fSFUJITA Tomonori dev_list) { 56631da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 56641da177e4SLinus Torvalds kfree(sdbg_devinfo); 56651da177e4SLinus Torvalds } 56661da177e4SLinus Torvalds 56671da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 56681da177e4SLinus Torvalds return 0; 56691da177e4SLinus Torvalds } 56701da177e4SLinus Torvalds 56718dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 56728dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 56731da177e4SLinus Torvalds { 56748dea0d02SFUJITA Tomonori return 1; 56758dea0d02SFUJITA Tomonori } 56761da177e4SLinus Torvalds 56778dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 56788dea0d02SFUJITA Tomonori .name = "pseudo", 56798dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 56808dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 56818dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 568282069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 56838dea0d02SFUJITA Tomonori }; 5684