11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv 31da177e4SLinus Torvalds * Copyright (C) 1992 Eric Youngdale 41da177e4SLinus Torvalds * Simulate a host adapter with 2 disks attached. Do a lot of checking 51da177e4SLinus Torvalds * to make sure that we are not getting blocks mixed up, and PANIC if 61da177e4SLinus Torvalds * anything out of the ordinary is seen. 71da177e4SLinus Torvalds * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 81da177e4SLinus Torvalds * 9773642d9SDouglas Gilbert * Copyright (C) 2001 - 2016 Douglas Gilbert 101da177e4SLinus Torvalds * 11773642d9SDouglas Gilbert * This program is free software; you can redistribute it and/or modify 12773642d9SDouglas Gilbert * it under the terms of the GNU General Public License as published by 13773642d9SDouglas Gilbert * the Free Software Foundation; either version 2, or (at your option) 14773642d9SDouglas Gilbert * any later version. 151da177e4SLinus Torvalds * 1678d4e5a0SDouglas Gilbert * For documentation see http://sg.danny.cz/sg/sdebug26.html 171da177e4SLinus Torvalds * 181da177e4SLinus Torvalds */ 191da177e4SLinus Torvalds 20c1287970STomas Winkler 21c1287970STomas Winkler #define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__ 22c1287970STomas Winkler 231da177e4SLinus Torvalds #include <linux/module.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include <linux/kernel.h> 261da177e4SLinus Torvalds #include <linux/errno.h> 27b333a819SDouglas Gilbert #include <linux/jiffies.h> 285a0e3ad6STejun Heo #include <linux/slab.h> 291da177e4SLinus Torvalds #include <linux/types.h> 301da177e4SLinus Torvalds #include <linux/string.h> 311da177e4SLinus Torvalds #include <linux/genhd.h> 321da177e4SLinus Torvalds #include <linux/fs.h> 331da177e4SLinus Torvalds #include <linux/init.h> 341da177e4SLinus Torvalds #include <linux/proc_fs.h> 351da177e4SLinus Torvalds #include <linux/vmalloc.h> 361da177e4SLinus Torvalds #include <linux/moduleparam.h> 37852e034dSJens Axboe #include <linux/scatterlist.h> 381da177e4SLinus Torvalds #include <linux/blkdev.h> 39c6a44287SMartin K. Petersen #include <linux/crc-t10dif.h> 40cbf67842SDouglas Gilbert #include <linux/spinlock.h> 41cbf67842SDouglas Gilbert #include <linux/interrupt.h> 42cbf67842SDouglas Gilbert #include <linux/atomic.h> 43cbf67842SDouglas Gilbert #include <linux/hrtimer.h> 4409ba24c1SDouglas Gilbert #include <linux/uuid.h> 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 */ 64b01f6f83SDouglas Gilbert #define SDEBUG_VERSION "1.86" 65b01f6f83SDouglas Gilbert static const char *sdebug_version_date = "20160430"; 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 108c2206098SDouglas Gilbert #define DEF_JDELAY 1 /* if > 0 unit is a jiffy */ 1091da177e4SLinus Torvalds #define DEF_DEV_SIZE_MB 8 1105b94e232SMartin K. Petersen #define DEF_DIF 0 1115b94e232SMartin K. Petersen #define DEF_DIX 0 1125b94e232SMartin K. Petersen #define DEF_D_SENSE 0 1131da177e4SLinus Torvalds #define DEF_EVERY_NTH 0 1145b94e232SMartin K. Petersen #define DEF_FAKE_RW 0 1155b94e232SMartin K. Petersen #define DEF_GUARD 0 116cbf67842SDouglas Gilbert #define DEF_HOST_LOCK 0 1175b94e232SMartin K. Petersen #define DEF_LBPU 0 1185b94e232SMartin K. Petersen #define DEF_LBPWS 0 1195b94e232SMartin K. Petersen #define DEF_LBPWS10 0 120be1dd78dSEric Sandeen #define DEF_LBPRZ 1 1215b94e232SMartin K. Petersen #define DEF_LOWEST_ALIGNED 0 122cbf67842SDouglas Gilbert #define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */ 1235b94e232SMartin K. Petersen #define DEF_NO_LUN_0 0 1241da177e4SLinus Torvalds #define DEF_NUM_PARTS 0 1251da177e4SLinus Torvalds #define DEF_OPTS 0 12632c5844aSMartin K. Petersen #define DEF_OPT_BLKS 1024 1275b94e232SMartin K. Petersen #define DEF_PHYSBLK_EXP 0 12886e6828aSLukas Herbolt #define DEF_OPT_XFERLEN_EXP 0 129b01f6f83SDouglas Gilbert #define DEF_PTYPE TYPE_DISK 130d986788bSMartin Pitt #define DEF_REMOVABLE false 131760f3b03SDouglas Gilbert #define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */ 1325b94e232SMartin K. Petersen #define DEF_SECTOR_SIZE 512 1335b94e232SMartin K. Petersen #define DEF_UNMAP_ALIGNMENT 0 1345b94e232SMartin K. Petersen #define DEF_UNMAP_GRANULARITY 1 1356014759cSMartin K. Petersen #define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF 1366014759cSMartin K. Petersen #define DEF_UNMAP_MAX_DESC 256 1375b94e232SMartin K. Petersen #define DEF_VIRTUAL_GB 0 1385b94e232SMartin K. Petersen #define DEF_VPD_USE_HOSTNO 1 1395b94e232SMartin K. Petersen #define DEF_WRITESAME_LENGTH 0xFFFF 140c2248fc9SDouglas Gilbert #define DEF_STRICT 0 141c4837394SDouglas Gilbert #define DEF_STATISTICS false 142c4837394SDouglas Gilbert #define DEF_SUBMIT_QUEUES 1 14309ba24c1SDouglas Gilbert #define DEF_UUID_CTL 0 144c2206098SDouglas Gilbert #define JDELAY_OVERRIDDEN -9999 1451da177e4SLinus Torvalds 146b01f6f83SDouglas Gilbert #define SDEBUG_LUN_0_VAL 0 147b01f6f83SDouglas Gilbert 148773642d9SDouglas Gilbert /* bit mask values for sdebug_opts */ 149773642d9SDouglas Gilbert #define SDEBUG_OPT_NOISE 1 150773642d9SDouglas Gilbert #define SDEBUG_OPT_MEDIUM_ERR 2 151773642d9SDouglas Gilbert #define SDEBUG_OPT_TIMEOUT 4 152773642d9SDouglas Gilbert #define SDEBUG_OPT_RECOVERED_ERR 8 153773642d9SDouglas Gilbert #define SDEBUG_OPT_TRANSPORT_ERR 16 154773642d9SDouglas Gilbert #define SDEBUG_OPT_DIF_ERR 32 155773642d9SDouglas Gilbert #define SDEBUG_OPT_DIX_ERR 64 156773642d9SDouglas Gilbert #define SDEBUG_OPT_MAC_TIMEOUT 128 157773642d9SDouglas Gilbert #define SDEBUG_OPT_SHORT_TRANSFER 0x100 158773642d9SDouglas Gilbert #define SDEBUG_OPT_Q_NOISE 0x200 159773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_TSF 0x400 160773642d9SDouglas Gilbert #define SDEBUG_OPT_RARE_TSF 0x800 161773642d9SDouglas Gilbert #define SDEBUG_OPT_N_WCE 0x1000 162773642d9SDouglas Gilbert #define SDEBUG_OPT_RESET_NOISE 0x2000 163773642d9SDouglas Gilbert #define SDEBUG_OPT_NO_CDB_NOISE 0x4000 164773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \ 165773642d9SDouglas Gilbert SDEBUG_OPT_RESET_NOISE) 166773642d9SDouglas Gilbert #define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \ 167773642d9SDouglas Gilbert SDEBUG_OPT_TRANSPORT_ERR | \ 168773642d9SDouglas Gilbert SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \ 169773642d9SDouglas Gilbert SDEBUG_OPT_SHORT_TRANSFER) 1701da177e4SLinus Torvalds /* When "every_nth" > 0 then modulo "every_nth" commands: 171fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1721da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 173773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1746f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 175773642d9SDouglas Gilbert * commands if SDEBUG_OPT_TRANSPORT_ERR is set. 1761da177e4SLinus Torvalds * 1771da177e4SLinus Torvalds * When "every_nth" < 0 then after "- every_nth" commands: 178fd32119bSDouglas Gilbert * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set 1791da177e4SLinus Torvalds * - a RECOVERED_ERROR is simulated on successful read and write 180773642d9SDouglas Gilbert * commands if SDEBUG_OPT_RECOVERED_ERR is set. 1816f3cbf55SDouglas Gilbert * - a TRANSPORT_ERROR is simulated on successful read and write 182773642d9SDouglas Gilbert * commands if _DEBUG_OPT_TRANSPORT_ERR is set. 183773642d9SDouglas Gilbert * This will continue on every subsequent command until some other action 184773642d9SDouglas Gilbert * occurs (e.g. the user * writing a new value (other than -1 or 1) to 185773642d9SDouglas Gilbert * every_nth via sysfs). 1861da177e4SLinus Torvalds */ 1871da177e4SLinus Torvalds 188cbf67842SDouglas Gilbert /* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in 189cbf67842SDouglas Gilbert * priority order. In the subset implemented here lower numbers have higher 190cbf67842SDouglas Gilbert * priority. The UA numbers should be a sequence starting from 0 with 191cbf67842SDouglas Gilbert * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */ 192cbf67842SDouglas Gilbert #define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */ 193cbf67842SDouglas Gilbert #define SDEBUG_UA_BUS_RESET 1 194cbf67842SDouglas Gilbert #define SDEBUG_UA_MODE_CHANGED 2 1950d01c5dfSDouglas Gilbert #define SDEBUG_UA_CAPACITY_CHANGED 3 19619c8ead7SEwan D. Milne #define SDEBUG_UA_LUNS_CHANGED 4 197acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */ 198acafd0b9SEwan D. Milne #define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6 199acafd0b9SEwan D. Milne #define SDEBUG_NUM_UAS 7 200cbf67842SDouglas Gilbert 201773642d9SDouglas Gilbert /* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this 2021da177e4SLinus Torvalds * sector on read commands: */ 2031da177e4SLinus Torvalds #define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */ 20432f7ef73SDouglas Gilbert #define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */ 2051da177e4SLinus Torvalds 2061da177e4SLinus Torvalds /* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1) 2071da177e4SLinus Torvalds * or "peripheral device" addressing (value 0) */ 2081da177e4SLinus Torvalds #define SAM2_LUN_ADDRESS_METHOD 0 2091da177e4SLinus Torvalds 210c4837394SDouglas Gilbert /* SDEBUG_CANQUEUE is the maximum number of commands that can be queued 211c4837394SDouglas Gilbert * (for response) per submit queue at one time. Can be reduced by max_queue 212c4837394SDouglas Gilbert * option. Command responses are not queued when jdelay=0 and ndelay=0. The 213c4837394SDouglas Gilbert * per-device DEF_CMD_PER_LUN can be changed via sysfs: 214c4837394SDouglas Gilbert * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth 215c4837394SDouglas Gilbert * but cannot exceed SDEBUG_CANQUEUE . 216c4837394SDouglas Gilbert */ 217c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */ 218c4837394SDouglas Gilbert #define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG) 219cbf67842SDouglas Gilbert #define DEF_CMD_PER_LUN 255 220cbf67842SDouglas Gilbert 221fd32119bSDouglas Gilbert #define F_D_IN 1 222fd32119bSDouglas Gilbert #define F_D_OUT 2 223fd32119bSDouglas Gilbert #define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */ 224fd32119bSDouglas Gilbert #define F_D_UNKN 8 225fd32119bSDouglas Gilbert #define F_RL_WLUN_OK 0x10 226fd32119bSDouglas Gilbert #define F_SKIP_UA 0x20 227fd32119bSDouglas Gilbert #define F_DELAY_OVERR 0x40 228fd32119bSDouglas Gilbert #define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */ 229fd32119bSDouglas Gilbert #define F_SA_HIGH 0x100 /* as used by variable length cdbs */ 230fd32119bSDouglas Gilbert #define F_INV_OP 0x200 231fd32119bSDouglas Gilbert #define F_FAKE_RW 0x400 232fd32119bSDouglas Gilbert #define F_M_ACCESS 0x800 /* media access */ 233fd32119bSDouglas Gilbert 234fd32119bSDouglas Gilbert #define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR) 235fd32119bSDouglas Gilbert #define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW) 236fd32119bSDouglas Gilbert #define FF_SA (F_SA_HIGH | F_SA_LOW) 237fd32119bSDouglas Gilbert 238fd32119bSDouglas Gilbert #define SDEBUG_MAX_PARTS 4 239fd32119bSDouglas Gilbert 240b01f6f83SDouglas Gilbert #define SDEBUG_MAX_CMD_LEN 32 241fd32119bSDouglas Gilbert 242fd32119bSDouglas Gilbert 243fd32119bSDouglas Gilbert struct sdebug_dev_info { 244fd32119bSDouglas Gilbert struct list_head dev_list; 245fd32119bSDouglas Gilbert unsigned int channel; 246fd32119bSDouglas Gilbert unsigned int target; 247fd32119bSDouglas Gilbert u64 lun; 248bf476433SChristoph Hellwig uuid_t lu_name; 249fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host; 250fd32119bSDouglas Gilbert unsigned long uas_bm[1]; 251fd32119bSDouglas Gilbert atomic_t num_in_q; 252c4837394SDouglas Gilbert atomic_t stopped; 253fd32119bSDouglas Gilbert bool used; 254fd32119bSDouglas Gilbert }; 255fd32119bSDouglas Gilbert 256fd32119bSDouglas Gilbert struct sdebug_host_info { 257fd32119bSDouglas Gilbert struct list_head host_list; 258fd32119bSDouglas Gilbert struct Scsi_Host *shost; 259fd32119bSDouglas Gilbert struct device dev; 260fd32119bSDouglas Gilbert struct list_head dev_info_list; 261fd32119bSDouglas Gilbert }; 262fd32119bSDouglas Gilbert 263fd32119bSDouglas Gilbert #define to_sdebug_host(d) \ 264fd32119bSDouglas Gilbert container_of(d, struct sdebug_host_info, dev) 265fd32119bSDouglas Gilbert 266fd32119bSDouglas Gilbert struct sdebug_defer { 267fd32119bSDouglas Gilbert struct hrtimer hrt; 268fd32119bSDouglas Gilbert struct execute_work ew; 269c4837394SDouglas Gilbert int sqa_idx; /* index of sdebug_queue array */ 270c4837394SDouglas Gilbert int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */ 271c4837394SDouglas Gilbert int issuing_cpu; 272fd32119bSDouglas Gilbert }; 273fd32119bSDouglas Gilbert 274fd32119bSDouglas Gilbert struct sdebug_queued_cmd { 275c4837394SDouglas Gilbert /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue 276c4837394SDouglas Gilbert * instance indicates this slot is in use. 277c4837394SDouglas Gilbert */ 278fd32119bSDouglas Gilbert struct sdebug_defer *sd_dp; 279fd32119bSDouglas Gilbert struct scsi_cmnd *a_cmnd; 280c4837394SDouglas Gilbert unsigned int inj_recovered:1; 281c4837394SDouglas Gilbert unsigned int inj_transport:1; 282c4837394SDouglas Gilbert unsigned int inj_dif:1; 283c4837394SDouglas Gilbert unsigned int inj_dix:1; 284c4837394SDouglas Gilbert unsigned int inj_short:1; 285fd32119bSDouglas Gilbert }; 286fd32119bSDouglas Gilbert 287c4837394SDouglas Gilbert struct sdebug_queue { 288c4837394SDouglas Gilbert struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE]; 289c4837394SDouglas Gilbert unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS]; 290c4837394SDouglas Gilbert spinlock_t qc_lock; 291c4837394SDouglas Gilbert atomic_t blocked; /* to temporarily stop more being queued */ 292fd32119bSDouglas Gilbert }; 293fd32119bSDouglas Gilbert 294c4837394SDouglas Gilbert static atomic_t sdebug_cmnd_count; /* number of incoming commands */ 295c4837394SDouglas Gilbert static atomic_t sdebug_completions; /* count of deferred completions */ 296c4837394SDouglas Gilbert static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */ 297c4837394SDouglas Gilbert static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */ 298c4837394SDouglas Gilbert 299fd32119bSDouglas Gilbert struct opcode_info_t { 300b01f6f83SDouglas Gilbert u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */ 301b01f6f83SDouglas Gilbert /* for terminating element */ 302fd32119bSDouglas Gilbert u8 opcode; /* if num_attached > 0, preferred */ 303fd32119bSDouglas Gilbert u16 sa; /* service action */ 304fd32119bSDouglas Gilbert u32 flags; /* OR-ed set of SDEB_F_* */ 305fd32119bSDouglas Gilbert int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 306fd32119bSDouglas Gilbert const struct opcode_info_t *arrp; /* num_attached elements or NULL */ 307fd32119bSDouglas Gilbert u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */ 308fd32119bSDouglas Gilbert /* ignore cdb bytes after position 15 */ 309fd32119bSDouglas Gilbert }; 310fd32119bSDouglas Gilbert 311fd32119bSDouglas Gilbert /* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */ 312c2248fc9SDouglas Gilbert enum sdeb_opcode_index { 313c2248fc9SDouglas Gilbert SDEB_I_INVALID_OPCODE = 0, 314c2248fc9SDouglas Gilbert SDEB_I_INQUIRY = 1, 315c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS = 2, 316c2248fc9SDouglas Gilbert SDEB_I_REQUEST_SENSE = 3, 317c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY = 4, 318c2248fc9SDouglas Gilbert SDEB_I_MODE_SENSE = 5, /* 6, 10 */ 319c2248fc9SDouglas Gilbert SDEB_I_MODE_SELECT = 6, /* 6, 10 */ 320c2248fc9SDouglas Gilbert SDEB_I_LOG_SENSE = 7, 321c2248fc9SDouglas Gilbert SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */ 322c2248fc9SDouglas Gilbert SDEB_I_READ = 9, /* 6, 10, 12, 16 */ 323c2248fc9SDouglas Gilbert SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */ 324c2248fc9SDouglas Gilbert SDEB_I_START_STOP = 11, 325c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */ 326c2248fc9SDouglas Gilbert SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */ 327c2248fc9SDouglas Gilbert SDEB_I_MAINT_IN = 14, 328c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT = 15, 329c2248fc9SDouglas Gilbert SDEB_I_VERIFY = 16, /* 10 only */ 330c2248fc9SDouglas Gilbert SDEB_I_VARIABLE_LEN = 17, 331c2248fc9SDouglas Gilbert SDEB_I_RESERVE = 18, /* 6, 10 */ 332c2248fc9SDouglas Gilbert SDEB_I_RELEASE = 19, /* 6, 10 */ 333c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */ 334c2248fc9SDouglas Gilbert SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */ 335c2248fc9SDouglas Gilbert SDEB_I_ATA_PT = 22, /* 12, 16 */ 336c2248fc9SDouglas Gilbert SDEB_I_SEND_DIAG = 23, 337c2248fc9SDouglas Gilbert SDEB_I_UNMAP = 24, 338c2248fc9SDouglas Gilbert SDEB_I_XDWRITEREAD = 25, /* 10 only */ 339c2248fc9SDouglas Gilbert SDEB_I_WRITE_BUFFER = 26, 340c2248fc9SDouglas Gilbert SDEB_I_WRITE_SAME = 27, /* 10, 16 */ 341c2248fc9SDouglas Gilbert SDEB_I_SYNC_CACHE = 28, /* 10 only */ 342c2248fc9SDouglas Gilbert SDEB_I_COMP_WRITE = 29, 343c2248fc9SDouglas Gilbert SDEB_I_LAST_ELEMENT = 30, /* keep this last */ 344c2248fc9SDouglas Gilbert }; 345c2248fc9SDouglas Gilbert 346c4837394SDouglas Gilbert 347c2248fc9SDouglas Gilbert static const unsigned char opcode_ind_arr[256] = { 348c2248fc9SDouglas Gilbert /* 0x0; 0x0->0x1f: 6 byte cdbs */ 349c2248fc9SDouglas Gilbert SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE, 350c2248fc9SDouglas Gilbert 0, 0, 0, 0, 351c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0, 352c2248fc9SDouglas Gilbert 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 353c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 354c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG, 355c2248fc9SDouglas Gilbert SDEB_I_ALLOW_REMOVAL, 0, 356c2248fc9SDouglas Gilbert /* 0x20; 0x20->0x3f: 10 byte cdbs */ 357c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0, 358c2248fc9SDouglas Gilbert SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY, 359c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0, 360c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0, 361c2248fc9SDouglas Gilbert /* 0x40; 0x40->0x5f: 10 byte cdbs */ 362c2248fc9SDouglas Gilbert 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0, 363c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0, 364c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE, 365c2248fc9SDouglas Gilbert SDEB_I_RELEASE, 366c2248fc9SDouglas Gilbert 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0, 367fd32119bSDouglas Gilbert /* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */ 368c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 370c2248fc9SDouglas Gilbert 0, SDEB_I_VARIABLE_LEN, 371c2248fc9SDouglas Gilbert /* 0x80; 0x80->0x9f: 16 byte cdbs */ 372c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0, 373c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0, 374c2248fc9SDouglas Gilbert 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0, 375c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT, 376c2248fc9SDouglas Gilbert /* 0xa0; 0xa0->0xbf: 12 byte cdbs */ 377c2248fc9SDouglas Gilbert SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN, 378c2248fc9SDouglas Gilbert SDEB_I_MAINT_OUT, 0, 0, 0, 379c2248fc9SDouglas Gilbert SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN, 380c2248fc9SDouglas Gilbert 0, 0, 0, 0, 381c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 382c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 383c2248fc9SDouglas Gilbert /* 0xc0; 0xc0->0xff: vendor specific */ 384c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 385c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 386c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 387c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 388c2248fc9SDouglas Gilbert }; 389c2248fc9SDouglas Gilbert 390c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *); 391c2248fc9SDouglas Gilbert static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *); 392c2248fc9SDouglas Gilbert static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *); 393c2248fc9SDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 394c2248fc9SDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *); 395c2248fc9SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *); 396c2248fc9SDouglas Gilbert static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *); 397c2248fc9SDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 398c2248fc9SDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *); 399c2248fc9SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *); 400c2248fc9SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *); 401c2248fc9SDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *); 402c2248fc9SDouglas Gilbert static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *); 403c2248fc9SDouglas Gilbert static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *); 40438d5c833SDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *); 40538d5c833SDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *); 406c2248fc9SDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *); 407c2248fc9SDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *); 408c2248fc9SDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *); 40938d5c833SDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *); 410acafd0b9SEwan D. Milne static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *); 411c2248fc9SDouglas Gilbert 412c2248fc9SDouglas Gilbert static const struct opcode_info_t msense_iarr[1] = { 413c2248fc9SDouglas Gilbert {0, 0x1a, 0, F_D_IN, NULL, NULL, 414c2248fc9SDouglas Gilbert {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 415c2248fc9SDouglas Gilbert }; 416c2248fc9SDouglas Gilbert 417c2248fc9SDouglas Gilbert static const struct opcode_info_t mselect_iarr[1] = { 418c2248fc9SDouglas Gilbert {0, 0x15, 0, F_D_OUT, NULL, NULL, 419c2248fc9SDouglas Gilbert {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 420c2248fc9SDouglas Gilbert }; 421c2248fc9SDouglas Gilbert 422c2248fc9SDouglas Gilbert static const struct opcode_info_t read_iarr[3] = { 423c2248fc9SDouglas Gilbert {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */ 424c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 425c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 426c2248fc9SDouglas Gilbert {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */ 427c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 428c2248fc9SDouglas Gilbert {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */ 429c2248fc9SDouglas Gilbert {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 430c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 431c2248fc9SDouglas Gilbert }; 432c2248fc9SDouglas Gilbert 433c2248fc9SDouglas Gilbert static const struct opcode_info_t write_iarr[3] = { 434c2248fc9SDouglas Gilbert {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */ 435c2248fc9SDouglas Gilbert {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 436c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 437c2248fc9SDouglas Gilbert {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */ 438c2248fc9SDouglas Gilbert {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 439c2248fc9SDouglas Gilbert {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */ 440c2248fc9SDouglas Gilbert {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f, 441c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 442c2248fc9SDouglas Gilbert }; 443c2248fc9SDouglas Gilbert 444c2248fc9SDouglas Gilbert static const struct opcode_info_t sa_in_iarr[1] = { 445c2248fc9SDouglas Gilbert {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL, 446c2248fc9SDouglas Gilbert {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 447c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0, 0xc7} }, 448c2248fc9SDouglas Gilbert }; 449c2248fc9SDouglas Gilbert 450c2248fc9SDouglas Gilbert static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */ 451c2248fc9SDouglas Gilbert {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0, 452c2248fc9SDouglas Gilbert NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa, 453c2248fc9SDouglas Gilbert 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */ 454c2248fc9SDouglas Gilbert }; 455c2248fc9SDouglas Gilbert 456c2248fc9SDouglas Gilbert static const struct opcode_info_t maint_in_iarr[2] = { 45738d5c833SDouglas Gilbert {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL, 458c2248fc9SDouglas Gilbert {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 459c2248fc9SDouglas Gilbert 0xc7, 0, 0, 0, 0} }, 46038d5c833SDouglas Gilbert {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL, 461c2248fc9SDouglas Gilbert {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 462c2248fc9SDouglas Gilbert 0, 0} }, 463c2248fc9SDouglas Gilbert }; 464c2248fc9SDouglas Gilbert 465c2248fc9SDouglas Gilbert static const struct opcode_info_t write_same_iarr[1] = { 466c2248fc9SDouglas Gilbert {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL, 467c2248fc9SDouglas Gilbert {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 468c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1f, 0xc7} }, 469c2248fc9SDouglas Gilbert }; 470c2248fc9SDouglas Gilbert 471c2248fc9SDouglas Gilbert static const struct opcode_info_t reserve_iarr[1] = { 472c2248fc9SDouglas Gilbert {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */ 473c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 474c2248fc9SDouglas Gilbert }; 475c2248fc9SDouglas Gilbert 476c2248fc9SDouglas Gilbert static const struct opcode_info_t release_iarr[1] = { 477c2248fc9SDouglas Gilbert {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */ 478c2248fc9SDouglas Gilbert {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 479c2248fc9SDouglas Gilbert }; 480c2248fc9SDouglas Gilbert 481c2248fc9SDouglas Gilbert 482c2248fc9SDouglas Gilbert /* This array is accessed via SDEB_I_* values. Make sure all are mapped, 483c2248fc9SDouglas Gilbert * plus the terminating elements for logic that scans this table such as 484c2248fc9SDouglas Gilbert * REPORT SUPPORTED OPERATION CODES. */ 485c2248fc9SDouglas Gilbert static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = { 486c2248fc9SDouglas Gilbert /* 0 */ 487c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, 488c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 489c2248fc9SDouglas Gilbert {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, 490c2248fc9SDouglas Gilbert {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 491c2248fc9SDouglas Gilbert {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL, 492c2248fc9SDouglas Gilbert {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 493c2248fc9SDouglas Gilbert 0, 0} }, 494c2248fc9SDouglas Gilbert {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL, 495c2248fc9SDouglas Gilbert {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 496c2248fc9SDouglas Gilbert {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */ 497c2248fc9SDouglas Gilbert {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 498c2248fc9SDouglas Gilbert {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr, 499c2248fc9SDouglas Gilbert {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 500c2248fc9SDouglas Gilbert 0} }, 501c2248fc9SDouglas Gilbert {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr, 502c2248fc9SDouglas Gilbert {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 503c2248fc9SDouglas Gilbert {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, 504c2248fc9SDouglas Gilbert {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 505c2248fc9SDouglas Gilbert 0, 0, 0} }, 506c2248fc9SDouglas Gilbert {0, 0x25, 0, F_D_IN, resp_readcap, NULL, 507c2248fc9SDouglas Gilbert {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0, 508c2248fc9SDouglas Gilbert 0, 0} }, 509c2248fc9SDouglas Gilbert {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr, 510c2248fc9SDouglas Gilbert {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 511c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */ 512c2248fc9SDouglas Gilbert /* 10 */ 513c2248fc9SDouglas Gilbert {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr, 514c2248fc9SDouglas Gilbert {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 515c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */ 516c2248fc9SDouglas Gilbert {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */ 517c2248fc9SDouglas Gilbert {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 518c2248fc9SDouglas Gilbert {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr, 519c2248fc9SDouglas Gilbert {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 520c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */ 521c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */ 522c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 523c2248fc9SDouglas Gilbert {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr, 524c2248fc9SDouglas Gilbert {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0, 525c2248fc9SDouglas Gilbert 0} }, 526c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */ 527c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 528f7f9f26bSDouglas Gilbert {0, 0x2f, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, NULL, NULL, /* VERIFY(10) */ 529f7f9f26bSDouglas Gilbert {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 530f7f9f26bSDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 531c2248fc9SDouglas Gilbert {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0, 532c2248fc9SDouglas Gilbert vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0, 533c2248fc9SDouglas Gilbert 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */ 534c2248fc9SDouglas Gilbert {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */ 535c2248fc9SDouglas Gilbert {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 536c2248fc9SDouglas Gilbert 0} }, 537c2248fc9SDouglas Gilbert {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */ 538c2248fc9SDouglas Gilbert {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 539c2248fc9SDouglas Gilbert 0} }, 540c2248fc9SDouglas Gilbert /* 20 */ 541f7f9f26bSDouglas Gilbert {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */ 542f7f9f26bSDouglas Gilbert {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 543c2248fc9SDouglas Gilbert {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */ 544c2248fc9SDouglas Gilbert {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 545c2248fc9SDouglas Gilbert {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */ 546c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 547c2248fc9SDouglas Gilbert {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */ 548c2248fc9SDouglas Gilbert {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 549c2248fc9SDouglas Gilbert {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */ 550c2248fc9SDouglas Gilbert {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 551c2248fc9SDouglas Gilbert {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10, 552c2248fc9SDouglas Gilbert NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 553c2248fc9SDouglas Gilbert 0, 0, 0, 0, 0, 0} }, 554acafd0b9SEwan D. Milne {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL, 555acafd0b9SEwan D. Milne {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 556acafd0b9SEwan D. Milne 0, 0, 0, 0} }, /* WRITE_BUFFER */ 557c2248fc9SDouglas Gilbert {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10, 558c2248fc9SDouglas Gilbert write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 559c2248fc9SDouglas Gilbert 0xff, 0xc7, 0, 0, 0, 0, 0, 0} }, 560c2248fc9SDouglas Gilbert {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */ 561c2248fc9SDouglas Gilbert {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 562c2248fc9SDouglas Gilbert 0, 0, 0, 0} }, 56338d5c833SDouglas Gilbert {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL, 564c2248fc9SDouglas Gilbert {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0, 565c2248fc9SDouglas Gilbert 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */ 566c2248fc9SDouglas Gilbert 567c2248fc9SDouglas Gilbert /* 30 */ 568c2248fc9SDouglas Gilbert {0xff, 0, 0, 0, NULL, NULL, /* terminating element */ 569c2248fc9SDouglas Gilbert {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, 570c2248fc9SDouglas Gilbert }; 571c2248fc9SDouglas Gilbert 572773642d9SDouglas Gilbert static int sdebug_add_host = DEF_NUM_HOST; 573773642d9SDouglas Gilbert static int sdebug_ato = DEF_ATO; 574c2206098SDouglas Gilbert static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */ 575773642d9SDouglas Gilbert static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB; 576773642d9SDouglas Gilbert static int sdebug_dif = DEF_DIF; 577773642d9SDouglas Gilbert static int sdebug_dix = DEF_DIX; 578773642d9SDouglas Gilbert static int sdebug_dsense = DEF_D_SENSE; 579773642d9SDouglas Gilbert static int sdebug_every_nth = DEF_EVERY_NTH; 580773642d9SDouglas Gilbert static int sdebug_fake_rw = DEF_FAKE_RW; 581773642d9SDouglas Gilbert static unsigned int sdebug_guard = DEF_GUARD; 582773642d9SDouglas Gilbert static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED; 583773642d9SDouglas Gilbert static int sdebug_max_luns = DEF_MAX_LUNS; 584c4837394SDouglas Gilbert static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */ 585cbf67842SDouglas Gilbert static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */ 586c2206098SDouglas Gilbert static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */ 587773642d9SDouglas Gilbert static int sdebug_no_lun_0 = DEF_NO_LUN_0; 588773642d9SDouglas Gilbert static int sdebug_no_uld; 589773642d9SDouglas Gilbert static int sdebug_num_parts = DEF_NUM_PARTS; 590773642d9SDouglas Gilbert static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */ 591773642d9SDouglas Gilbert static int sdebug_opt_blks = DEF_OPT_BLKS; 592773642d9SDouglas Gilbert static int sdebug_opts = DEF_OPTS; 593773642d9SDouglas Gilbert static int sdebug_physblk_exp = DEF_PHYSBLK_EXP; 59486e6828aSLukas Herbolt static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP; 595b01f6f83SDouglas Gilbert static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */ 596773642d9SDouglas Gilbert static int sdebug_scsi_level = DEF_SCSI_LEVEL; 597773642d9SDouglas Gilbert static int sdebug_sector_size = DEF_SECTOR_SIZE; 598773642d9SDouglas Gilbert static int sdebug_virtual_gb = DEF_VIRTUAL_GB; 599773642d9SDouglas Gilbert static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO; 600773642d9SDouglas Gilbert static unsigned int sdebug_lbpu = DEF_LBPU; 601773642d9SDouglas Gilbert static unsigned int sdebug_lbpws = DEF_LBPWS; 602773642d9SDouglas Gilbert static unsigned int sdebug_lbpws10 = DEF_LBPWS10; 603773642d9SDouglas Gilbert static unsigned int sdebug_lbprz = DEF_LBPRZ; 604773642d9SDouglas Gilbert static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT; 605773642d9SDouglas Gilbert static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY; 606773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS; 607773642d9SDouglas Gilbert static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC; 608773642d9SDouglas Gilbert static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH; 60909ba24c1SDouglas Gilbert static int sdebug_uuid_ctl = DEF_UUID_CTL; 610773642d9SDouglas Gilbert static bool sdebug_removable = DEF_REMOVABLE; 611773642d9SDouglas Gilbert static bool sdebug_clustering; 612773642d9SDouglas Gilbert static bool sdebug_host_lock = DEF_HOST_LOCK; 613773642d9SDouglas Gilbert static bool sdebug_strict = DEF_STRICT; 614817fd66bSDouglas Gilbert static bool sdebug_any_injecting_opt; 615773642d9SDouglas Gilbert static bool sdebug_verbose; 616f46eb0e9SDouglas Gilbert static bool have_dif_prot; 617c4837394SDouglas Gilbert static bool sdebug_statistics = DEF_STATISTICS; 618c4837394SDouglas Gilbert static bool sdebug_mq_active; 6191da177e4SLinus Torvalds 620c65b1445SDouglas Gilbert static unsigned int sdebug_store_sectors; 6211da177e4SLinus Torvalds static sector_t sdebug_capacity; /* in sectors */ 6221da177e4SLinus Torvalds 6231da177e4SLinus Torvalds /* old BIOS stuff, kernel may get rid of them but some mode sense pages 6241da177e4SLinus Torvalds may still need them */ 6251da177e4SLinus Torvalds static int sdebug_heads; /* heads per disk */ 6261da177e4SLinus Torvalds static int sdebug_cylinders_per; /* cylinders per surface */ 6271da177e4SLinus Torvalds static int sdebug_sectors_per; /* sectors per cylinder */ 6281da177e4SLinus Torvalds 6291da177e4SLinus Torvalds static LIST_HEAD(sdebug_host_list); 6301da177e4SLinus Torvalds static DEFINE_SPINLOCK(sdebug_host_list_lock); 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds static unsigned char *fake_storep; /* ramdisk storage */ 6336ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_storep; /* protection info */ 63444d92694SMartin K. Petersen static void *map_storep; /* provisioning map */ 6351da177e4SLinus Torvalds 63644d92694SMartin K. Petersen static unsigned long map_size; 637cbf67842SDouglas Gilbert static int num_aborts; 638cbf67842SDouglas Gilbert static int num_dev_resets; 639cbf67842SDouglas Gilbert static int num_target_resets; 640cbf67842SDouglas Gilbert static int num_bus_resets; 641cbf67842SDouglas Gilbert static int num_host_resets; 642c6a44287SMartin K. Petersen static int dix_writes; 643c6a44287SMartin K. Petersen static int dix_reads; 644c6a44287SMartin K. Petersen static int dif_errors; 6451da177e4SLinus Torvalds 646c4837394SDouglas Gilbert static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */ 647c4837394SDouglas Gilbert static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */ 648fd32119bSDouglas Gilbert 6491da177e4SLinus Torvalds static DEFINE_RWLOCK(atomic_rw); 6501da177e4SLinus Torvalds 651cbf67842SDouglas Gilbert static char sdebug_proc_name[] = MY_NAME; 652cbf67842SDouglas Gilbert static const char *my_name = MY_NAME; 6531da177e4SLinus Torvalds 6541da177e4SLinus Torvalds static struct bus_type pseudo_lld_bus; 6551da177e4SLinus Torvalds 6561da177e4SLinus Torvalds static struct device_driver sdebug_driverfs_driver = { 6571da177e4SLinus Torvalds .name = sdebug_proc_name, 6581da177e4SLinus Torvalds .bus = &pseudo_lld_bus, 6591da177e4SLinus Torvalds }; 6601da177e4SLinus Torvalds 6611da177e4SLinus Torvalds static const int check_condition_result = 6621da177e4SLinus Torvalds (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; 6631da177e4SLinus Torvalds 664c6a44287SMartin K. Petersen static const int illegal_condition_result = 665c6a44287SMartin K. Petersen (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION; 666c6a44287SMartin K. Petersen 667cbf67842SDouglas Gilbert static const int device_qfull_result = 668cbf67842SDouglas Gilbert (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL; 669cbf67842SDouglas Gilbert 670fd32119bSDouglas Gilbert 671760f3b03SDouglas Gilbert /* Only do the extra work involved in logical block provisioning if one or 672760f3b03SDouglas Gilbert * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing 673760f3b03SDouglas Gilbert * real reads and writes (i.e. not skipping them for speed). 674760f3b03SDouglas Gilbert */ 675760f3b03SDouglas Gilbert static inline bool scsi_debug_lbp(void) 676fd32119bSDouglas Gilbert { 677fd32119bSDouglas Gilbert return 0 == sdebug_fake_rw && 678fd32119bSDouglas Gilbert (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10); 679fd32119bSDouglas Gilbert } 680c65b1445SDouglas Gilbert 68114faa944SAkinobu Mita static void *fake_store(unsigned long long lba) 68214faa944SAkinobu Mita { 68314faa944SAkinobu Mita lba = do_div(lba, sdebug_store_sectors); 68414faa944SAkinobu Mita 685773642d9SDouglas Gilbert return fake_storep + lba * sdebug_sector_size; 68614faa944SAkinobu Mita } 68714faa944SAkinobu Mita 6886ebf105cSChristoph Hellwig static struct t10_pi_tuple *dif_store(sector_t sector) 68914faa944SAkinobu Mita { 69049413112SArnd Bergmann sector = sector_div(sector, sdebug_store_sectors); 69114faa944SAkinobu Mita 69214faa944SAkinobu Mita return dif_storep + sector; 69314faa944SAkinobu Mita } 69414faa944SAkinobu Mita 6958dea0d02SFUJITA Tomonori static void sdebug_max_tgts_luns(void) 6968dea0d02SFUJITA Tomonori { 6978dea0d02SFUJITA Tomonori struct sdebug_host_info *sdbg_host; 6988dea0d02SFUJITA Tomonori struct Scsi_Host *hpnt; 6998dea0d02SFUJITA Tomonori 7008dea0d02SFUJITA Tomonori spin_lock(&sdebug_host_list_lock); 7018dea0d02SFUJITA Tomonori list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 7028dea0d02SFUJITA Tomonori hpnt = sdbg_host->shost; 7038dea0d02SFUJITA Tomonori if ((hpnt->this_id >= 0) && 704773642d9SDouglas Gilbert (sdebug_num_tgts > hpnt->this_id)) 705773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 7068dea0d02SFUJITA Tomonori else 707773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 708773642d9SDouglas Gilbert /* sdebug_max_luns; */ 709f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 7108dea0d02SFUJITA Tomonori } 7118dea0d02SFUJITA Tomonori spin_unlock(&sdebug_host_list_lock); 7128dea0d02SFUJITA Tomonori } 7138dea0d02SFUJITA Tomonori 71422017ed2SDouglas Gilbert enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1}; 71522017ed2SDouglas Gilbert 71622017ed2SDouglas Gilbert /* Set in_bit to -1 to indicate no bit position of invalid field */ 717fd32119bSDouglas Gilbert static void mk_sense_invalid_fld(struct scsi_cmnd *scp, 718fd32119bSDouglas Gilbert enum sdeb_cmd_data c_d, 71922017ed2SDouglas Gilbert int in_byte, int in_bit) 72022017ed2SDouglas Gilbert { 72122017ed2SDouglas Gilbert unsigned char *sbuff; 72222017ed2SDouglas Gilbert u8 sks[4]; 72322017ed2SDouglas Gilbert int sl, asc; 72422017ed2SDouglas Gilbert 72522017ed2SDouglas Gilbert sbuff = scp->sense_buffer; 72622017ed2SDouglas Gilbert if (!sbuff) { 72722017ed2SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 72822017ed2SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 72922017ed2SDouglas Gilbert return; 73022017ed2SDouglas Gilbert } 73122017ed2SDouglas Gilbert asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST; 73222017ed2SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 733773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0); 73422017ed2SDouglas Gilbert memset(sks, 0, sizeof(sks)); 73522017ed2SDouglas Gilbert sks[0] = 0x80; 73622017ed2SDouglas Gilbert if (c_d) 73722017ed2SDouglas Gilbert sks[0] |= 0x40; 73822017ed2SDouglas Gilbert if (in_bit >= 0) { 73922017ed2SDouglas Gilbert sks[0] |= 0x8; 74022017ed2SDouglas Gilbert sks[0] |= 0x7 & in_bit; 74122017ed2SDouglas Gilbert } 74222017ed2SDouglas Gilbert put_unaligned_be16(in_byte, sks + 1); 743773642d9SDouglas Gilbert if (sdebug_dsense) { 74422017ed2SDouglas Gilbert sl = sbuff[7] + 8; 74522017ed2SDouglas Gilbert sbuff[7] = sl; 74622017ed2SDouglas Gilbert sbuff[sl] = 0x2; 74722017ed2SDouglas Gilbert sbuff[sl + 1] = 0x6; 74822017ed2SDouglas Gilbert memcpy(sbuff + sl + 4, sks, 3); 74922017ed2SDouglas Gilbert } else 75022017ed2SDouglas Gilbert memcpy(sbuff + 15, sks, 3); 751773642d9SDouglas Gilbert if (sdebug_verbose) 75222017ed2SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq" 75322017ed2SDouglas Gilbert "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n", 75422017ed2SDouglas Gilbert my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit); 75522017ed2SDouglas Gilbert } 75622017ed2SDouglas Gilbert 757cbf67842SDouglas Gilbert static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq) 7588dea0d02SFUJITA Tomonori { 7598dea0d02SFUJITA Tomonori unsigned char *sbuff; 7608dea0d02SFUJITA Tomonori 761cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 762cbf67842SDouglas Gilbert if (!sbuff) { 763cbf67842SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, 764cbf67842SDouglas Gilbert "%s: sense_buffer is NULL\n", __func__); 765cbf67842SDouglas Gilbert return; 766cbf67842SDouglas Gilbert } 767cbf67842SDouglas Gilbert memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE); 7688dea0d02SFUJITA Tomonori 769773642d9SDouglas Gilbert scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq); 7708dea0d02SFUJITA Tomonori 771773642d9SDouglas Gilbert if (sdebug_verbose) 772cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 773cbf67842SDouglas Gilbert "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n", 774cbf67842SDouglas Gilbert my_name, key, asc, asq); 7758dea0d02SFUJITA Tomonori } 7761da177e4SLinus Torvalds 777fd32119bSDouglas Gilbert static void mk_sense_invalid_opcode(struct scsi_cmnd *scp) 77822017ed2SDouglas Gilbert { 77922017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0); 78022017ed2SDouglas Gilbert } 78122017ed2SDouglas Gilbert 7821da177e4SLinus Torvalds static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg) 7831da177e4SLinus Torvalds { 784773642d9SDouglas Gilbert if (sdebug_verbose) { 785cbf67842SDouglas Gilbert if (0x1261 == cmd) 786cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 787cbf67842SDouglas Gilbert "%s: BLKFLSBUF [0x1261]\n", __func__); 788cbf67842SDouglas Gilbert else if (0x5331 == cmd) 789cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, 790cbf67842SDouglas Gilbert "%s: CDROM_GET_CAPABILITY [0x5331]\n", 791cbf67842SDouglas Gilbert __func__); 792cbf67842SDouglas Gilbert else 793cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n", 794cbf67842SDouglas Gilbert __func__, cmd); 7951da177e4SLinus Torvalds } 7961da177e4SLinus Torvalds return -EINVAL; 7971da177e4SLinus Torvalds /* return -ENOTTY; // correct return but upsets fdisk */ 7981da177e4SLinus Torvalds } 7991da177e4SLinus Torvalds 80019c8ead7SEwan D. Milne static void clear_luns_changed_on_target(struct sdebug_dev_info *devip) 80119c8ead7SEwan D. Milne { 80219c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 80319c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 80419c8ead7SEwan D. Milne 80519c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 80619c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, host_list) { 80719c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) { 80819c8ead7SEwan D. Milne if ((devip->sdbg_host == dp->sdbg_host) && 80919c8ead7SEwan D. Milne (devip->target == dp->target)) 81019c8ead7SEwan D. Milne clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm); 81119c8ead7SEwan D. Milne } 81219c8ead7SEwan D. Milne } 81319c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 81419c8ead7SEwan D. Milne } 81519c8ead7SEwan D. Milne 816f46eb0e9SDouglas Gilbert static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 8171da177e4SLinus Torvalds { 818cbf67842SDouglas Gilbert int k; 819cbf67842SDouglas Gilbert 820cbf67842SDouglas Gilbert k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS); 821cbf67842SDouglas Gilbert if (k != SDEBUG_NUM_UAS) { 822cbf67842SDouglas Gilbert const char *cp = NULL; 823cbf67842SDouglas Gilbert 824cbf67842SDouglas Gilbert switch (k) { 825cbf67842SDouglas Gilbert case SDEBUG_UA_POR: 826f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 827f46eb0e9SDouglas Gilbert POWER_ON_RESET_ASCQ); 828773642d9SDouglas Gilbert if (sdebug_verbose) 829cbf67842SDouglas Gilbert cp = "power on reset"; 830cbf67842SDouglas Gilbert break; 831cbf67842SDouglas Gilbert case SDEBUG_UA_BUS_RESET: 832f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC, 833f46eb0e9SDouglas Gilbert BUS_RESET_ASCQ); 834773642d9SDouglas Gilbert if (sdebug_verbose) 835cbf67842SDouglas Gilbert cp = "bus reset"; 836cbf67842SDouglas Gilbert break; 837cbf67842SDouglas Gilbert case SDEBUG_UA_MODE_CHANGED: 838f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 839f46eb0e9SDouglas Gilbert MODE_CHANGED_ASCQ); 840773642d9SDouglas Gilbert if (sdebug_verbose) 841cbf67842SDouglas Gilbert cp = "mode parameters changed"; 842cbf67842SDouglas Gilbert break; 8430d01c5dfSDouglas Gilbert case SDEBUG_UA_CAPACITY_CHANGED: 844f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC, 845f46eb0e9SDouglas Gilbert CAPACITY_CHANGED_ASCQ); 846773642d9SDouglas Gilbert if (sdebug_verbose) 8470d01c5dfSDouglas Gilbert cp = "capacity data changed"; 848f49accf1SEwan D. Milne break; 849acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED: 850f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 851b01f6f83SDouglas Gilbert TARGET_CHANGED_ASC, 852b01f6f83SDouglas Gilbert MICROCODE_CHANGED_ASCQ); 853773642d9SDouglas Gilbert if (sdebug_verbose) 854acafd0b9SEwan D. Milne cp = "microcode has been changed"; 855acafd0b9SEwan D. Milne break; 856acafd0b9SEwan D. Milne case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET: 857f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 858acafd0b9SEwan D. Milne TARGET_CHANGED_ASC, 859acafd0b9SEwan D. Milne MICROCODE_CHANGED_WO_RESET_ASCQ); 860773642d9SDouglas Gilbert if (sdebug_verbose) 861acafd0b9SEwan D. Milne cp = "microcode has been changed without reset"; 862acafd0b9SEwan D. Milne break; 86319c8ead7SEwan D. Milne case SDEBUG_UA_LUNS_CHANGED: 86419c8ead7SEwan D. Milne /* 86519c8ead7SEwan D. Milne * SPC-3 behavior is to report a UNIT ATTENTION with 86619c8ead7SEwan D. Milne * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN 86719c8ead7SEwan D. Milne * on the target, until a REPORT LUNS command is 86819c8ead7SEwan D. Milne * received. SPC-4 behavior is to report it only once. 869773642d9SDouglas Gilbert * NOTE: sdebug_scsi_level does not use the same 87019c8ead7SEwan D. Milne * values as struct scsi_device->scsi_level. 87119c8ead7SEwan D. Milne */ 872773642d9SDouglas Gilbert if (sdebug_scsi_level >= 6) /* SPC-4 and above */ 87319c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 874f46eb0e9SDouglas Gilbert mk_sense_buffer(scp, UNIT_ATTENTION, 87519c8ead7SEwan D. Milne TARGET_CHANGED_ASC, 87619c8ead7SEwan D. Milne LUNS_CHANGED_ASCQ); 877773642d9SDouglas Gilbert if (sdebug_verbose) 87819c8ead7SEwan D. Milne cp = "reported luns data has changed"; 87919c8ead7SEwan D. Milne break; 880cbf67842SDouglas Gilbert default: 881773642d9SDouglas Gilbert pr_warn("unexpected unit attention code=%d\n", k); 882773642d9SDouglas Gilbert if (sdebug_verbose) 883cbf67842SDouglas Gilbert cp = "unknown"; 884cbf67842SDouglas Gilbert break; 885cbf67842SDouglas Gilbert } 886cbf67842SDouglas Gilbert clear_bit(k, devip->uas_bm); 887773642d9SDouglas Gilbert if (sdebug_verbose) 888f46eb0e9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 889cbf67842SDouglas Gilbert "%s reports: Unit attention: %s\n", 890cbf67842SDouglas Gilbert my_name, cp); 8911da177e4SLinus Torvalds return check_condition_result; 8921da177e4SLinus Torvalds } 8931da177e4SLinus Torvalds return 0; 8941da177e4SLinus Torvalds } 8951da177e4SLinus Torvalds 896fb0cc8d1SDouglas Gilbert /* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */ 8971da177e4SLinus Torvalds static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 8981da177e4SLinus Torvalds int arr_len) 8991da177e4SLinus Torvalds { 90021a61829SFUJITA Tomonori int act_len; 901072d0bb3SFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 9021da177e4SLinus Torvalds 903072d0bb3SFUJITA Tomonori if (!sdb->length) 9041da177e4SLinus Torvalds return 0; 905072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 906773642d9SDouglas Gilbert return DID_ERROR << 16; 90721a61829SFUJITA Tomonori 90821a61829SFUJITA Tomonori act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents, 90921a61829SFUJITA Tomonori arr, arr_len); 91021a61829SFUJITA Tomonori sdb->resid = scsi_bufflen(scp) - act_len; 91121a61829SFUJITA Tomonori 9121da177e4SLinus Torvalds return 0; 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 915fb0cc8d1SDouglas Gilbert /* Partial build of SCSI "data-in" buffer. Returns 0 if ok else 916fb0cc8d1SDouglas Gilbert * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple 917fb0cc8d1SDouglas Gilbert * calls, not required to write in ascending offset order. Assumes resid 918fb0cc8d1SDouglas Gilbert * set to scsi_bufflen() prior to any calls. 919fb0cc8d1SDouglas Gilbert */ 920fb0cc8d1SDouglas Gilbert static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, 921fb0cc8d1SDouglas Gilbert int arr_len, unsigned int off_dst) 922fb0cc8d1SDouglas Gilbert { 923fb0cc8d1SDouglas Gilbert int act_len, n; 924fb0cc8d1SDouglas Gilbert struct scsi_data_buffer *sdb = scsi_in(scp); 925fb0cc8d1SDouglas Gilbert off_t skip = off_dst; 926fb0cc8d1SDouglas Gilbert 927fb0cc8d1SDouglas Gilbert if (sdb->length <= off_dst) 928fb0cc8d1SDouglas Gilbert return 0; 929fb0cc8d1SDouglas Gilbert if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_FROM_DEVICE)) 930fb0cc8d1SDouglas Gilbert return DID_ERROR << 16; 931fb0cc8d1SDouglas Gilbert 932fb0cc8d1SDouglas Gilbert act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents, 933fb0cc8d1SDouglas Gilbert arr, arr_len, skip); 934fb0cc8d1SDouglas Gilbert pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", 935fb0cc8d1SDouglas Gilbert __func__, off_dst, scsi_bufflen(scp), act_len, sdb->resid); 936fb0cc8d1SDouglas Gilbert n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len); 937fb0cc8d1SDouglas Gilbert sdb->resid = min(sdb->resid, n); 938fb0cc8d1SDouglas Gilbert return 0; 939fb0cc8d1SDouglas Gilbert } 940fb0cc8d1SDouglas Gilbert 941fb0cc8d1SDouglas Gilbert /* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into 942fb0cc8d1SDouglas Gilbert * 'arr' or -1 if error. 943fb0cc8d1SDouglas Gilbert */ 9441da177e4SLinus Torvalds static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, 94521a61829SFUJITA Tomonori int arr_len) 9461da177e4SLinus Torvalds { 94721a61829SFUJITA Tomonori if (!scsi_bufflen(scp)) 9481da177e4SLinus Torvalds return 0; 949072d0bb3SFUJITA Tomonori if (!(scsi_bidi_cmnd(scp) || scp->sc_data_direction == DMA_TO_DEVICE)) 9501da177e4SLinus Torvalds return -1; 95121a61829SFUJITA Tomonori 95221a61829SFUJITA Tomonori return scsi_sg_copy_to_buffer(scp, arr, arr_len); 9531da177e4SLinus Torvalds } 9541da177e4SLinus Torvalds 9551da177e4SLinus Torvalds 956e5203cf0SHannes Reinecke static char sdebug_inq_vendor_id[9] = "Linux "; 957e5203cf0SHannes Reinecke static char sdebug_inq_product_id[17] = "scsi_debug "; 958e5203cf0SHannes Reinecke static char sdebug_inq_product_rev[5] = "0186"; /* version less '.' */ 9591b37bd60SDouglas Gilbert /* Use some locally assigned NAAs for SAS addresses. */ 9601b37bd60SDouglas Gilbert static const u64 naa3_comp_a = 0x3222222000000000ULL; 9611b37bd60SDouglas Gilbert static const u64 naa3_comp_b = 0x3333333000000000ULL; 9621b37bd60SDouglas Gilbert static const u64 naa3_comp_c = 0x3111111000000000ULL; 9631da177e4SLinus Torvalds 964cbf67842SDouglas Gilbert /* Device identification VPD page. Returns number of bytes placed in arr */ 965760f3b03SDouglas Gilbert static int inquiry_vpd_83(unsigned char *arr, int port_group_id, 9665a09e398SHannes Reinecke int target_dev_id, int dev_id_num, 96709ba24c1SDouglas Gilbert const char *dev_id_str, int dev_id_str_len, 968bf476433SChristoph Hellwig const uuid_t *lu_name) 9691da177e4SLinus Torvalds { 970c65b1445SDouglas Gilbert int num, port_a; 971c65b1445SDouglas Gilbert char b[32]; 9721da177e4SLinus Torvalds 973c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 9741da177e4SLinus Torvalds /* T10 vendor identifier field format (faked) */ 9751da177e4SLinus Torvalds arr[0] = 0x2; /* ASCII */ 9761da177e4SLinus Torvalds arr[1] = 0x1; 9771da177e4SLinus Torvalds arr[2] = 0x0; 978e5203cf0SHannes Reinecke memcpy(&arr[4], sdebug_inq_vendor_id, 8); 979e5203cf0SHannes Reinecke memcpy(&arr[12], sdebug_inq_product_id, 16); 9801da177e4SLinus Torvalds memcpy(&arr[28], dev_id_str, dev_id_str_len); 9811da177e4SLinus Torvalds num = 8 + 16 + dev_id_str_len; 9821da177e4SLinus Torvalds arr[3] = num; 9831da177e4SLinus Torvalds num += 4; 984c65b1445SDouglas Gilbert if (dev_id_num >= 0) { 98509ba24c1SDouglas Gilbert if (sdebug_uuid_ctl) { 98609ba24c1SDouglas Gilbert /* Locally assigned UUID */ 98709ba24c1SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 98809ba24c1SDouglas Gilbert arr[num++] = 0xa; /* PIV=0, lu, naa */ 98909ba24c1SDouglas Gilbert arr[num++] = 0x0; 99009ba24c1SDouglas Gilbert arr[num++] = 0x12; 99109ba24c1SDouglas Gilbert arr[num++] = 0x10; /* uuid type=1, locally assigned */ 99209ba24c1SDouglas Gilbert arr[num++] = 0x0; 99309ba24c1SDouglas Gilbert memcpy(arr + num, lu_name, 16); 99409ba24c1SDouglas Gilbert num += 16; 99509ba24c1SDouglas Gilbert } else { 9961b37bd60SDouglas Gilbert /* NAA-3, Logical unit identifier (binary) */ 997c65b1445SDouglas Gilbert arr[num++] = 0x1; /* binary (not necessarily sas) */ 998c65b1445SDouglas Gilbert arr[num++] = 0x3; /* PIV=0, lu, naa */ 999c65b1445SDouglas Gilbert arr[num++] = 0x0; 1000c65b1445SDouglas Gilbert arr[num++] = 0x8; 10011b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num); 1002773642d9SDouglas Gilbert num += 8; 100309ba24c1SDouglas Gilbert } 1004c65b1445SDouglas Gilbert /* Target relative port number */ 1005c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1006c65b1445SDouglas Gilbert arr[num++] = 0x94; /* PIV=1, target port, rel port */ 1007c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1008c65b1445SDouglas Gilbert arr[num++] = 0x4; /* length */ 1009c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1010c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1011c65b1445SDouglas Gilbert arr[num++] = 0x0; 1012c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port A */ 1013c65b1445SDouglas Gilbert } 10141b37bd60SDouglas Gilbert /* NAA-3, Target port identifier */ 1015c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1016c65b1445SDouglas Gilbert arr[num++] = 0x93; /* piv=1, target port, naa */ 1017c65b1445SDouglas Gilbert arr[num++] = 0x0; 1018c65b1445SDouglas Gilbert arr[num++] = 0x8; 10191b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1020773642d9SDouglas Gilbert num += 8; 10211b37bd60SDouglas Gilbert /* NAA-3, Target port group identifier */ 10225a09e398SHannes Reinecke arr[num++] = 0x61; /* proto=sas, binary */ 10235a09e398SHannes Reinecke arr[num++] = 0x95; /* piv=1, target port group id */ 10245a09e398SHannes Reinecke arr[num++] = 0x0; 10255a09e398SHannes Reinecke arr[num++] = 0x4; 10265a09e398SHannes Reinecke arr[num++] = 0; 10275a09e398SHannes Reinecke arr[num++] = 0; 1028773642d9SDouglas Gilbert put_unaligned_be16(port_group_id, arr + num); 1029773642d9SDouglas Gilbert num += 2; 10301b37bd60SDouglas Gilbert /* NAA-3, Target device identifier */ 1031c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1032c65b1445SDouglas Gilbert arr[num++] = 0xa3; /* piv=1, target device, naa */ 1033c65b1445SDouglas Gilbert arr[num++] = 0x0; 1034c65b1445SDouglas Gilbert arr[num++] = 0x8; 10351b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num); 1036773642d9SDouglas Gilbert num += 8; 1037c65b1445SDouglas Gilbert /* SCSI name string: Target device identifier */ 1038c65b1445SDouglas Gilbert arr[num++] = 0x63; /* proto=sas, UTF-8 */ 1039c65b1445SDouglas Gilbert arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */ 1040c65b1445SDouglas Gilbert arr[num++] = 0x0; 1041c65b1445SDouglas Gilbert arr[num++] = 24; 10421b37bd60SDouglas Gilbert memcpy(arr + num, "naa.32222220", 12); 1043c65b1445SDouglas Gilbert num += 12; 1044c65b1445SDouglas Gilbert snprintf(b, sizeof(b), "%08X", target_dev_id); 1045c65b1445SDouglas Gilbert memcpy(arr + num, b, 8); 1046c65b1445SDouglas Gilbert num += 8; 1047c65b1445SDouglas Gilbert memset(arr + num, 0, 4); 1048c65b1445SDouglas Gilbert num += 4; 1049c65b1445SDouglas Gilbert return num; 1050c65b1445SDouglas Gilbert } 1051c65b1445SDouglas Gilbert 1052c65b1445SDouglas Gilbert static unsigned char vpd84_data[] = { 1053c65b1445SDouglas Gilbert /* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0, 1054c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x1, 1055c65b1445SDouglas Gilbert 0x22,0x22,0x22,0x0,0xbb,0x2, 1056c65b1445SDouglas Gilbert }; 1057c65b1445SDouglas Gilbert 1058cbf67842SDouglas Gilbert /* Software interface identification VPD page */ 1059760f3b03SDouglas Gilbert static int inquiry_vpd_84(unsigned char *arr) 1060c65b1445SDouglas Gilbert { 1061c65b1445SDouglas Gilbert memcpy(arr, vpd84_data, sizeof(vpd84_data)); 1062c65b1445SDouglas Gilbert return sizeof(vpd84_data); 1063c65b1445SDouglas Gilbert } 1064c65b1445SDouglas Gilbert 1065cbf67842SDouglas Gilbert /* Management network addresses VPD page */ 1066760f3b03SDouglas Gilbert static int inquiry_vpd_85(unsigned char *arr) 1067c65b1445SDouglas Gilbert { 1068c65b1445SDouglas Gilbert int num = 0; 1069c65b1445SDouglas Gilbert const char * na1 = "https://www.kernel.org/config"; 1070c65b1445SDouglas Gilbert const char * na2 = "http://www.kernel.org/log"; 1071c65b1445SDouglas Gilbert int plen, olen; 1072c65b1445SDouglas Gilbert 1073c65b1445SDouglas Gilbert arr[num++] = 0x1; /* lu, storage config */ 1074c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1075c65b1445SDouglas Gilbert arr[num++] = 0x0; 1076c65b1445SDouglas Gilbert olen = strlen(na1); 1077c65b1445SDouglas Gilbert plen = olen + 1; 1078c65b1445SDouglas Gilbert if (plen % 4) 1079c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1080c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null termianted, padded */ 1081c65b1445SDouglas Gilbert memcpy(arr + num, na1, olen); 1082c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1083c65b1445SDouglas Gilbert num += plen; 1084c65b1445SDouglas Gilbert 1085c65b1445SDouglas Gilbert arr[num++] = 0x4; /* lu, logging */ 1086c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1087c65b1445SDouglas Gilbert arr[num++] = 0x0; 1088c65b1445SDouglas Gilbert olen = strlen(na2); 1089c65b1445SDouglas Gilbert plen = olen + 1; 1090c65b1445SDouglas Gilbert if (plen % 4) 1091c65b1445SDouglas Gilbert plen = ((plen / 4) + 1) * 4; 1092c65b1445SDouglas Gilbert arr[num++] = plen; /* length, null terminated, padded */ 1093c65b1445SDouglas Gilbert memcpy(arr + num, na2, olen); 1094c65b1445SDouglas Gilbert memset(arr + num + olen, 0, plen - olen); 1095c65b1445SDouglas Gilbert num += plen; 1096c65b1445SDouglas Gilbert 1097c65b1445SDouglas Gilbert return num; 1098c65b1445SDouglas Gilbert } 1099c65b1445SDouglas Gilbert 1100c65b1445SDouglas Gilbert /* SCSI ports VPD page */ 1101760f3b03SDouglas Gilbert static int inquiry_vpd_88(unsigned char *arr, int target_dev_id) 1102c65b1445SDouglas Gilbert { 1103c65b1445SDouglas Gilbert int num = 0; 1104c65b1445SDouglas Gilbert int port_a, port_b; 1105c65b1445SDouglas Gilbert 1106c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1107c65b1445SDouglas Gilbert port_b = port_a + 1; 1108c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1109c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1110c65b1445SDouglas Gilbert arr[num++] = 0x0; 1111c65b1445SDouglas Gilbert arr[num++] = 0x1; /* relative port 1 (primary) */ 1112c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1113c65b1445SDouglas Gilbert num += 6; 1114c65b1445SDouglas Gilbert arr[num++] = 0x0; 1115c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1116c65b1445SDouglas Gilbert /* naa-5 target port identifier (A) */ 1117c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1118c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1119c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1120c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 11211b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_a, arr + num); 1122773642d9SDouglas Gilbert num += 8; 1123c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1124c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1125c65b1445SDouglas Gilbert arr[num++] = 0x0; 1126c65b1445SDouglas Gilbert arr[num++] = 0x2; /* relative port 2 (secondary) */ 1127c65b1445SDouglas Gilbert memset(arr + num, 0, 6); 1128c65b1445SDouglas Gilbert num += 6; 1129c65b1445SDouglas Gilbert arr[num++] = 0x0; 1130c65b1445SDouglas Gilbert arr[num++] = 12; /* length tp descriptor */ 1131c65b1445SDouglas Gilbert /* naa-5 target port identifier (B) */ 1132c65b1445SDouglas Gilbert arr[num++] = 0x61; /* proto=sas, binary */ 1133c65b1445SDouglas Gilbert arr[num++] = 0x93; /* PIV=1, target port, NAA */ 1134c65b1445SDouglas Gilbert arr[num++] = 0x0; /* reserved */ 1135c65b1445SDouglas Gilbert arr[num++] = 0x8; /* length */ 11361b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a + port_b, arr + num); 1137773642d9SDouglas Gilbert num += 8; 1138c65b1445SDouglas Gilbert 1139c65b1445SDouglas Gilbert return num; 1140c65b1445SDouglas Gilbert } 1141c65b1445SDouglas Gilbert 1142c65b1445SDouglas Gilbert 1143c65b1445SDouglas Gilbert static unsigned char vpd89_data[] = { 1144c65b1445SDouglas Gilbert /* from 4th byte */ 0,0,0,0, 1145c65b1445SDouglas Gilbert 'l','i','n','u','x',' ',' ',' ', 1146c65b1445SDouglas Gilbert 'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ', 1147c65b1445SDouglas Gilbert '1','2','3','4', 1148c65b1445SDouglas Gilbert 0x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, 1149c65b1445SDouglas Gilbert 0xec,0,0,0, 1150c65b1445SDouglas Gilbert 0x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0, 1151c65b1445SDouglas Gilbert 0,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20, 1152c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33, 1153c65b1445SDouglas Gilbert 0x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31, 1154c65b1445SDouglas Gilbert 0x53,0x41, 1155c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1156c65b1445SDouglas Gilbert 0x20,0x20, 1157c65b1445SDouglas Gilbert 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 1158c65b1445SDouglas Gilbert 0x10,0x80, 1159c65b1445SDouglas Gilbert 0,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0, 1160c65b1445SDouglas Gilbert 0x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0, 1161c65b1445SDouglas Gilbert 0x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0, 1162c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0, 1163c65b1445SDouglas Gilbert 0x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40, 1164c65b1445SDouglas Gilbert 0x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0, 1165c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0, 1166c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1167c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1168c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1169c65b1445SDouglas Gilbert 0x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42, 1170c65b1445SDouglas Gilbert 0,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8, 1171c65b1445SDouglas Gilbert 0xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe, 1172c65b1445SDouglas Gilbert 0,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0, 1173c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1174c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1175c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1176c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1177c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1178c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1179c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1180c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1181c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1182c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1183c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1184c65b1445SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51, 1185c65b1445SDouglas Gilbert }; 1186c65b1445SDouglas Gilbert 1187cbf67842SDouglas Gilbert /* ATA Information VPD page */ 1188760f3b03SDouglas Gilbert static int inquiry_vpd_89(unsigned char *arr) 1189c65b1445SDouglas Gilbert { 1190c65b1445SDouglas Gilbert memcpy(arr, vpd89_data, sizeof(vpd89_data)); 1191c65b1445SDouglas Gilbert return sizeof(vpd89_data); 1192c65b1445SDouglas Gilbert } 1193c65b1445SDouglas Gilbert 1194c65b1445SDouglas Gilbert 1195c65b1445SDouglas Gilbert static unsigned char vpdb0_data[] = { 11961e49f785SDouglas Gilbert /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64, 11971e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11981e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 11991e49f785SDouglas Gilbert 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 1200c65b1445SDouglas Gilbert }; 1201c65b1445SDouglas Gilbert 1202cbf67842SDouglas Gilbert /* Block limits VPD page (SBC-3) */ 1203760f3b03SDouglas Gilbert static int inquiry_vpd_b0(unsigned char *arr) 1204c65b1445SDouglas Gilbert { 1205ea61fca5SMartin K. Petersen unsigned int gran; 1206ea61fca5SMartin K. Petersen 1207c65b1445SDouglas Gilbert memcpy(arr, vpdb0_data, sizeof(vpdb0_data)); 1208e308b3d1SMartin K. Petersen 1209e308b3d1SMartin K. Petersen /* Optimal transfer length granularity */ 121086e6828aSLukas Herbolt if (sdebug_opt_xferlen_exp != 0 && 121186e6828aSLukas Herbolt sdebug_physblk_exp < sdebug_opt_xferlen_exp) 121286e6828aSLukas Herbolt gran = 1 << sdebug_opt_xferlen_exp; 121386e6828aSLukas Herbolt else 1214773642d9SDouglas Gilbert gran = 1 << sdebug_physblk_exp; 1215773642d9SDouglas Gilbert put_unaligned_be16(gran, arr + 2); 1216e308b3d1SMartin K. Petersen 1217e308b3d1SMartin K. Petersen /* Maximum Transfer Length */ 1218773642d9SDouglas Gilbert if (sdebug_store_sectors > 0x400) 1219773642d9SDouglas Gilbert put_unaligned_be32(sdebug_store_sectors, arr + 4); 122044d92694SMartin K. Petersen 1221e308b3d1SMartin K. Petersen /* Optimal Transfer Length */ 1222773642d9SDouglas Gilbert put_unaligned_be32(sdebug_opt_blks, &arr[8]); 1223e308b3d1SMartin K. Petersen 1224773642d9SDouglas Gilbert if (sdebug_lbpu) { 1225e308b3d1SMartin K. Petersen /* Maximum Unmap LBA Count */ 1226773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]); 1227e308b3d1SMartin K. Petersen 1228e308b3d1SMartin K. Petersen /* Maximum Unmap Block Descriptor Count */ 1229773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]); 123044d92694SMartin K. Petersen } 123144d92694SMartin K. Petersen 1232e308b3d1SMartin K. Petersen /* Unmap Granularity Alignment */ 1233773642d9SDouglas Gilbert if (sdebug_unmap_alignment) { 1234773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_alignment, &arr[28]); 123544d92694SMartin K. Petersen arr[28] |= 0x80; /* UGAVALID */ 123644d92694SMartin K. Petersen } 123744d92694SMartin K. Petersen 1238e308b3d1SMartin K. Petersen /* Optimal Unmap Granularity */ 1239773642d9SDouglas Gilbert put_unaligned_be32(sdebug_unmap_granularity, &arr[24]); 12406014759cSMartin K. Petersen 12415b94e232SMartin K. Petersen /* Maximum WRITE SAME Length */ 1242773642d9SDouglas Gilbert put_unaligned_be64(sdebug_write_same_length, &arr[32]); 12435b94e232SMartin K. Petersen 12445b94e232SMartin K. Petersen return 0x3c; /* Mandatory page length for Logical Block Provisioning */ 124544d92694SMartin K. Petersen 1246c65b1445SDouglas Gilbert return sizeof(vpdb0_data); 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds 12491e49f785SDouglas Gilbert /* Block device characteristics VPD page (SBC-3) */ 1250760f3b03SDouglas Gilbert static int inquiry_vpd_b1(unsigned char *arr) 1251eac6e8e4SMatthew Wilcox { 1252eac6e8e4SMatthew Wilcox memset(arr, 0, 0x3c); 1253eac6e8e4SMatthew Wilcox arr[0] = 0; 12541e49f785SDouglas Gilbert arr[1] = 1; /* non rotating medium (e.g. solid state) */ 12551e49f785SDouglas Gilbert arr[2] = 0; 12561e49f785SDouglas Gilbert arr[3] = 5; /* less than 1.8" */ 1257eac6e8e4SMatthew Wilcox 1258eac6e8e4SMatthew Wilcox return 0x3c; 1259eac6e8e4SMatthew Wilcox } 12601da177e4SLinus Torvalds 1261760f3b03SDouglas Gilbert /* Logical block provisioning VPD page (SBC-4) */ 1262760f3b03SDouglas Gilbert static int inquiry_vpd_b2(unsigned char *arr) 12636014759cSMartin K. Petersen { 12643f0bc3b3SMartin K. Petersen memset(arr, 0, 0x4); 12656014759cSMartin K. Petersen arr[0] = 0; /* threshold exponent */ 1266773642d9SDouglas Gilbert if (sdebug_lbpu) 12676014759cSMartin K. Petersen arr[1] = 1 << 7; 1268773642d9SDouglas Gilbert if (sdebug_lbpws) 12696014759cSMartin K. Petersen arr[1] |= 1 << 6; 1270773642d9SDouglas Gilbert if (sdebug_lbpws10) 12715b94e232SMartin K. Petersen arr[1] |= 1 << 5; 1272760f3b03SDouglas Gilbert if (sdebug_lbprz && scsi_debug_lbp()) 1273760f3b03SDouglas Gilbert arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */ 1274760f3b03SDouglas Gilbert /* anc_sup=0; dp=0 (no provisioning group descriptor) */ 1275760f3b03SDouglas Gilbert /* minimum_percentage=0; provisioning_type=0 (unknown) */ 1276760f3b03SDouglas Gilbert /* threshold_percentage=0 */ 12773f0bc3b3SMartin K. Petersen return 0x4; 12786014759cSMartin K. Petersen } 12796014759cSMartin K. Petersen 12801da177e4SLinus Torvalds #define SDEBUG_LONG_INQ_SZ 96 1281c65b1445SDouglas Gilbert #define SDEBUG_MAX_INQ_ARR_SZ 584 12821da177e4SLinus Torvalds 1283c2248fc9SDouglas Gilbert static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 12841da177e4SLinus Torvalds { 12851da177e4SLinus Torvalds unsigned char pq_pdt; 12865a09e398SHannes Reinecke unsigned char * arr; 128701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 12885a09e398SHannes Reinecke int alloc_len, n, ret; 1289760f3b03SDouglas Gilbert bool have_wlun, is_disk; 12901da177e4SLinus Torvalds 1291773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 3); 12926f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC); 12936f3cbf55SDouglas Gilbert if (! arr) 12946f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 1295760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 1296b01f6f83SDouglas Gilbert have_wlun = scsi_is_wlun(scp->device->lun); 1297c2248fc9SDouglas Gilbert if (have_wlun) 1298b01f6f83SDouglas Gilbert pq_pdt = TYPE_WLUN; /* present, wlun */ 1299b01f6f83SDouglas Gilbert else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL)) 1300b01f6f83SDouglas Gilbert pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */ 1301c65b1445SDouglas Gilbert else 1302773642d9SDouglas Gilbert pq_pdt = (sdebug_ptype & 0x1f); 13031da177e4SLinus Torvalds arr[0] = pq_pdt; 13041da177e4SLinus Torvalds if (0x2 & cmd[1]) { /* CMDDT bit set */ 130522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1); 13065a09e398SHannes Reinecke kfree(arr); 13071da177e4SLinus Torvalds return check_condition_result; 13081da177e4SLinus Torvalds } else if (0x1 & cmd[1]) { /* EVPD bit set */ 13095a09e398SHannes Reinecke int lu_id_num, port_group_id, target_dev_id, len; 1310c65b1445SDouglas Gilbert char lu_id_str[6]; 1311c65b1445SDouglas Gilbert int host_no = devip->sdbg_host->shost->host_no; 13121da177e4SLinus Torvalds 13135a09e398SHannes Reinecke port_group_id = (((host_no + 1) & 0x7f) << 8) + 13145a09e398SHannes Reinecke (devip->channel & 0x7f); 1315b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 131623183910SDouglas Gilbert host_no = 0; 1317c2248fc9SDouglas Gilbert lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) + 1318c65b1445SDouglas Gilbert (devip->target * 1000) + devip->lun); 1319c65b1445SDouglas Gilbert target_dev_id = ((host_no + 1) * 2000) + 1320c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 1321c65b1445SDouglas Gilbert len = scnprintf(lu_id_str, 6, "%d", lu_id_num); 13221da177e4SLinus Torvalds if (0 == cmd[2]) { /* supported vital product data pages */ 1323c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1324c65b1445SDouglas Gilbert n = 4; 1325c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 1326c65b1445SDouglas Gilbert arr[n++] = 0x80; /* unit serial number */ 1327c65b1445SDouglas Gilbert arr[n++] = 0x83; /* device identification */ 1328c65b1445SDouglas Gilbert arr[n++] = 0x84; /* software interface ident. */ 1329c65b1445SDouglas Gilbert arr[n++] = 0x85; /* management network addresses */ 1330c65b1445SDouglas Gilbert arr[n++] = 0x86; /* extended inquiry */ 1331c65b1445SDouglas Gilbert arr[n++] = 0x87; /* mode page policy */ 1332c65b1445SDouglas Gilbert arr[n++] = 0x88; /* SCSI ports */ 1333760f3b03SDouglas Gilbert if (is_disk) { /* SBC only */ 1334c65b1445SDouglas Gilbert arr[n++] = 0x89; /* ATA information */ 1335760f3b03SDouglas Gilbert arr[n++] = 0xb0; /* Block limits */ 1336760f3b03SDouglas Gilbert arr[n++] = 0xb1; /* Block characteristics */ 1337760f3b03SDouglas Gilbert arr[n++] = 0xb2; /* Logical Block Prov */ 1338760f3b03SDouglas Gilbert } 1339c65b1445SDouglas Gilbert arr[3] = n - 4; /* number of supported VPD pages */ 13401da177e4SLinus Torvalds } else if (0x80 == cmd[2]) { /* unit serial number */ 1341c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 13421da177e4SLinus Torvalds arr[3] = len; 1343c65b1445SDouglas Gilbert memcpy(&arr[4], lu_id_str, len); 13441da177e4SLinus Torvalds } else if (0x83 == cmd[2]) { /* device identification */ 1345c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1346760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_83(&arr[4], port_group_id, 13475a09e398SHannes Reinecke target_dev_id, lu_id_num, 134809ba24c1SDouglas Gilbert lu_id_str, len, 134909ba24c1SDouglas Gilbert &devip->lu_name); 1350c65b1445SDouglas Gilbert } else if (0x84 == cmd[2]) { /* Software interface ident. */ 1351c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1352760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_84(&arr[4]); 1353c65b1445SDouglas Gilbert } else if (0x85 == cmd[2]) { /* Management network addresses */ 1354c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1355760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_85(&arr[4]); 1356c65b1445SDouglas Gilbert } else if (0x86 == cmd[2]) { /* extended inquiry */ 1357c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1358c65b1445SDouglas Gilbert arr[3] = 0x3c; /* number of following entries */ 13598475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE3_PROTECTION) 1360c6a44287SMartin K. Petersen arr[4] = 0x4; /* SPT: GRD_CHK:1 */ 1361760f3b03SDouglas Gilbert else if (have_dif_prot) 1362c6a44287SMartin K. Petersen arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */ 1363c6a44287SMartin K. Petersen else 1364c65b1445SDouglas Gilbert arr[4] = 0x0; /* no protection stuff */ 1365c65b1445SDouglas Gilbert arr[5] = 0x7; /* head of q, ordered + simple q's */ 1366c65b1445SDouglas Gilbert } else if (0x87 == cmd[2]) { /* mode page policy */ 1367c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1368c65b1445SDouglas Gilbert arr[3] = 0x8; /* number of following entries */ 1369c65b1445SDouglas Gilbert arr[4] = 0x2; /* disconnect-reconnect mp */ 1370c65b1445SDouglas Gilbert arr[6] = 0x80; /* mlus, shared */ 1371c65b1445SDouglas Gilbert arr[8] = 0x18; /* protocol specific lu */ 1372c65b1445SDouglas Gilbert arr[10] = 0x82; /* mlus, per initiator port */ 1373c65b1445SDouglas Gilbert } else if (0x88 == cmd[2]) { /* SCSI Ports */ 1374c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1375760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_88(&arr[4], target_dev_id); 1376760f3b03SDouglas Gilbert } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */ 1377c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1378760f3b03SDouglas Gilbert n = inquiry_vpd_89(&arr[4]); 1379773642d9SDouglas Gilbert put_unaligned_be16(n, arr + 2); 1380760f3b03SDouglas Gilbert } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */ 1381c65b1445SDouglas Gilbert arr[1] = cmd[2]; /*sanity */ 1382760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b0(&arr[4]); 1383760f3b03SDouglas Gilbert } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */ 1384eac6e8e4SMatthew Wilcox arr[1] = cmd[2]; /*sanity */ 1385760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b1(&arr[4]); 1386760f3b03SDouglas Gilbert } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */ 13876014759cSMartin K. Petersen arr[1] = cmd[2]; /*sanity */ 1388760f3b03SDouglas Gilbert arr[3] = inquiry_vpd_b2(&arr[4]); 13891da177e4SLinus Torvalds } else { 139022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 13915a09e398SHannes Reinecke kfree(arr); 13921da177e4SLinus Torvalds return check_condition_result; 13931da177e4SLinus Torvalds } 1394773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 13955a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 1396c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 13975a09e398SHannes Reinecke kfree(arr); 13985a09e398SHannes Reinecke return ret; 13991da177e4SLinus Torvalds } 14001da177e4SLinus Torvalds /* drops through here for a standard inquiry */ 1401773642d9SDouglas Gilbert arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */ 1402773642d9SDouglas Gilbert arr[2] = sdebug_scsi_level; 14031da177e4SLinus Torvalds arr[3] = 2; /* response_data_format==2 */ 14041da177e4SLinus Torvalds arr[4] = SDEBUG_LONG_INQ_SZ - 5; 1405f46eb0e9SDouglas Gilbert arr[5] = (int)have_dif_prot; /* PROTECT bit */ 1406b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) 140770bdf202SMartin K. Petersen arr[5] |= 0x10; /* claim: implicit TPGS */ 1408c65b1445SDouglas Gilbert arr[6] = 0x10; /* claim: MultiP */ 14091da177e4SLinus Torvalds /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */ 1410c65b1445SDouglas Gilbert arr[7] = 0xa; /* claim: LINKED + CMDQUE */ 1411e5203cf0SHannes Reinecke memcpy(&arr[8], sdebug_inq_vendor_id, 8); 1412e5203cf0SHannes Reinecke memcpy(&arr[16], sdebug_inq_product_id, 16); 1413e5203cf0SHannes Reinecke memcpy(&arr[32], sdebug_inq_product_rev, 4); 14141da177e4SLinus Torvalds /* version descriptors (2 bytes each) follow */ 1415760f3b03SDouglas Gilbert put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */ 1416760f3b03SDouglas Gilbert put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */ 1417c65b1445SDouglas Gilbert n = 62; 1418760f3b03SDouglas Gilbert if (is_disk) { /* SBC-4 no version claimed */ 1419760f3b03SDouglas Gilbert put_unaligned_be16(0x600, arr + n); 1420760f3b03SDouglas Gilbert n += 2; 1421760f3b03SDouglas Gilbert } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */ 1422760f3b03SDouglas Gilbert put_unaligned_be16(0x525, arr + n); 1423760f3b03SDouglas Gilbert n += 2; 14241da177e4SLinus Torvalds } 1425760f3b03SDouglas Gilbert put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */ 14265a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 14271da177e4SLinus Torvalds min(alloc_len, SDEBUG_LONG_INQ_SZ)); 14285a09e398SHannes Reinecke kfree(arr); 14295a09e398SHannes Reinecke return ret; 14301da177e4SLinus Torvalds } 14311da177e4SLinus Torvalds 1432fd32119bSDouglas Gilbert static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1433fd32119bSDouglas Gilbert 0, 0, 0x0, 0x0}; 1434fd32119bSDouglas Gilbert 14351da177e4SLinus Torvalds static int resp_requests(struct scsi_cmnd * scp, 14361da177e4SLinus Torvalds struct sdebug_dev_info * devip) 14371da177e4SLinus Torvalds { 14381da177e4SLinus Torvalds unsigned char * sbuff; 143901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1440cbf67842SDouglas Gilbert unsigned char arr[SCSI_SENSE_BUFFERSIZE]; 14412492fc09STomas Winkler bool dsense; 14421da177e4SLinus Torvalds int len = 18; 14431da177e4SLinus Torvalds 1444c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 1445c2248fc9SDouglas Gilbert dsense = !!(cmd[1] & 1); 1446cbf67842SDouglas Gilbert sbuff = scp->sense_buffer; 1447c65b1445SDouglas Gilbert if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) { 1448c2248fc9SDouglas Gilbert if (dsense) { 1449c65b1445SDouglas Gilbert arr[0] = 0x72; 1450c65b1445SDouglas Gilbert arr[1] = 0x0; /* NO_SENSE in sense_key */ 1451c65b1445SDouglas Gilbert arr[2] = THRESHOLD_EXCEEDED; 1452c65b1445SDouglas Gilbert arr[3] = 0xff; /* TEST set and MRIE==6 */ 1453c2248fc9SDouglas Gilbert len = 8; 1454c65b1445SDouglas Gilbert } else { 1455c65b1445SDouglas Gilbert arr[0] = 0x70; 1456c65b1445SDouglas Gilbert arr[2] = 0x0; /* NO_SENSE in sense_key */ 1457c65b1445SDouglas Gilbert arr[7] = 0xa; /* 18 byte sense buffer */ 1458c65b1445SDouglas Gilbert arr[12] = THRESHOLD_EXCEEDED; 1459c65b1445SDouglas Gilbert arr[13] = 0xff; /* TEST set and MRIE==6 */ 1460c65b1445SDouglas Gilbert } 1461c65b1445SDouglas Gilbert } else { 1462cbf67842SDouglas Gilbert memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE); 1463773642d9SDouglas Gilbert if (arr[0] >= 0x70 && dsense == sdebug_dsense) 1464c2248fc9SDouglas Gilbert ; /* have sense and formats match */ 1465c2248fc9SDouglas Gilbert else if (arr[0] <= 0x70) { 1466c2248fc9SDouglas Gilbert if (dsense) { 1467c2248fc9SDouglas Gilbert memset(arr, 0, 8); 1468c2248fc9SDouglas Gilbert arr[0] = 0x72; 1469c2248fc9SDouglas Gilbert len = 8; 1470c2248fc9SDouglas Gilbert } else { 1471c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1472c2248fc9SDouglas Gilbert arr[0] = 0x70; 1473c2248fc9SDouglas Gilbert arr[7] = 0xa; 1474c2248fc9SDouglas Gilbert } 1475c2248fc9SDouglas Gilbert } else if (dsense) { 1476c2248fc9SDouglas Gilbert memset(arr, 0, 8); 14771da177e4SLinus Torvalds arr[0] = 0x72; 14781da177e4SLinus Torvalds arr[1] = sbuff[2]; /* sense key */ 14791da177e4SLinus Torvalds arr[2] = sbuff[12]; /* asc */ 14801da177e4SLinus Torvalds arr[3] = sbuff[13]; /* ascq */ 14811da177e4SLinus Torvalds len = 8; 1482c2248fc9SDouglas Gilbert } else { 1483c2248fc9SDouglas Gilbert memset(arr, 0, 18); 1484c2248fc9SDouglas Gilbert arr[0] = 0x70; 1485c2248fc9SDouglas Gilbert arr[2] = sbuff[1]; 1486c2248fc9SDouglas Gilbert arr[7] = 0xa; 1487c2248fc9SDouglas Gilbert arr[12] = sbuff[1]; 1488c2248fc9SDouglas Gilbert arr[13] = sbuff[3]; 1489c65b1445SDouglas Gilbert } 1490c2248fc9SDouglas Gilbert 1491c65b1445SDouglas Gilbert } 1492cbf67842SDouglas Gilbert mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0); 14931da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, len); 14941da177e4SLinus Torvalds } 14951da177e4SLinus Torvalds 1496c65b1445SDouglas Gilbert static int resp_start_stop(struct scsi_cmnd * scp, 1497c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1498c65b1445SDouglas Gilbert { 149901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1500c4837394SDouglas Gilbert int power_cond, stop; 1501c65b1445SDouglas Gilbert 1502c65b1445SDouglas Gilbert power_cond = (cmd[4] & 0xf0) >> 4; 1503c65b1445SDouglas Gilbert if (power_cond) { 150422017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7); 1505c65b1445SDouglas Gilbert return check_condition_result; 1506c65b1445SDouglas Gilbert } 1507c4837394SDouglas Gilbert stop = !(cmd[4] & 1); 1508c4837394SDouglas Gilbert atomic_xchg(&devip->stopped, stop); 1509c65b1445SDouglas Gilbert return 0; 1510c65b1445SDouglas Gilbert } 1511c65b1445SDouglas Gilbert 151228898873SFUJITA Tomonori static sector_t get_sdebug_capacity(void) 151328898873SFUJITA Tomonori { 1514773642d9SDouglas Gilbert static const unsigned int gibibyte = 1073741824; 1515773642d9SDouglas Gilbert 1516773642d9SDouglas Gilbert if (sdebug_virtual_gb > 0) 1517773642d9SDouglas Gilbert return (sector_t)sdebug_virtual_gb * 1518773642d9SDouglas Gilbert (gibibyte / sdebug_sector_size); 151928898873SFUJITA Tomonori else 152028898873SFUJITA Tomonori return sdebug_store_sectors; 152128898873SFUJITA Tomonori } 152228898873SFUJITA Tomonori 15231da177e4SLinus Torvalds #define SDEBUG_READCAP_ARR_SZ 8 15241da177e4SLinus Torvalds static int resp_readcap(struct scsi_cmnd * scp, 15251da177e4SLinus Torvalds struct sdebug_dev_info * devip) 15261da177e4SLinus Torvalds { 15271da177e4SLinus Torvalds unsigned char arr[SDEBUG_READCAP_ARR_SZ]; 1528c65b1445SDouglas Gilbert unsigned int capac; 15291da177e4SLinus Torvalds 1530c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 153128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 15321da177e4SLinus Torvalds memset(arr, 0, SDEBUG_READCAP_ARR_SZ); 1533c65b1445SDouglas Gilbert if (sdebug_capacity < 0xffffffff) { 1534c65b1445SDouglas Gilbert capac = (unsigned int)sdebug_capacity - 1; 1535773642d9SDouglas Gilbert put_unaligned_be32(capac, arr + 0); 1536773642d9SDouglas Gilbert } else 1537773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, arr + 0); 1538773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, arr + 6); 15391da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ); 15401da177e4SLinus Torvalds } 15411da177e4SLinus Torvalds 1542c65b1445SDouglas Gilbert #define SDEBUG_READCAP16_ARR_SZ 32 1543c65b1445SDouglas Gilbert static int resp_readcap16(struct scsi_cmnd * scp, 1544c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 1545c65b1445SDouglas Gilbert { 154601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 1547c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_READCAP16_ARR_SZ]; 1548773642d9SDouglas Gilbert int alloc_len; 1549c65b1445SDouglas Gilbert 1550773642d9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 1551c65b1445SDouglas Gilbert /* following just in case virtual_gb changed */ 155228898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 1553c65b1445SDouglas Gilbert memset(arr, 0, SDEBUG_READCAP16_ARR_SZ); 1554773642d9SDouglas Gilbert put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0); 1555773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, arr + 8); 1556773642d9SDouglas Gilbert arr[13] = sdebug_physblk_exp & 0xf; 1557773642d9SDouglas Gilbert arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f; 155844d92694SMartin K. Petersen 1559be1dd78dSEric Sandeen if (scsi_debug_lbp()) { 15605b94e232SMartin K. Petersen arr[14] |= 0x80; /* LBPME */ 1561760f3b03SDouglas Gilbert /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in 1562760f3b03SDouglas Gilbert * the LB Provisioning VPD page is 3 bits. Note that lbprz=2 1563760f3b03SDouglas Gilbert * in the wider field maps to 0 in this field. 1564760f3b03SDouglas Gilbert */ 1565760f3b03SDouglas Gilbert if (sdebug_lbprz & 1) /* precisely what the draft requires */ 1566760f3b03SDouglas Gilbert arr[14] |= 0x40; 1567be1dd78dSEric Sandeen } 156844d92694SMartin K. Petersen 1569773642d9SDouglas Gilbert arr[15] = sdebug_lowest_aligned & 0xff; 1570c6a44287SMartin K. Petersen 1571760f3b03SDouglas Gilbert if (have_dif_prot) { 1572773642d9SDouglas Gilbert arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */ 1573c6a44287SMartin K. Petersen arr[12] |= 1; /* PROT_EN */ 1574c6a44287SMartin K. Petersen } 1575c6a44287SMartin K. Petersen 1576c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 1577c65b1445SDouglas Gilbert min(alloc_len, SDEBUG_READCAP16_ARR_SZ)); 1578c65b1445SDouglas Gilbert } 1579c65b1445SDouglas Gilbert 15805a09e398SHannes Reinecke #define SDEBUG_MAX_TGTPGS_ARR_SZ 1412 15815a09e398SHannes Reinecke 15825a09e398SHannes Reinecke static int resp_report_tgtpgs(struct scsi_cmnd * scp, 15835a09e398SHannes Reinecke struct sdebug_dev_info * devip) 15845a09e398SHannes Reinecke { 158501123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 15865a09e398SHannes Reinecke unsigned char * arr; 15875a09e398SHannes Reinecke int host_no = devip->sdbg_host->shost->host_no; 15885a09e398SHannes Reinecke int n, ret, alen, rlen; 15895a09e398SHannes Reinecke int port_group_a, port_group_b, port_a, port_b; 15905a09e398SHannes Reinecke 1591773642d9SDouglas Gilbert alen = get_unaligned_be32(cmd + 6); 15926f3cbf55SDouglas Gilbert arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC); 15936f3cbf55SDouglas Gilbert if (! arr) 15946f3cbf55SDouglas Gilbert return DID_REQUEUE << 16; 15955a09e398SHannes Reinecke /* 15965a09e398SHannes Reinecke * EVPD page 0x88 states we have two ports, one 15975a09e398SHannes Reinecke * real and a fake port with no device connected. 15985a09e398SHannes Reinecke * So we create two port groups with one port each 15995a09e398SHannes Reinecke * and set the group with port B to unavailable. 16005a09e398SHannes Reinecke */ 16015a09e398SHannes Reinecke port_a = 0x1; /* relative port A */ 16025a09e398SHannes Reinecke port_b = 0x2; /* relative port B */ 16035a09e398SHannes Reinecke port_group_a = (((host_no + 1) & 0x7f) << 8) + 16045a09e398SHannes Reinecke (devip->channel & 0x7f); 16055a09e398SHannes Reinecke port_group_b = (((host_no + 1) & 0x7f) << 8) + 16065a09e398SHannes Reinecke (devip->channel & 0x7f) + 0x80; 16075a09e398SHannes Reinecke 16085a09e398SHannes Reinecke /* 16095a09e398SHannes Reinecke * The asymmetric access state is cycled according to the host_id. 16105a09e398SHannes Reinecke */ 16115a09e398SHannes Reinecke n = 4; 1612b01f6f83SDouglas Gilbert if (sdebug_vpd_use_hostno == 0) { 16135a09e398SHannes Reinecke arr[n++] = host_no % 3; /* Asymm access state */ 16145a09e398SHannes Reinecke arr[n++] = 0x0F; /* claim: all states are supported */ 16155a09e398SHannes Reinecke } else { 16165a09e398SHannes Reinecke arr[n++] = 0x0; /* Active/Optimized path */ 1617773642d9SDouglas Gilbert arr[n++] = 0x01; /* only support active/optimized paths */ 16185a09e398SHannes Reinecke } 1619773642d9SDouglas Gilbert put_unaligned_be16(port_group_a, arr + n); 1620773642d9SDouglas Gilbert n += 2; 16215a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16225a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16235a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16245a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16255a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16265a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1627773642d9SDouglas Gilbert put_unaligned_be16(port_a, arr + n); 1628773642d9SDouglas Gilbert n += 2; 16295a09e398SHannes Reinecke arr[n++] = 3; /* Port unavailable */ 16305a09e398SHannes Reinecke arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */ 1631773642d9SDouglas Gilbert put_unaligned_be16(port_group_b, arr + n); 1632773642d9SDouglas Gilbert n += 2; 16335a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16345a09e398SHannes Reinecke arr[n++] = 0; /* Status code */ 16355a09e398SHannes Reinecke arr[n++] = 0; /* Vendor unique */ 16365a09e398SHannes Reinecke arr[n++] = 0x1; /* One port per group */ 16375a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 16385a09e398SHannes Reinecke arr[n++] = 0; /* Reserved */ 1639773642d9SDouglas Gilbert put_unaligned_be16(port_b, arr + n); 1640773642d9SDouglas Gilbert n += 2; 16415a09e398SHannes Reinecke 16425a09e398SHannes Reinecke rlen = n - 4; 1643773642d9SDouglas Gilbert put_unaligned_be32(rlen, arr + 0); 16445a09e398SHannes Reinecke 16455a09e398SHannes Reinecke /* 16465a09e398SHannes Reinecke * Return the smallest value of either 16475a09e398SHannes Reinecke * - The allocated length 16485a09e398SHannes Reinecke * - The constructed command length 16495a09e398SHannes Reinecke * - The maximum array size 16505a09e398SHannes Reinecke */ 16515a09e398SHannes Reinecke rlen = min(alen,n); 16525a09e398SHannes Reinecke ret = fill_from_dev_buffer(scp, arr, 16535a09e398SHannes Reinecke min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ)); 16545a09e398SHannes Reinecke kfree(arr); 16555a09e398SHannes Reinecke return ret; 16565a09e398SHannes Reinecke } 16575a09e398SHannes Reinecke 1658fd32119bSDouglas Gilbert static int resp_rsup_opcodes(struct scsi_cmnd *scp, 1659fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 166038d5c833SDouglas Gilbert { 166138d5c833SDouglas Gilbert bool rctd; 166238d5c833SDouglas Gilbert u8 reporting_opts, req_opcode, sdeb_i, supp; 166338d5c833SDouglas Gilbert u16 req_sa, u; 166438d5c833SDouglas Gilbert u32 alloc_len, a_len; 166538d5c833SDouglas Gilbert int k, offset, len, errsts, count, bump, na; 166638d5c833SDouglas Gilbert const struct opcode_info_t *oip; 166738d5c833SDouglas Gilbert const struct opcode_info_t *r_oip; 166838d5c833SDouglas Gilbert u8 *arr; 166938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 167038d5c833SDouglas Gilbert 167138d5c833SDouglas Gilbert rctd = !!(cmd[2] & 0x80); 167238d5c833SDouglas Gilbert reporting_opts = cmd[2] & 0x7; 167338d5c833SDouglas Gilbert req_opcode = cmd[3]; 167438d5c833SDouglas Gilbert req_sa = get_unaligned_be16(cmd + 4); 167538d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 16766d310dfbSColin Ian King if (alloc_len < 4 || alloc_len > 0xffff) { 167738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 167838d5c833SDouglas Gilbert return check_condition_result; 167938d5c833SDouglas Gilbert } 168038d5c833SDouglas Gilbert if (alloc_len > 8192) 168138d5c833SDouglas Gilbert a_len = 8192; 168238d5c833SDouglas Gilbert else 168338d5c833SDouglas Gilbert a_len = alloc_len; 168499531e60SSasha Levin arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC); 168538d5c833SDouglas Gilbert if (NULL == arr) { 168638d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 168738d5c833SDouglas Gilbert INSUFF_RES_ASCQ); 168838d5c833SDouglas Gilbert return check_condition_result; 168938d5c833SDouglas Gilbert } 169038d5c833SDouglas Gilbert switch (reporting_opts) { 169138d5c833SDouglas Gilbert case 0: /* all commands */ 169238d5c833SDouglas Gilbert /* count number of commands */ 169338d5c833SDouglas Gilbert for (count = 0, oip = opcode_info_arr; 169438d5c833SDouglas Gilbert oip->num_attached != 0xff; ++oip) { 169538d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 169638d5c833SDouglas Gilbert continue; 169738d5c833SDouglas Gilbert count += (oip->num_attached + 1); 169838d5c833SDouglas Gilbert } 169938d5c833SDouglas Gilbert bump = rctd ? 20 : 8; 170038d5c833SDouglas Gilbert put_unaligned_be32(count * bump, arr); 170138d5c833SDouglas Gilbert for (offset = 4, oip = opcode_info_arr; 170238d5c833SDouglas Gilbert oip->num_attached != 0xff && offset < a_len; ++oip) { 170338d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 170438d5c833SDouglas Gilbert continue; 170538d5c833SDouglas Gilbert na = oip->num_attached; 170638d5c833SDouglas Gilbert arr[offset] = oip->opcode; 170738d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 170838d5c833SDouglas Gilbert if (rctd) 170938d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 171038d5c833SDouglas Gilbert if (FF_SA & oip->flags) 171138d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 171238d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], arr + offset + 6); 171338d5c833SDouglas Gilbert if (rctd) 171438d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset + 8); 171538d5c833SDouglas Gilbert r_oip = oip; 171638d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) { 171738d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) 171838d5c833SDouglas Gilbert continue; 171938d5c833SDouglas Gilbert offset += bump; 172038d5c833SDouglas Gilbert arr[offset] = oip->opcode; 172138d5c833SDouglas Gilbert put_unaligned_be16(oip->sa, arr + offset + 2); 172238d5c833SDouglas Gilbert if (rctd) 172338d5c833SDouglas Gilbert arr[offset + 5] |= 0x2; 172438d5c833SDouglas Gilbert if (FF_SA & oip->flags) 172538d5c833SDouglas Gilbert arr[offset + 5] |= 0x1; 172638d5c833SDouglas Gilbert put_unaligned_be16(oip->len_mask[0], 172738d5c833SDouglas Gilbert arr + offset + 6); 172838d5c833SDouglas Gilbert if (rctd) 172938d5c833SDouglas Gilbert put_unaligned_be16(0xa, 173038d5c833SDouglas Gilbert arr + offset + 8); 173138d5c833SDouglas Gilbert } 173238d5c833SDouglas Gilbert oip = r_oip; 173338d5c833SDouglas Gilbert offset += bump; 173438d5c833SDouglas Gilbert } 173538d5c833SDouglas Gilbert break; 173638d5c833SDouglas Gilbert case 1: /* one command: opcode only */ 173738d5c833SDouglas Gilbert case 2: /* one command: opcode plus service action */ 173838d5c833SDouglas Gilbert case 3: /* one command: if sa==0 then opcode only else opcode+sa */ 173938d5c833SDouglas Gilbert sdeb_i = opcode_ind_arr[req_opcode]; 174038d5c833SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; 174138d5c833SDouglas Gilbert if (F_INV_OP & oip->flags) { 174238d5c833SDouglas Gilbert supp = 1; 174338d5c833SDouglas Gilbert offset = 4; 174438d5c833SDouglas Gilbert } else { 174538d5c833SDouglas Gilbert if (1 == reporting_opts) { 174638d5c833SDouglas Gilbert if (FF_SA & oip->flags) { 174738d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 174838d5c833SDouglas Gilbert 2, 2); 174938d5c833SDouglas Gilbert kfree(arr); 175038d5c833SDouglas Gilbert return check_condition_result; 175138d5c833SDouglas Gilbert } 175238d5c833SDouglas Gilbert req_sa = 0; 175338d5c833SDouglas Gilbert } else if (2 == reporting_opts && 175438d5c833SDouglas Gilbert 0 == (FF_SA & oip->flags)) { 175538d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1); 175638d5c833SDouglas Gilbert kfree(arr); /* point at requested sa */ 175738d5c833SDouglas Gilbert return check_condition_result; 175838d5c833SDouglas Gilbert } 175938d5c833SDouglas Gilbert if (0 == (FF_SA & oip->flags) && 176038d5c833SDouglas Gilbert req_opcode == oip->opcode) 176138d5c833SDouglas Gilbert supp = 3; 176238d5c833SDouglas Gilbert else if (0 == (FF_SA & oip->flags)) { 176338d5c833SDouglas Gilbert na = oip->num_attached; 176438d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 176538d5c833SDouglas Gilbert ++k, ++oip) { 176638d5c833SDouglas Gilbert if (req_opcode == oip->opcode) 176738d5c833SDouglas Gilbert break; 176838d5c833SDouglas Gilbert } 176938d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 177038d5c833SDouglas Gilbert } else if (req_sa != oip->sa) { 177138d5c833SDouglas Gilbert na = oip->num_attached; 177238d5c833SDouglas Gilbert for (k = 0, oip = oip->arrp; k < na; 177338d5c833SDouglas Gilbert ++k, ++oip) { 177438d5c833SDouglas Gilbert if (req_sa == oip->sa) 177538d5c833SDouglas Gilbert break; 177638d5c833SDouglas Gilbert } 177738d5c833SDouglas Gilbert supp = (k >= na) ? 1 : 3; 177838d5c833SDouglas Gilbert } else 177938d5c833SDouglas Gilbert supp = 3; 178038d5c833SDouglas Gilbert if (3 == supp) { 178138d5c833SDouglas Gilbert u = oip->len_mask[0]; 178238d5c833SDouglas Gilbert put_unaligned_be16(u, arr + 2); 178338d5c833SDouglas Gilbert arr[4] = oip->opcode; 178438d5c833SDouglas Gilbert for (k = 1; k < u; ++k) 178538d5c833SDouglas Gilbert arr[4 + k] = (k < 16) ? 178638d5c833SDouglas Gilbert oip->len_mask[k] : 0xff; 178738d5c833SDouglas Gilbert offset = 4 + u; 178838d5c833SDouglas Gilbert } else 178938d5c833SDouglas Gilbert offset = 4; 179038d5c833SDouglas Gilbert } 179138d5c833SDouglas Gilbert arr[1] = (rctd ? 0x80 : 0) | supp; 179238d5c833SDouglas Gilbert if (rctd) { 179338d5c833SDouglas Gilbert put_unaligned_be16(0xa, arr + offset); 179438d5c833SDouglas Gilbert offset += 12; 179538d5c833SDouglas Gilbert } 179638d5c833SDouglas Gilbert break; 179738d5c833SDouglas Gilbert default: 179838d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2); 179938d5c833SDouglas Gilbert kfree(arr); 180038d5c833SDouglas Gilbert return check_condition_result; 180138d5c833SDouglas Gilbert } 180238d5c833SDouglas Gilbert offset = (offset < a_len) ? offset : a_len; 180338d5c833SDouglas Gilbert len = (offset < alloc_len) ? offset : alloc_len; 180438d5c833SDouglas Gilbert errsts = fill_from_dev_buffer(scp, arr, len); 180538d5c833SDouglas Gilbert kfree(arr); 180638d5c833SDouglas Gilbert return errsts; 180738d5c833SDouglas Gilbert } 180838d5c833SDouglas Gilbert 1809fd32119bSDouglas Gilbert static int resp_rsup_tmfs(struct scsi_cmnd *scp, 1810fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 181138d5c833SDouglas Gilbert { 181238d5c833SDouglas Gilbert bool repd; 181338d5c833SDouglas Gilbert u32 alloc_len, len; 181438d5c833SDouglas Gilbert u8 arr[16]; 181538d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 181638d5c833SDouglas Gilbert 181738d5c833SDouglas Gilbert memset(arr, 0, sizeof(arr)); 181838d5c833SDouglas Gilbert repd = !!(cmd[2] & 0x80); 181938d5c833SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 182038d5c833SDouglas Gilbert if (alloc_len < 4) { 182138d5c833SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 182238d5c833SDouglas Gilbert return check_condition_result; 182338d5c833SDouglas Gilbert } 182438d5c833SDouglas Gilbert arr[0] = 0xc8; /* ATS | ATSS | LURS */ 182538d5c833SDouglas Gilbert arr[1] = 0x1; /* ITNRS */ 182638d5c833SDouglas Gilbert if (repd) { 182738d5c833SDouglas Gilbert arr[3] = 0xc; 182838d5c833SDouglas Gilbert len = 16; 182938d5c833SDouglas Gilbert } else 183038d5c833SDouglas Gilbert len = 4; 183138d5c833SDouglas Gilbert 183238d5c833SDouglas Gilbert len = (len < alloc_len) ? len : alloc_len; 183338d5c833SDouglas Gilbert return fill_from_dev_buffer(scp, arr, len); 183438d5c833SDouglas Gilbert } 183538d5c833SDouglas Gilbert 18361da177e4SLinus Torvalds /* <<Following mode page info copied from ST318451LW>> */ 18371da177e4SLinus Torvalds 18381da177e4SLinus Torvalds static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target) 18391da177e4SLinus Torvalds { /* Read-Write Error Recovery page for mode_sense */ 18401da177e4SLinus Torvalds unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0, 18411da177e4SLinus Torvalds 5, 0, 0xff, 0xff}; 18421da177e4SLinus Torvalds 18431da177e4SLinus Torvalds memcpy(p, err_recov_pg, sizeof(err_recov_pg)); 18441da177e4SLinus Torvalds if (1 == pcontrol) 18451da177e4SLinus Torvalds memset(p + 2, 0, sizeof(err_recov_pg) - 2); 18461da177e4SLinus Torvalds return sizeof(err_recov_pg); 18471da177e4SLinus Torvalds } 18481da177e4SLinus Torvalds 18491da177e4SLinus Torvalds static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target) 18501da177e4SLinus Torvalds { /* Disconnect-Reconnect page for mode_sense */ 18511da177e4SLinus Torvalds unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0, 18521da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0}; 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds memcpy(p, disconnect_pg, sizeof(disconnect_pg)); 18551da177e4SLinus Torvalds if (1 == pcontrol) 18561da177e4SLinus Torvalds memset(p + 2, 0, sizeof(disconnect_pg) - 2); 18571da177e4SLinus Torvalds return sizeof(disconnect_pg); 18581da177e4SLinus Torvalds } 18591da177e4SLinus Torvalds 18601da177e4SLinus Torvalds static int resp_format_pg(unsigned char * p, int pcontrol, int target) 18611da177e4SLinus Torvalds { /* Format device page for mode_sense */ 18621da177e4SLinus Torvalds unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0, 18631da177e4SLinus Torvalds 0, 0, 0, 0, 0, 0, 0, 0, 18641da177e4SLinus Torvalds 0, 0, 0, 0, 0x40, 0, 0, 0}; 18651da177e4SLinus Torvalds 18661da177e4SLinus Torvalds memcpy(p, format_pg, sizeof(format_pg)); 1867773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sectors_per, p + 10); 1868773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, p + 12); 1869773642d9SDouglas Gilbert if (sdebug_removable) 18701da177e4SLinus Torvalds p[20] |= 0x20; /* should agree with INQUIRY */ 18711da177e4SLinus Torvalds if (1 == pcontrol) 18721da177e4SLinus Torvalds memset(p + 2, 0, sizeof(format_pg) - 2); 18731da177e4SLinus Torvalds return sizeof(format_pg); 18741da177e4SLinus Torvalds } 18751da177e4SLinus Torvalds 1876fd32119bSDouglas Gilbert static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 1877fd32119bSDouglas Gilbert 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 1878fd32119bSDouglas Gilbert 0, 0, 0, 0}; 1879fd32119bSDouglas Gilbert 18801da177e4SLinus Torvalds static int resp_caching_pg(unsigned char * p, int pcontrol, int target) 18811da177e4SLinus Torvalds { /* Caching page for mode_sense */ 1882cbf67842SDouglas Gilbert unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0, 1883cbf67842SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 1884cbf67842SDouglas Gilbert unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0, 18851da177e4SLinus Torvalds 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0}; 18861da177e4SLinus Torvalds 1887773642d9SDouglas Gilbert if (SDEBUG_OPT_N_WCE & sdebug_opts) 1888cbf67842SDouglas Gilbert caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */ 18891da177e4SLinus Torvalds memcpy(p, caching_pg, sizeof(caching_pg)); 18901da177e4SLinus Torvalds if (1 == pcontrol) 1891cbf67842SDouglas Gilbert memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg)); 1892cbf67842SDouglas Gilbert else if (2 == pcontrol) 1893cbf67842SDouglas Gilbert memcpy(p, d_caching_pg, sizeof(d_caching_pg)); 18941da177e4SLinus Torvalds return sizeof(caching_pg); 18951da177e4SLinus Torvalds } 18961da177e4SLinus Torvalds 1897fd32119bSDouglas Gilbert static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 1898fd32119bSDouglas Gilbert 0, 0, 0x2, 0x4b}; 1899fd32119bSDouglas Gilbert 19001da177e4SLinus Torvalds static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target) 19011da177e4SLinus Torvalds { /* Control mode page for mode_sense */ 1902c65b1445SDouglas Gilbert unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0, 1903c65b1445SDouglas Gilbert 0, 0, 0, 0}; 1904c65b1445SDouglas Gilbert unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0, 19051da177e4SLinus Torvalds 0, 0, 0x2, 0x4b}; 19061da177e4SLinus Torvalds 1907773642d9SDouglas Gilbert if (sdebug_dsense) 19081da177e4SLinus Torvalds ctrl_m_pg[2] |= 0x4; 1909c65b1445SDouglas Gilbert else 1910c65b1445SDouglas Gilbert ctrl_m_pg[2] &= ~0x4; 1911c6a44287SMartin K. Petersen 1912773642d9SDouglas Gilbert if (sdebug_ato) 1913c6a44287SMartin K. Petersen ctrl_m_pg[5] |= 0x80; /* ATO=1 */ 1914c6a44287SMartin K. Petersen 19151da177e4SLinus Torvalds memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg)); 19161da177e4SLinus Torvalds if (1 == pcontrol) 1917c65b1445SDouglas Gilbert memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg)); 1918c65b1445SDouglas Gilbert else if (2 == pcontrol) 1919c65b1445SDouglas Gilbert memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg)); 19201da177e4SLinus Torvalds return sizeof(ctrl_m_pg); 19211da177e4SLinus Torvalds } 19221da177e4SLinus Torvalds 1923c65b1445SDouglas Gilbert 19241da177e4SLinus Torvalds static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target) 19251da177e4SLinus Torvalds { /* Informational Exceptions control mode page for mode_sense */ 1926c65b1445SDouglas Gilbert unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0, 19271da177e4SLinus Torvalds 0, 0, 0x0, 0x0}; 1928c65b1445SDouglas Gilbert unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0, 1929c65b1445SDouglas Gilbert 0, 0, 0x0, 0x0}; 1930c65b1445SDouglas Gilbert 19311da177e4SLinus Torvalds memcpy(p, iec_m_pg, sizeof(iec_m_pg)); 19321da177e4SLinus Torvalds if (1 == pcontrol) 1933c65b1445SDouglas Gilbert memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg)); 1934c65b1445SDouglas Gilbert else if (2 == pcontrol) 1935c65b1445SDouglas Gilbert memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg)); 19361da177e4SLinus Torvalds return sizeof(iec_m_pg); 19371da177e4SLinus Torvalds } 19381da177e4SLinus Torvalds 1939c65b1445SDouglas Gilbert static int resp_sas_sf_m_pg(unsigned char * p, int pcontrol, int target) 1940c65b1445SDouglas Gilbert { /* SAS SSP mode page - short format for mode_sense */ 1941c65b1445SDouglas Gilbert unsigned char sas_sf_m_pg[] = {0x19, 0x6, 1942c65b1445SDouglas Gilbert 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0}; 1943c65b1445SDouglas Gilbert 1944c65b1445SDouglas Gilbert memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg)); 1945c65b1445SDouglas Gilbert if (1 == pcontrol) 1946c65b1445SDouglas Gilbert memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2); 1947c65b1445SDouglas Gilbert return sizeof(sas_sf_m_pg); 1948c65b1445SDouglas Gilbert } 1949c65b1445SDouglas Gilbert 1950c65b1445SDouglas Gilbert 1951c65b1445SDouglas Gilbert static int resp_sas_pcd_m_spg(unsigned char * p, int pcontrol, int target, 1952c65b1445SDouglas Gilbert int target_dev_id) 1953c65b1445SDouglas Gilbert { /* SAS phy control and discover mode page for mode_sense */ 1954c65b1445SDouglas Gilbert unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2, 1955c65b1445SDouglas Gilbert 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0, 1956773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1957773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1958c65b1445SDouglas Gilbert 0x2, 0, 0, 0, 0, 0, 0, 0, 1959c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1960c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1961c65b1445SDouglas Gilbert 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0, 1962773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1963773642d9SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */ 1964c65b1445SDouglas Gilbert 0x3, 0, 0, 0, 0, 0, 0, 0, 1965c65b1445SDouglas Gilbert 0x88, 0x99, 0, 0, 0, 0, 0, 0, 1966c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1967c65b1445SDouglas Gilbert }; 1968c65b1445SDouglas Gilbert int port_a, port_b; 1969c65b1445SDouglas Gilbert 19701b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16); 19711b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24); 19721b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64); 19731b37bd60SDouglas Gilbert put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72); 1974c65b1445SDouglas Gilbert port_a = target_dev_id + 1; 1975c65b1445SDouglas Gilbert port_b = port_a + 1; 1976c65b1445SDouglas Gilbert memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg)); 1977773642d9SDouglas Gilbert put_unaligned_be32(port_a, p + 20); 1978773642d9SDouglas Gilbert put_unaligned_be32(port_b, p + 48 + 20); 1979c65b1445SDouglas Gilbert if (1 == pcontrol) 1980c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4); 1981c65b1445SDouglas Gilbert return sizeof(sas_pcd_m_pg); 1982c65b1445SDouglas Gilbert } 1983c65b1445SDouglas Gilbert 1984c65b1445SDouglas Gilbert static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol) 1985c65b1445SDouglas Gilbert { /* SAS SSP shared protocol specific port mode subpage */ 1986c65b1445SDouglas Gilbert unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0, 1987c65b1445SDouglas Gilbert 0, 0, 0, 0, 0, 0, 0, 0, 1988c65b1445SDouglas Gilbert }; 1989c65b1445SDouglas Gilbert 1990c65b1445SDouglas Gilbert memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg)); 1991c65b1445SDouglas Gilbert if (1 == pcontrol) 1992c65b1445SDouglas Gilbert memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4); 1993c65b1445SDouglas Gilbert return sizeof(sas_sha_m_pg); 1994c65b1445SDouglas Gilbert } 1995c65b1445SDouglas Gilbert 19961da177e4SLinus Torvalds #define SDEBUG_MAX_MSENSE_SZ 256 19971da177e4SLinus Torvalds 1998fd32119bSDouglas Gilbert static int resp_mode_sense(struct scsi_cmnd *scp, 1999fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 20001da177e4SLinus Torvalds { 200123183910SDouglas Gilbert int pcontrol, pcode, subpcode, bd_len; 20021da177e4SLinus Torvalds unsigned char dev_spec; 2003760f3b03SDouglas Gilbert int alloc_len, offset, len, target_dev_id; 2004c2248fc9SDouglas Gilbert int target = scp->device->id; 20051da177e4SLinus Torvalds unsigned char * ap; 20061da177e4SLinus Torvalds unsigned char arr[SDEBUG_MAX_MSENSE_SZ]; 200701123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2008760f3b03SDouglas Gilbert bool dbd, llbaa, msense_6, is_disk, bad_pcode; 20091da177e4SLinus Torvalds 2010760f3b03SDouglas Gilbert dbd = !!(cmd[1] & 0x8); /* disable block descriptors */ 20111da177e4SLinus Torvalds pcontrol = (cmd[2] & 0xc0) >> 6; 20121da177e4SLinus Torvalds pcode = cmd[2] & 0x3f; 20131da177e4SLinus Torvalds subpcode = cmd[3]; 20141da177e4SLinus Torvalds msense_6 = (MODE_SENSE == cmd[0]); 2015760f3b03SDouglas Gilbert llbaa = msense_6 ? false : !!(cmd[1] & 0x10); 2016760f3b03SDouglas Gilbert is_disk = (sdebug_ptype == TYPE_DISK); 2017760f3b03SDouglas Gilbert if (is_disk && !dbd) 201823183910SDouglas Gilbert bd_len = llbaa ? 16 : 8; 201923183910SDouglas Gilbert else 202023183910SDouglas Gilbert bd_len = 0; 2021773642d9SDouglas Gilbert alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7); 20221da177e4SLinus Torvalds memset(arr, 0, SDEBUG_MAX_MSENSE_SZ); 20231da177e4SLinus Torvalds if (0x3 == pcontrol) { /* Saving values not supported */ 2024cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0); 20251da177e4SLinus Torvalds return check_condition_result; 20261da177e4SLinus Torvalds } 2027c65b1445SDouglas Gilbert target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) + 2028c65b1445SDouglas Gilbert (devip->target * 1000) - 3; 2029b01f6f83SDouglas Gilbert /* for disks set DPOFUA bit and clear write protect (WP) bit */ 2030760f3b03SDouglas Gilbert if (is_disk) 2031b01f6f83SDouglas Gilbert dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */ 203223183910SDouglas Gilbert else 203323183910SDouglas Gilbert dev_spec = 0x0; 20341da177e4SLinus Torvalds if (msense_6) { 20351da177e4SLinus Torvalds arr[2] = dev_spec; 203623183910SDouglas Gilbert arr[3] = bd_len; 20371da177e4SLinus Torvalds offset = 4; 20381da177e4SLinus Torvalds } else { 20391da177e4SLinus Torvalds arr[3] = dev_spec; 204023183910SDouglas Gilbert if (16 == bd_len) 204123183910SDouglas Gilbert arr[4] = 0x1; /* set LONGLBA bit */ 204223183910SDouglas Gilbert arr[7] = bd_len; /* assume 255 or less */ 20431da177e4SLinus Torvalds offset = 8; 20441da177e4SLinus Torvalds } 20451da177e4SLinus Torvalds ap = arr + offset; 204628898873SFUJITA Tomonori if ((bd_len > 0) && (!sdebug_capacity)) 204728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 204828898873SFUJITA Tomonori 204923183910SDouglas Gilbert if (8 == bd_len) { 2050773642d9SDouglas Gilbert if (sdebug_capacity > 0xfffffffe) 2051773642d9SDouglas Gilbert put_unaligned_be32(0xffffffff, ap + 0); 2052773642d9SDouglas Gilbert else 2053773642d9SDouglas Gilbert put_unaligned_be32(sdebug_capacity, ap + 0); 2054773642d9SDouglas Gilbert put_unaligned_be16(sdebug_sector_size, ap + 6); 205523183910SDouglas Gilbert offset += bd_len; 205623183910SDouglas Gilbert ap = arr + offset; 205723183910SDouglas Gilbert } else if (16 == bd_len) { 2058773642d9SDouglas Gilbert put_unaligned_be64((u64)sdebug_capacity, ap + 0); 2059773642d9SDouglas Gilbert put_unaligned_be32(sdebug_sector_size, ap + 12); 206023183910SDouglas Gilbert offset += bd_len; 206123183910SDouglas Gilbert ap = arr + offset; 206223183910SDouglas Gilbert } 20631da177e4SLinus Torvalds 2064c65b1445SDouglas Gilbert if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) { 2065c65b1445SDouglas Gilbert /* TODO: Control Extension page */ 206622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 20671da177e4SLinus Torvalds return check_condition_result; 20681da177e4SLinus Torvalds } 2069760f3b03SDouglas Gilbert bad_pcode = false; 2070760f3b03SDouglas Gilbert 20711da177e4SLinus Torvalds switch (pcode) { 20721da177e4SLinus Torvalds case 0x1: /* Read-Write error recovery page, direct access */ 20731da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 20741da177e4SLinus Torvalds offset += len; 20751da177e4SLinus Torvalds break; 20761da177e4SLinus Torvalds case 0x2: /* Disconnect-Reconnect page, all devices */ 20771da177e4SLinus Torvalds len = resp_disconnect_pg(ap, pcontrol, target); 20781da177e4SLinus Torvalds offset += len; 20791da177e4SLinus Torvalds break; 20801da177e4SLinus Torvalds case 0x3: /* Format device page, direct access */ 2081760f3b03SDouglas Gilbert if (is_disk) { 20821da177e4SLinus Torvalds len = resp_format_pg(ap, pcontrol, target); 20831da177e4SLinus Torvalds offset += len; 2084760f3b03SDouglas Gilbert } else 2085760f3b03SDouglas Gilbert bad_pcode = true; 20861da177e4SLinus Torvalds break; 20871da177e4SLinus Torvalds case 0x8: /* Caching page, direct access */ 2088760f3b03SDouglas Gilbert if (is_disk) { 20891da177e4SLinus Torvalds len = resp_caching_pg(ap, pcontrol, target); 20901da177e4SLinus Torvalds offset += len; 2091760f3b03SDouglas Gilbert } else 2092760f3b03SDouglas Gilbert bad_pcode = true; 20931da177e4SLinus Torvalds break; 20941da177e4SLinus Torvalds case 0xa: /* Control Mode page, all devices */ 20951da177e4SLinus Torvalds len = resp_ctrl_m_pg(ap, pcontrol, target); 20961da177e4SLinus Torvalds offset += len; 20971da177e4SLinus Torvalds break; 2098c65b1445SDouglas Gilbert case 0x19: /* if spc==1 then sas phy, control+discover */ 2099c65b1445SDouglas Gilbert if ((subpcode > 0x2) && (subpcode < 0xff)) { 210022017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2101c65b1445SDouglas Gilbert return check_condition_result; 2102c65b1445SDouglas Gilbert } 2103c65b1445SDouglas Gilbert len = 0; 2104c65b1445SDouglas Gilbert if ((0x0 == subpcode) || (0xff == subpcode)) 2105c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2106c65b1445SDouglas Gilbert if ((0x1 == subpcode) || (0xff == subpcode)) 2107c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, target, 2108c65b1445SDouglas Gilbert target_dev_id); 2109c65b1445SDouglas Gilbert if ((0x2 == subpcode) || (0xff == subpcode)) 2110c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2111c65b1445SDouglas Gilbert offset += len; 2112c65b1445SDouglas Gilbert break; 21131da177e4SLinus Torvalds case 0x1c: /* Informational Exceptions Mode page, all devices */ 21141da177e4SLinus Torvalds len = resp_iec_m_pg(ap, pcontrol, target); 21151da177e4SLinus Torvalds offset += len; 21161da177e4SLinus Torvalds break; 21171da177e4SLinus Torvalds case 0x3f: /* Read all Mode pages */ 2118c65b1445SDouglas Gilbert if ((0 == subpcode) || (0xff == subpcode)) { 21191da177e4SLinus Torvalds len = resp_err_recov_pg(ap, pcontrol, target); 21201da177e4SLinus Torvalds len += resp_disconnect_pg(ap + len, pcontrol, target); 2121760f3b03SDouglas Gilbert if (is_disk) { 2122760f3b03SDouglas Gilbert len += resp_format_pg(ap + len, pcontrol, 2123760f3b03SDouglas Gilbert target); 2124760f3b03SDouglas Gilbert len += resp_caching_pg(ap + len, pcontrol, 2125760f3b03SDouglas Gilbert target); 2126760f3b03SDouglas Gilbert } 21271da177e4SLinus Torvalds len += resp_ctrl_m_pg(ap + len, pcontrol, target); 2128c65b1445SDouglas Gilbert len += resp_sas_sf_m_pg(ap + len, pcontrol, target); 2129c65b1445SDouglas Gilbert if (0xff == subpcode) { 2130c65b1445SDouglas Gilbert len += resp_sas_pcd_m_spg(ap + len, pcontrol, 2131c65b1445SDouglas Gilbert target, target_dev_id); 2132c65b1445SDouglas Gilbert len += resp_sas_sha_m_spg(ap + len, pcontrol); 2133c65b1445SDouglas Gilbert } 21341da177e4SLinus Torvalds len += resp_iec_m_pg(ap + len, pcontrol, target); 2135760f3b03SDouglas Gilbert offset += len; 2136c65b1445SDouglas Gilbert } else { 213722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 2138c65b1445SDouglas Gilbert return check_condition_result; 2139c65b1445SDouglas Gilbert } 21401da177e4SLinus Torvalds break; 21411da177e4SLinus Torvalds default: 2142760f3b03SDouglas Gilbert bad_pcode = true; 2143760f3b03SDouglas Gilbert break; 2144760f3b03SDouglas Gilbert } 2145760f3b03SDouglas Gilbert if (bad_pcode) { 214622017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 21471da177e4SLinus Torvalds return check_condition_result; 21481da177e4SLinus Torvalds } 21491da177e4SLinus Torvalds if (msense_6) 21501da177e4SLinus Torvalds arr[0] = offset - 1; 2151773642d9SDouglas Gilbert else 2152773642d9SDouglas Gilbert put_unaligned_be16((offset - 2), arr + 0); 21531da177e4SLinus Torvalds return fill_from_dev_buffer(scp, arr, min(alloc_len, offset)); 21541da177e4SLinus Torvalds } 21551da177e4SLinus Torvalds 2156c65b1445SDouglas Gilbert #define SDEBUG_MAX_MSELECT_SZ 512 2157c65b1445SDouglas Gilbert 2158fd32119bSDouglas Gilbert static int resp_mode_select(struct scsi_cmnd *scp, 2159fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 2160c65b1445SDouglas Gilbert { 2161c65b1445SDouglas Gilbert int pf, sp, ps, md_len, bd_len, off, spf, pg_len; 2162c2248fc9SDouglas Gilbert int param_len, res, mpage; 2163c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_MSELECT_SZ]; 216401123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2165c2248fc9SDouglas Gilbert int mselect6 = (MODE_SELECT == cmd[0]); 2166c65b1445SDouglas Gilbert 2167c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2168c65b1445SDouglas Gilbert pf = cmd[1] & 0x10; 2169c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2170773642d9SDouglas Gilbert param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7); 2171c65b1445SDouglas Gilbert if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) { 217222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1); 2173c65b1445SDouglas Gilbert return check_condition_result; 2174c65b1445SDouglas Gilbert } 2175c65b1445SDouglas Gilbert res = fetch_to_dev_buffer(scp, arr, param_len); 2176c65b1445SDouglas Gilbert if (-1 == res) 2177773642d9SDouglas Gilbert return DID_ERROR << 16; 2178773642d9SDouglas Gilbert else if (sdebug_verbose && (res < param_len)) 2179cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2180cbf67842SDouglas Gilbert "%s: cdb indicated=%d, IO sent=%d bytes\n", 2181cbf67842SDouglas Gilbert __func__, param_len, res); 2182773642d9SDouglas Gilbert md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2); 2183773642d9SDouglas Gilbert bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6); 218423183910SDouglas Gilbert if (md_len > 2) { 218522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1); 2186c65b1445SDouglas Gilbert return check_condition_result; 2187c65b1445SDouglas Gilbert } 2188c65b1445SDouglas Gilbert off = bd_len + (mselect6 ? 4 : 8); 2189c65b1445SDouglas Gilbert mpage = arr[off] & 0x3f; 2190c65b1445SDouglas Gilbert ps = !!(arr[off] & 0x80); 2191c65b1445SDouglas Gilbert if (ps) { 219222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7); 2193c65b1445SDouglas Gilbert return check_condition_result; 2194c65b1445SDouglas Gilbert } 2195c65b1445SDouglas Gilbert spf = !!(arr[off] & 0x40); 2196773642d9SDouglas Gilbert pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) : 2197c65b1445SDouglas Gilbert (arr[off + 1] + 2); 2198c65b1445SDouglas Gilbert if ((pg_len + off) > param_len) { 2199cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 2200c65b1445SDouglas Gilbert PARAMETER_LIST_LENGTH_ERR, 0); 2201c65b1445SDouglas Gilbert return check_condition_result; 2202c65b1445SDouglas Gilbert } 2203c65b1445SDouglas Gilbert switch (mpage) { 2204cbf67842SDouglas Gilbert case 0x8: /* Caching Mode page */ 2205cbf67842SDouglas Gilbert if (caching_pg[1] == arr[off + 1]) { 2206cbf67842SDouglas Gilbert memcpy(caching_pg + 2, arr + off + 2, 2207cbf67842SDouglas Gilbert sizeof(caching_pg) - 2); 2208cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2209cbf67842SDouglas Gilbert } 2210cbf67842SDouglas Gilbert break; 2211c65b1445SDouglas Gilbert case 0xa: /* Control Mode page */ 2212c65b1445SDouglas Gilbert if (ctrl_m_pg[1] == arr[off + 1]) { 2213c65b1445SDouglas Gilbert memcpy(ctrl_m_pg + 2, arr + off + 2, 2214c65b1445SDouglas Gilbert sizeof(ctrl_m_pg) - 2); 2215773642d9SDouglas Gilbert sdebug_dsense = !!(ctrl_m_pg[2] & 0x4); 2216cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2217c65b1445SDouglas Gilbert } 2218c65b1445SDouglas Gilbert break; 2219c65b1445SDouglas Gilbert case 0x1c: /* Informational Exceptions Mode page */ 2220c65b1445SDouglas Gilbert if (iec_m_pg[1] == arr[off + 1]) { 2221c65b1445SDouglas Gilbert memcpy(iec_m_pg + 2, arr + off + 2, 2222c65b1445SDouglas Gilbert sizeof(iec_m_pg) - 2); 2223cbf67842SDouglas Gilbert goto set_mode_changed_ua; 2224c65b1445SDouglas Gilbert } 2225c65b1445SDouglas Gilbert break; 2226c65b1445SDouglas Gilbert default: 2227c65b1445SDouglas Gilbert break; 2228c65b1445SDouglas Gilbert } 222922017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5); 2230c65b1445SDouglas Gilbert return check_condition_result; 2231cbf67842SDouglas Gilbert set_mode_changed_ua: 2232cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm); 2233cbf67842SDouglas Gilbert return 0; 2234c65b1445SDouglas Gilbert } 2235c65b1445SDouglas Gilbert 2236c65b1445SDouglas Gilbert static int resp_temp_l_pg(unsigned char * arr) 2237c65b1445SDouglas Gilbert { 2238c65b1445SDouglas Gilbert unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38, 2239c65b1445SDouglas Gilbert 0x0, 0x1, 0x3, 0x2, 0x0, 65, 2240c65b1445SDouglas Gilbert }; 2241c65b1445SDouglas Gilbert 2242c65b1445SDouglas Gilbert memcpy(arr, temp_l_pg, sizeof(temp_l_pg)); 2243c65b1445SDouglas Gilbert return sizeof(temp_l_pg); 2244c65b1445SDouglas Gilbert } 2245c65b1445SDouglas Gilbert 2246c65b1445SDouglas Gilbert static int resp_ie_l_pg(unsigned char * arr) 2247c65b1445SDouglas Gilbert { 2248c65b1445SDouglas Gilbert unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38, 2249c65b1445SDouglas Gilbert }; 2250c65b1445SDouglas Gilbert 2251c65b1445SDouglas Gilbert memcpy(arr, ie_l_pg, sizeof(ie_l_pg)); 2252c65b1445SDouglas Gilbert if (iec_m_pg[2] & 0x4) { /* TEST bit set */ 2253c65b1445SDouglas Gilbert arr[4] = THRESHOLD_EXCEEDED; 2254c65b1445SDouglas Gilbert arr[5] = 0xff; 2255c65b1445SDouglas Gilbert } 2256c65b1445SDouglas Gilbert return sizeof(ie_l_pg); 2257c65b1445SDouglas Gilbert } 2258c65b1445SDouglas Gilbert 2259c65b1445SDouglas Gilbert #define SDEBUG_MAX_LSENSE_SZ 512 2260c65b1445SDouglas Gilbert 2261c65b1445SDouglas Gilbert static int resp_log_sense(struct scsi_cmnd * scp, 2262c65b1445SDouglas Gilbert struct sdebug_dev_info * devip) 2263c65b1445SDouglas Gilbert { 2264ab17241cSBart Van Assche int ppc, sp, pcode, subpcode, alloc_len, len, n; 2265c65b1445SDouglas Gilbert unsigned char arr[SDEBUG_MAX_LSENSE_SZ]; 226601123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 2267c65b1445SDouglas Gilbert 2268c65b1445SDouglas Gilbert memset(arr, 0, sizeof(arr)); 2269c65b1445SDouglas Gilbert ppc = cmd[1] & 0x2; 2270c65b1445SDouglas Gilbert sp = cmd[1] & 0x1; 2271c65b1445SDouglas Gilbert if (ppc || sp) { 227222017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0); 2273c65b1445SDouglas Gilbert return check_condition_result; 2274c65b1445SDouglas Gilbert } 2275c65b1445SDouglas Gilbert pcode = cmd[2] & 0x3f; 227623183910SDouglas Gilbert subpcode = cmd[3] & 0xff; 2277773642d9SDouglas Gilbert alloc_len = get_unaligned_be16(cmd + 7); 2278c65b1445SDouglas Gilbert arr[0] = pcode; 227923183910SDouglas Gilbert if (0 == subpcode) { 2280c65b1445SDouglas Gilbert switch (pcode) { 2281c65b1445SDouglas Gilbert case 0x0: /* Supported log pages log page */ 2282c65b1445SDouglas Gilbert n = 4; 2283c65b1445SDouglas Gilbert arr[n++] = 0x0; /* this page */ 2284c65b1445SDouglas Gilbert arr[n++] = 0xd; /* Temperature */ 2285c65b1445SDouglas Gilbert arr[n++] = 0x2f; /* Informational exceptions */ 2286c65b1445SDouglas Gilbert arr[3] = n - 4; 2287c65b1445SDouglas Gilbert break; 2288c65b1445SDouglas Gilbert case 0xd: /* Temperature log page */ 2289c65b1445SDouglas Gilbert arr[3] = resp_temp_l_pg(arr + 4); 2290c65b1445SDouglas Gilbert break; 2291c65b1445SDouglas Gilbert case 0x2f: /* Informational exceptions log page */ 2292c65b1445SDouglas Gilbert arr[3] = resp_ie_l_pg(arr + 4); 2293c65b1445SDouglas Gilbert break; 2294c65b1445SDouglas Gilbert default: 229522017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 2296c65b1445SDouglas Gilbert return check_condition_result; 2297c65b1445SDouglas Gilbert } 229823183910SDouglas Gilbert } else if (0xff == subpcode) { 229923183910SDouglas Gilbert arr[0] |= 0x40; 230023183910SDouglas Gilbert arr[1] = subpcode; 230123183910SDouglas Gilbert switch (pcode) { 230223183910SDouglas Gilbert case 0x0: /* Supported log pages and subpages log page */ 230323183910SDouglas Gilbert n = 4; 230423183910SDouglas Gilbert arr[n++] = 0x0; 230523183910SDouglas Gilbert arr[n++] = 0x0; /* 0,0 page */ 230623183910SDouglas Gilbert arr[n++] = 0x0; 230723183910SDouglas Gilbert arr[n++] = 0xff; /* this page */ 230823183910SDouglas Gilbert arr[n++] = 0xd; 230923183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 231023183910SDouglas Gilbert arr[n++] = 0x2f; 231123183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 231223183910SDouglas Gilbert arr[3] = n - 4; 231323183910SDouglas Gilbert break; 231423183910SDouglas Gilbert case 0xd: /* Temperature subpages */ 231523183910SDouglas Gilbert n = 4; 231623183910SDouglas Gilbert arr[n++] = 0xd; 231723183910SDouglas Gilbert arr[n++] = 0x0; /* Temperature */ 231823183910SDouglas Gilbert arr[3] = n - 4; 231923183910SDouglas Gilbert break; 232023183910SDouglas Gilbert case 0x2f: /* Informational exceptions subpages */ 232123183910SDouglas Gilbert n = 4; 232223183910SDouglas Gilbert arr[n++] = 0x2f; 232323183910SDouglas Gilbert arr[n++] = 0x0; /* Informational exceptions */ 232423183910SDouglas Gilbert arr[3] = n - 4; 232523183910SDouglas Gilbert break; 232623183910SDouglas Gilbert default: 232722017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5); 232823183910SDouglas Gilbert return check_condition_result; 232923183910SDouglas Gilbert } 233023183910SDouglas Gilbert } else { 233122017ed2SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1); 233223183910SDouglas Gilbert return check_condition_result; 233323183910SDouglas Gilbert } 2334773642d9SDouglas Gilbert len = min(get_unaligned_be16(arr + 2) + 4, alloc_len); 2335c65b1445SDouglas Gilbert return fill_from_dev_buffer(scp, arr, 2336c65b1445SDouglas Gilbert min(len, SDEBUG_MAX_INQ_ARR_SZ)); 2337c65b1445SDouglas Gilbert } 2338c65b1445SDouglas Gilbert 2339cbf67842SDouglas Gilbert static int check_device_access_params(struct scsi_cmnd *scp, 234019789100SFUJITA Tomonori unsigned long long lba, unsigned int num) 23411da177e4SLinus Torvalds { 2342c65b1445SDouglas Gilbert if (lba + num > sdebug_capacity) { 234322017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 23441da177e4SLinus Torvalds return check_condition_result; 23451da177e4SLinus Torvalds } 2346c65b1445SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2347c65b1445SDouglas Gilbert if (num > sdebug_store_sectors) { 234822017ed2SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2349cbf67842SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2350c65b1445SDouglas Gilbert return check_condition_result; 2351c65b1445SDouglas Gilbert } 235219789100SFUJITA Tomonori return 0; 235319789100SFUJITA Tomonori } 235419789100SFUJITA Tomonori 2355a4517511SAkinobu Mita /* Returns number of bytes copied or -1 if error. */ 2356fd32119bSDouglas Gilbert static int do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, 2357fd32119bSDouglas Gilbert bool do_write) 235819789100SFUJITA Tomonori { 235919789100SFUJITA Tomonori int ret; 2360c2248fc9SDouglas Gilbert u64 block, rest = 0; 2361a4517511SAkinobu Mita struct scsi_data_buffer *sdb; 2362a4517511SAkinobu Mita enum dma_data_direction dir; 236319789100SFUJITA Tomonori 2364c2248fc9SDouglas Gilbert if (do_write) { 2365a4517511SAkinobu Mita sdb = scsi_out(scmd); 2366a4517511SAkinobu Mita dir = DMA_TO_DEVICE; 2367a4517511SAkinobu Mita } else { 2368a4517511SAkinobu Mita sdb = scsi_in(scmd); 2369a4517511SAkinobu Mita dir = DMA_FROM_DEVICE; 2370a4517511SAkinobu Mita } 2371a4517511SAkinobu Mita 2372a4517511SAkinobu Mita if (!sdb->length) 2373a4517511SAkinobu Mita return 0; 2374a4517511SAkinobu Mita if (!(scsi_bidi_cmnd(scmd) || scmd->sc_data_direction == dir)) 2375a4517511SAkinobu Mita return -1; 237619789100SFUJITA Tomonori 237719789100SFUJITA Tomonori block = do_div(lba, sdebug_store_sectors); 237819789100SFUJITA Tomonori if (block + num > sdebug_store_sectors) 237919789100SFUJITA Tomonori rest = block + num - sdebug_store_sectors; 238019789100SFUJITA Tomonori 2381386ecb12SDave Gordon ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2382773642d9SDouglas Gilbert fake_storep + (block * sdebug_sector_size), 2383773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, 0, do_write); 2384773642d9SDouglas Gilbert if (ret != (num - rest) * sdebug_sector_size) 2385a4517511SAkinobu Mita return ret; 2386a4517511SAkinobu Mita 2387a4517511SAkinobu Mita if (rest) { 2388386ecb12SDave Gordon ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents, 2389773642d9SDouglas Gilbert fake_storep, rest * sdebug_sector_size, 2390773642d9SDouglas Gilbert (num - rest) * sdebug_sector_size, do_write); 2391a4517511SAkinobu Mita } 239219789100SFUJITA Tomonori 239319789100SFUJITA Tomonori return ret; 239419789100SFUJITA Tomonori } 239519789100SFUJITA Tomonori 239638d5c833SDouglas Gilbert /* If fake_store(lba,num) compares equal to arr(num), then copy top half of 239738d5c833SDouglas Gilbert * arr into fake_store(lba,num) and return true. If comparison fails then 239838d5c833SDouglas Gilbert * return false. */ 2399fd32119bSDouglas Gilbert static bool comp_write_worker(u64 lba, u32 num, const u8 *arr) 240038d5c833SDouglas Gilbert { 240138d5c833SDouglas Gilbert bool res; 240238d5c833SDouglas Gilbert u64 block, rest = 0; 240338d5c833SDouglas Gilbert u32 store_blks = sdebug_store_sectors; 2404773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 240538d5c833SDouglas Gilbert 240638d5c833SDouglas Gilbert block = do_div(lba, store_blks); 240738d5c833SDouglas Gilbert if (block + num > store_blks) 240838d5c833SDouglas Gilbert rest = block + num - store_blks; 240938d5c833SDouglas Gilbert 241038d5c833SDouglas Gilbert res = !memcmp(fake_storep + (block * lb_size), arr, 241138d5c833SDouglas Gilbert (num - rest) * lb_size); 241238d5c833SDouglas Gilbert if (!res) 241338d5c833SDouglas Gilbert return res; 241438d5c833SDouglas Gilbert if (rest) 241538d5c833SDouglas Gilbert res = memcmp(fake_storep, arr + ((num - rest) * lb_size), 241638d5c833SDouglas Gilbert rest * lb_size); 241738d5c833SDouglas Gilbert if (!res) 241838d5c833SDouglas Gilbert return res; 241938d5c833SDouglas Gilbert arr += num * lb_size; 242038d5c833SDouglas Gilbert memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size); 242138d5c833SDouglas Gilbert if (rest) 242238d5c833SDouglas Gilbert memcpy(fake_storep, arr + ((num - rest) * lb_size), 242338d5c833SDouglas Gilbert rest * lb_size); 242438d5c833SDouglas Gilbert return res; 242538d5c833SDouglas Gilbert } 242638d5c833SDouglas Gilbert 242751d648afSAkinobu Mita static __be16 dif_compute_csum(const void *buf, int len) 2428beb40ea4SAkinobu Mita { 242951d648afSAkinobu Mita __be16 csum; 2430beb40ea4SAkinobu Mita 2431773642d9SDouglas Gilbert if (sdebug_guard) 243251d648afSAkinobu Mita csum = (__force __be16)ip_compute_csum(buf, len); 243351d648afSAkinobu Mita else 2434beb40ea4SAkinobu Mita csum = cpu_to_be16(crc_t10dif(buf, len)); 243551d648afSAkinobu Mita 2436beb40ea4SAkinobu Mita return csum; 2437beb40ea4SAkinobu Mita } 2438beb40ea4SAkinobu Mita 24396ebf105cSChristoph Hellwig static int dif_verify(struct t10_pi_tuple *sdt, const void *data, 2440beb40ea4SAkinobu Mita sector_t sector, u32 ei_lba) 2441beb40ea4SAkinobu Mita { 2442773642d9SDouglas Gilbert __be16 csum = dif_compute_csum(data, sdebug_sector_size); 2443beb40ea4SAkinobu Mita 2444beb40ea4SAkinobu Mita if (sdt->guard_tag != csum) { 2445c1287970STomas Winkler pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n", 2446beb40ea4SAkinobu Mita (unsigned long)sector, 2447beb40ea4SAkinobu Mita be16_to_cpu(sdt->guard_tag), 2448beb40ea4SAkinobu Mita be16_to_cpu(csum)); 2449beb40ea4SAkinobu Mita return 0x01; 2450beb40ea4SAkinobu Mita } 24518475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE1_PROTECTION && 2452beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) { 2453c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2454c1287970STomas Winkler (unsigned long)sector); 2455beb40ea4SAkinobu Mita return 0x03; 2456beb40ea4SAkinobu Mita } 24578475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2458beb40ea4SAkinobu Mita be32_to_cpu(sdt->ref_tag) != ei_lba) { 2459c1287970STomas Winkler pr_err("REF check failed on sector %lu\n", 2460c1287970STomas Winkler (unsigned long)sector); 2461beb40ea4SAkinobu Mita return 0x03; 2462beb40ea4SAkinobu Mita } 2463beb40ea4SAkinobu Mita return 0; 2464beb40ea4SAkinobu Mita } 2465beb40ea4SAkinobu Mita 2466bb8c063cSAkinobu Mita static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector, 246765f72f2aSAkinobu Mita unsigned int sectors, bool read) 2468c6a44287SMartin K. Petersen { 2469be4e11beSAkinobu Mita size_t resid; 2470c6a44287SMartin K. Petersen void *paddr; 247114faa944SAkinobu Mita const void *dif_store_end = dif_storep + sdebug_store_sectors; 2472be4e11beSAkinobu Mita struct sg_mapping_iter miter; 2473c6a44287SMartin K. Petersen 2474e18d8beaSAkinobu Mita /* Bytes of protection data to copy into sgl */ 2475e18d8beaSAkinobu Mita resid = sectors * sizeof(*dif_storep); 2476c6a44287SMartin K. Petersen 2477be4e11beSAkinobu Mita sg_miter_start(&miter, scsi_prot_sglist(SCpnt), 2478be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC | 2479be4e11beSAkinobu Mita (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG)); 2480be4e11beSAkinobu Mita 2481be4e11beSAkinobu Mita while (sg_miter_next(&miter) && resid > 0) { 2482be4e11beSAkinobu Mita size_t len = min(miter.length, resid); 248314faa944SAkinobu Mita void *start = dif_store(sector); 2484be4e11beSAkinobu Mita size_t rest = 0; 248514faa944SAkinobu Mita 248614faa944SAkinobu Mita if (dif_store_end < start + len) 248714faa944SAkinobu Mita rest = start + len - dif_store_end; 2488c6a44287SMartin K. Petersen 2489be4e11beSAkinobu Mita paddr = miter.addr; 249014faa944SAkinobu Mita 249165f72f2aSAkinobu Mita if (read) 249265f72f2aSAkinobu Mita memcpy(paddr, start, len - rest); 249365f72f2aSAkinobu Mita else 249465f72f2aSAkinobu Mita memcpy(start, paddr, len - rest); 249565f72f2aSAkinobu Mita 249665f72f2aSAkinobu Mita if (rest) { 249765f72f2aSAkinobu Mita if (read) 249814faa944SAkinobu Mita memcpy(paddr + len - rest, dif_storep, rest); 249965f72f2aSAkinobu Mita else 250065f72f2aSAkinobu Mita memcpy(dif_storep, paddr + len - rest, rest); 250165f72f2aSAkinobu Mita } 2502c6a44287SMartin K. Petersen 2503e18d8beaSAkinobu Mita sector += len / sizeof(*dif_storep); 2504c6a44287SMartin K. Petersen resid -= len; 2505c6a44287SMartin K. Petersen } 2506be4e11beSAkinobu Mita sg_miter_stop(&miter); 2507bb8c063cSAkinobu Mita } 2508c6a44287SMartin K. Petersen 2509bb8c063cSAkinobu Mita static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec, 2510bb8c063cSAkinobu Mita unsigned int sectors, u32 ei_lba) 2511bb8c063cSAkinobu Mita { 2512bb8c063cSAkinobu Mita unsigned int i; 25136ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 2514bb8c063cSAkinobu Mita sector_t sector; 2515bb8c063cSAkinobu Mita 2516c45eabecSAkinobu Mita for (i = 0; i < sectors; i++, ei_lba++) { 2517bb8c063cSAkinobu Mita int ret; 2518bb8c063cSAkinobu Mita 2519bb8c063cSAkinobu Mita sector = start_sec + i; 2520bb8c063cSAkinobu Mita sdt = dif_store(sector); 2521bb8c063cSAkinobu Mita 252251d648afSAkinobu Mita if (sdt->app_tag == cpu_to_be16(0xffff)) 2523bb8c063cSAkinobu Mita continue; 2524bb8c063cSAkinobu Mita 2525bb8c063cSAkinobu Mita ret = dif_verify(sdt, fake_store(sector), sector, ei_lba); 2526bb8c063cSAkinobu Mita if (ret) { 2527bb8c063cSAkinobu Mita dif_errors++; 2528bb8c063cSAkinobu Mita return ret; 2529bb8c063cSAkinobu Mita } 2530bb8c063cSAkinobu Mita } 2531bb8c063cSAkinobu Mita 253265f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, true); 2533c6a44287SMartin K. Petersen dix_reads++; 2534c6a44287SMartin K. Petersen 2535c6a44287SMartin K. Petersen return 0; 2536c6a44287SMartin K. Petersen } 2537c6a44287SMartin K. Petersen 2538fd32119bSDouglas Gilbert static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 253919789100SFUJITA Tomonori { 2540c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2541c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 2542c2248fc9SDouglas Gilbert u64 lba; 2543c2248fc9SDouglas Gilbert u32 num; 2544c2248fc9SDouglas Gilbert u32 ei_lba; 254519789100SFUJITA Tomonori unsigned long iflags; 254619789100SFUJITA Tomonori int ret; 2547c2248fc9SDouglas Gilbert bool check_prot; 254819789100SFUJITA Tomonori 2549c2248fc9SDouglas Gilbert switch (cmd[0]) { 2550c2248fc9SDouglas Gilbert case READ_16: 2551c2248fc9SDouglas Gilbert ei_lba = 0; 2552c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2553c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2554c2248fc9SDouglas Gilbert check_prot = true; 2555c2248fc9SDouglas Gilbert break; 2556c2248fc9SDouglas Gilbert case READ_10: 2557c2248fc9SDouglas Gilbert ei_lba = 0; 2558c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2559c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2560c2248fc9SDouglas Gilbert check_prot = true; 2561c2248fc9SDouglas Gilbert break; 2562c2248fc9SDouglas Gilbert case READ_6: 2563c2248fc9SDouglas Gilbert ei_lba = 0; 2564c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2565c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2566c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2567c2248fc9SDouglas Gilbert check_prot = true; 2568c2248fc9SDouglas Gilbert break; 2569c2248fc9SDouglas Gilbert case READ_12: 2570c2248fc9SDouglas Gilbert ei_lba = 0; 2571c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2572c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2573c2248fc9SDouglas Gilbert check_prot = true; 2574c2248fc9SDouglas Gilbert break; 2575c2248fc9SDouglas Gilbert case XDWRITEREAD_10: 2576c2248fc9SDouglas Gilbert ei_lba = 0; 2577c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2578c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2579c2248fc9SDouglas Gilbert check_prot = false; 2580c2248fc9SDouglas Gilbert break; 2581c2248fc9SDouglas Gilbert default: /* assume READ(32) */ 2582c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2583c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2584c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2585c2248fc9SDouglas Gilbert check_prot = false; 2586c2248fc9SDouglas Gilbert break; 2587c2248fc9SDouglas Gilbert } 2588f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 25898475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2590c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2591c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2592c2248fc9SDouglas Gilbert return check_condition_result; 2593c2248fc9SDouglas Gilbert } 25948475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 25958475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 2596c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2597c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected RD " 2598c2248fc9SDouglas Gilbert "to DIF device\n"); 2599c2248fc9SDouglas Gilbert } 2600f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2601c4837394SDouglas Gilbert sqcp = (struct sdebug_queued_cmd *)scp->host_scribble; 2602c2248fc9SDouglas Gilbert 2603c4837394SDouglas Gilbert if (sqcp) { 2604c4837394SDouglas Gilbert if (sqcp->inj_short) 2605c2248fc9SDouglas Gilbert num /= 2; 2606c2248fc9SDouglas Gilbert } 2607c4837394SDouglas Gilbert } else 2608c4837394SDouglas Gilbert sqcp = NULL; 2609c2248fc9SDouglas Gilbert 2610c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2611f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2612c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2613c2248fc9SDouglas Gilbert return check_condition_result; 2614c2248fc9SDouglas Gilbert } 2615c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2616f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2617c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2618c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2619c2248fc9SDouglas Gilbert return check_condition_result; 2620c2248fc9SDouglas Gilbert } 262119789100SFUJITA Tomonori 2622f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) && 262332f7ef73SDouglas Gilbert (lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) && 2624f46eb0e9SDouglas Gilbert ((lba + num) > OPT_MEDIUM_ERR_ADDR))) { 2625c65b1445SDouglas Gilbert /* claim unrecoverable read error */ 2626c2248fc9SDouglas Gilbert mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0); 2627c65b1445SDouglas Gilbert /* set info field and valid bit for fixed descriptor */ 2628c2248fc9SDouglas Gilbert if (0x70 == (scp->sense_buffer[0] & 0x7f)) { 2629c2248fc9SDouglas Gilbert scp->sense_buffer[0] |= 0x80; /* Valid bit */ 263032f7ef73SDouglas Gilbert ret = (lba < OPT_MEDIUM_ERR_ADDR) 263132f7ef73SDouglas Gilbert ? OPT_MEDIUM_ERR_ADDR : (int)lba; 2632c2248fc9SDouglas Gilbert put_unaligned_be32(ret, scp->sense_buffer + 3); 2633c65b1445SDouglas Gilbert } 2634c2248fc9SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 26351da177e4SLinus Torvalds return check_condition_result; 26361da177e4SLinus Torvalds } 2637c6a44287SMartin K. Petersen 26386c78cc06SAkinobu Mita read_lock_irqsave(&atomic_rw, iflags); 26396c78cc06SAkinobu Mita 2640c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2641f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2642c2248fc9SDouglas Gilbert int prot_ret = prot_verify_read(scp, lba, num, ei_lba); 2643c6a44287SMartin K. Petersen 2644c6a44287SMartin K. Petersen if (prot_ret) { 26456c78cc06SAkinobu Mita read_unlock_irqrestore(&atomic_rw, iflags); 2646c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret); 2647c6a44287SMartin K. Petersen return illegal_condition_result; 2648c6a44287SMartin K. Petersen } 2649c6a44287SMartin K. Petersen } 2650c6a44287SMartin K. Petersen 2651c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, false); 26521da177e4SLinus Torvalds read_unlock_irqrestore(&atomic_rw, iflags); 2653f46eb0e9SDouglas Gilbert if (unlikely(ret == -1)) 2654a4517511SAkinobu Mita return DID_ERROR << 16; 2655a4517511SAkinobu Mita 2656c2248fc9SDouglas Gilbert scsi_in(scp)->resid = scsi_bufflen(scp) - ret; 2657a4517511SAkinobu Mita 2658c4837394SDouglas Gilbert if (unlikely(sqcp)) { 2659c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2660c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2661c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2662c2248fc9SDouglas Gilbert return check_condition_result; 2663c4837394SDouglas Gilbert } else if (sqcp->inj_transport) { 2664c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 2665c2248fc9SDouglas Gilbert TRANSPORT_PROBLEM, ACK_NAK_TO); 2666c2248fc9SDouglas Gilbert return check_condition_result; 2667c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2668c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2669c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2670c2248fc9SDouglas Gilbert return illegal_condition_result; 2671c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2672c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2673c2248fc9SDouglas Gilbert return illegal_condition_result; 2674c2248fc9SDouglas Gilbert } 2675c2248fc9SDouglas Gilbert } 2676a4517511SAkinobu Mita return 0; 26771da177e4SLinus Torvalds } 26781da177e4SLinus Torvalds 267958a8635dSTomas Winkler static void dump_sector(unsigned char *buf, int len) 2680c6a44287SMartin K. Petersen { 2681cbf67842SDouglas Gilbert int i, j, n; 2682c6a44287SMartin K. Petersen 2683cbf67842SDouglas Gilbert pr_err(">>> Sector Dump <<<\n"); 2684c6a44287SMartin K. Petersen for (i = 0 ; i < len ; i += 16) { 2685cbf67842SDouglas Gilbert char b[128]; 2686c6a44287SMartin K. Petersen 2687cbf67842SDouglas Gilbert for (j = 0, n = 0; j < 16; j++) { 2688c6a44287SMartin K. Petersen unsigned char c = buf[i+j]; 2689c6a44287SMartin K. Petersen 2690cbf67842SDouglas Gilbert if (c >= 0x20 && c < 0x7e) 2691cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2692cbf67842SDouglas Gilbert " %c ", buf[i+j]); 2693cbf67842SDouglas Gilbert else 2694cbf67842SDouglas Gilbert n += scnprintf(b + n, sizeof(b) - n, 2695cbf67842SDouglas Gilbert "%02x ", buf[i+j]); 2696cbf67842SDouglas Gilbert } 2697cbf67842SDouglas Gilbert pr_err("%04d: %s\n", i, b); 2698c6a44287SMartin K. Petersen } 2699c6a44287SMartin K. Petersen } 2700c6a44287SMartin K. Petersen 2701c6a44287SMartin K. Petersen static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec, 2702395cef03SMartin K. Petersen unsigned int sectors, u32 ei_lba) 2703c6a44287SMartin K. Petersen { 2704be4e11beSAkinobu Mita int ret; 27056ebf105cSChristoph Hellwig struct t10_pi_tuple *sdt; 2706be4e11beSAkinobu Mita void *daddr; 270765f72f2aSAkinobu Mita sector_t sector = start_sec; 2708c6a44287SMartin K. Petersen int ppage_offset; 2709be4e11beSAkinobu Mita int dpage_offset; 2710be4e11beSAkinobu Mita struct sg_mapping_iter diter; 2711be4e11beSAkinobu Mita struct sg_mapping_iter piter; 2712c6a44287SMartin K. Petersen 2713c6a44287SMartin K. Petersen BUG_ON(scsi_sg_count(SCpnt) == 0); 2714c6a44287SMartin K. Petersen BUG_ON(scsi_prot_sg_count(SCpnt) == 0); 2715c6a44287SMartin K. Petersen 2716be4e11beSAkinobu Mita sg_miter_start(&piter, scsi_prot_sglist(SCpnt), 2717be4e11beSAkinobu Mita scsi_prot_sg_count(SCpnt), 2718be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2719be4e11beSAkinobu Mita sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt), 2720be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_FROM_SG); 2721c6a44287SMartin K. Petersen 2722be4e11beSAkinobu Mita /* For each protection page */ 2723be4e11beSAkinobu Mita while (sg_miter_next(&piter)) { 2724be4e11beSAkinobu Mita dpage_offset = 0; 2725be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2726be4e11beSAkinobu Mita ret = 0x01; 2727be4e11beSAkinobu Mita goto out; 2728c6a44287SMartin K. Petersen } 2729c6a44287SMartin K. Petersen 2730be4e11beSAkinobu Mita for (ppage_offset = 0; ppage_offset < piter.length; 27316ebf105cSChristoph Hellwig ppage_offset += sizeof(struct t10_pi_tuple)) { 2732be4e11beSAkinobu Mita /* If we're at the end of the current 2733be4e11beSAkinobu Mita * data page advance to the next one 2734be4e11beSAkinobu Mita */ 2735be4e11beSAkinobu Mita if (dpage_offset >= diter.length) { 2736be4e11beSAkinobu Mita if (WARN_ON(!sg_miter_next(&diter))) { 2737be4e11beSAkinobu Mita ret = 0x01; 2738be4e11beSAkinobu Mita goto out; 2739be4e11beSAkinobu Mita } 2740be4e11beSAkinobu Mita dpage_offset = 0; 2741be4e11beSAkinobu Mita } 2742c6a44287SMartin K. Petersen 2743be4e11beSAkinobu Mita sdt = piter.addr + ppage_offset; 2744be4e11beSAkinobu Mita daddr = diter.addr + dpage_offset; 2745be4e11beSAkinobu Mita 2746be4e11beSAkinobu Mita ret = dif_verify(sdt, daddr, sector, ei_lba); 2747beb40ea4SAkinobu Mita if (ret) { 2748773642d9SDouglas Gilbert dump_sector(daddr, sdebug_sector_size); 2749395cef03SMartin K. Petersen goto out; 2750395cef03SMartin K. Petersen } 2751395cef03SMartin K. Petersen 2752c6a44287SMartin K. Petersen sector++; 2753395cef03SMartin K. Petersen ei_lba++; 2754773642d9SDouglas Gilbert dpage_offset += sdebug_sector_size; 2755c6a44287SMartin K. Petersen } 2756be4e11beSAkinobu Mita diter.consumed = dpage_offset; 2757be4e11beSAkinobu Mita sg_miter_stop(&diter); 2758c6a44287SMartin K. Petersen } 2759be4e11beSAkinobu Mita sg_miter_stop(&piter); 2760c6a44287SMartin K. Petersen 276165f72f2aSAkinobu Mita dif_copy_prot(SCpnt, start_sec, sectors, false); 2762c6a44287SMartin K. Petersen dix_writes++; 2763c6a44287SMartin K. Petersen 2764c6a44287SMartin K. Petersen return 0; 2765c6a44287SMartin K. Petersen 2766c6a44287SMartin K. Petersen out: 2767c6a44287SMartin K. Petersen dif_errors++; 2768be4e11beSAkinobu Mita sg_miter_stop(&diter); 2769be4e11beSAkinobu Mita sg_miter_stop(&piter); 2770c6a44287SMartin K. Petersen return ret; 2771c6a44287SMartin K. Petersen } 2772c6a44287SMartin K. Petersen 2773b90ebc3dSAkinobu Mita static unsigned long lba_to_map_index(sector_t lba) 2774b90ebc3dSAkinobu Mita { 2775773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2776773642d9SDouglas Gilbert lba += sdebug_unmap_granularity - sdebug_unmap_alignment; 2777773642d9SDouglas Gilbert sector_div(lba, sdebug_unmap_granularity); 2778b90ebc3dSAkinobu Mita return lba; 2779b90ebc3dSAkinobu Mita } 2780b90ebc3dSAkinobu Mita 2781b90ebc3dSAkinobu Mita static sector_t map_index_to_lba(unsigned long index) 2782b90ebc3dSAkinobu Mita { 2783773642d9SDouglas Gilbert sector_t lba = index * sdebug_unmap_granularity; 2784a027b5b9SAkinobu Mita 2785773642d9SDouglas Gilbert if (sdebug_unmap_alignment) 2786773642d9SDouglas Gilbert lba -= sdebug_unmap_granularity - sdebug_unmap_alignment; 2787a027b5b9SAkinobu Mita return lba; 2788a027b5b9SAkinobu Mita } 2789a027b5b9SAkinobu Mita 279044d92694SMartin K. Petersen static unsigned int map_state(sector_t lba, unsigned int *num) 279144d92694SMartin K. Petersen { 2792b90ebc3dSAkinobu Mita sector_t end; 2793b90ebc3dSAkinobu Mita unsigned int mapped; 2794b90ebc3dSAkinobu Mita unsigned long index; 2795b90ebc3dSAkinobu Mita unsigned long next; 279644d92694SMartin K. Petersen 2797b90ebc3dSAkinobu Mita index = lba_to_map_index(lba); 2798b90ebc3dSAkinobu Mita mapped = test_bit(index, map_storep); 279944d92694SMartin K. Petersen 280044d92694SMartin K. Petersen if (mapped) 2801b90ebc3dSAkinobu Mita next = find_next_zero_bit(map_storep, map_size, index); 280244d92694SMartin K. Petersen else 2803b90ebc3dSAkinobu Mita next = find_next_bit(map_storep, map_size, index); 280444d92694SMartin K. Petersen 2805b90ebc3dSAkinobu Mita end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next)); 280644d92694SMartin K. Petersen *num = end - lba; 280744d92694SMartin K. Petersen return mapped; 280844d92694SMartin K. Petersen } 280944d92694SMartin K. Petersen 281044d92694SMartin K. Petersen static void map_region(sector_t lba, unsigned int len) 281144d92694SMartin K. Petersen { 281244d92694SMartin K. Petersen sector_t end = lba + len; 281344d92694SMartin K. Petersen 281444d92694SMartin K. Petersen while (lba < end) { 2815b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 281644d92694SMartin K. Petersen 2817b90ebc3dSAkinobu Mita if (index < map_size) 2818b90ebc3dSAkinobu Mita set_bit(index, map_storep); 281944d92694SMartin K. Petersen 2820b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 282144d92694SMartin K. Petersen } 282244d92694SMartin K. Petersen } 282344d92694SMartin K. Petersen 282444d92694SMartin K. Petersen static void unmap_region(sector_t lba, unsigned int len) 282544d92694SMartin K. Petersen { 282644d92694SMartin K. Petersen sector_t end = lba + len; 282744d92694SMartin K. Petersen 282844d92694SMartin K. Petersen while (lba < end) { 2829b90ebc3dSAkinobu Mita unsigned long index = lba_to_map_index(lba); 283044d92694SMartin K. Petersen 2831b90ebc3dSAkinobu Mita if (lba == map_index_to_lba(index) && 2832773642d9SDouglas Gilbert lba + sdebug_unmap_granularity <= end && 2833b90ebc3dSAkinobu Mita index < map_size) { 2834b90ebc3dSAkinobu Mita clear_bit(index, map_storep); 2835760f3b03SDouglas Gilbert if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */ 2836be1dd78dSEric Sandeen memset(fake_storep + 2837760f3b03SDouglas Gilbert lba * sdebug_sector_size, 2838760f3b03SDouglas Gilbert (sdebug_lbprz & 1) ? 0 : 0xff, 2839773642d9SDouglas Gilbert sdebug_sector_size * 2840773642d9SDouglas Gilbert sdebug_unmap_granularity); 2841be1dd78dSEric Sandeen } 2842e9926b43SAkinobu Mita if (dif_storep) { 2843e9926b43SAkinobu Mita memset(dif_storep + lba, 0xff, 2844e9926b43SAkinobu Mita sizeof(*dif_storep) * 2845773642d9SDouglas Gilbert sdebug_unmap_granularity); 2846e9926b43SAkinobu Mita } 2847b90ebc3dSAkinobu Mita } 2848b90ebc3dSAkinobu Mita lba = map_index_to_lba(index + 1); 284944d92694SMartin K. Petersen } 285044d92694SMartin K. Petersen } 285144d92694SMartin K. Petersen 2852fd32119bSDouglas Gilbert static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 28531da177e4SLinus Torvalds { 2854c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 2855c2248fc9SDouglas Gilbert u64 lba; 2856c2248fc9SDouglas Gilbert u32 num; 2857c2248fc9SDouglas Gilbert u32 ei_lba; 28581da177e4SLinus Torvalds unsigned long iflags; 285919789100SFUJITA Tomonori int ret; 2860c2248fc9SDouglas Gilbert bool check_prot; 28611da177e4SLinus Torvalds 2862c2248fc9SDouglas Gilbert switch (cmd[0]) { 2863c2248fc9SDouglas Gilbert case WRITE_16: 2864c2248fc9SDouglas Gilbert ei_lba = 0; 2865c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 2866c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 2867c2248fc9SDouglas Gilbert check_prot = true; 2868c2248fc9SDouglas Gilbert break; 2869c2248fc9SDouglas Gilbert case WRITE_10: 2870c2248fc9SDouglas Gilbert ei_lba = 0; 2871c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2872c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2873c2248fc9SDouglas Gilbert check_prot = true; 2874c2248fc9SDouglas Gilbert break; 2875c2248fc9SDouglas Gilbert case WRITE_6: 2876c2248fc9SDouglas Gilbert ei_lba = 0; 2877c2248fc9SDouglas Gilbert lba = (u32)cmd[3] | (u32)cmd[2] << 8 | 2878c2248fc9SDouglas Gilbert (u32)(cmd[1] & 0x1f) << 16; 2879c2248fc9SDouglas Gilbert num = (0 == cmd[4]) ? 256 : cmd[4]; 2880c2248fc9SDouglas Gilbert check_prot = true; 2881c2248fc9SDouglas Gilbert break; 2882c2248fc9SDouglas Gilbert case WRITE_12: 2883c2248fc9SDouglas Gilbert ei_lba = 0; 2884c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2885c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 6); 2886c2248fc9SDouglas Gilbert check_prot = true; 2887c2248fc9SDouglas Gilbert break; 2888c2248fc9SDouglas Gilbert case 0x53: /* XDWRITEREAD(10) */ 2889c2248fc9SDouglas Gilbert ei_lba = 0; 2890c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 2891c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 2892c2248fc9SDouglas Gilbert check_prot = false; 2893c2248fc9SDouglas Gilbert break; 2894c2248fc9SDouglas Gilbert default: /* assume WRITE(32) */ 2895c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 12); 2896c2248fc9SDouglas Gilbert ei_lba = get_unaligned_be32(cmd + 20); 2897c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 28); 2898c2248fc9SDouglas Gilbert check_prot = false; 2899c2248fc9SDouglas Gilbert break; 2900c2248fc9SDouglas Gilbert } 2901f46eb0e9SDouglas Gilbert if (unlikely(have_dif_prot && check_prot)) { 29028475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 2903c2248fc9SDouglas Gilbert (cmd[1] & 0xe0)) { 2904c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 2905c2248fc9SDouglas Gilbert return check_condition_result; 2906c2248fc9SDouglas Gilbert } 29078475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 29088475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 2909c2248fc9SDouglas Gilbert (cmd[1] & 0xe0) == 0) 2910c2248fc9SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 2911c2248fc9SDouglas Gilbert "to DIF device\n"); 2912c2248fc9SDouglas Gilbert } 2913c2248fc9SDouglas Gilbert 2914c2248fc9SDouglas Gilbert /* inline check_device_access_params() */ 2915f46eb0e9SDouglas Gilbert if (unlikely(lba + num > sdebug_capacity)) { 2916c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 2917c2248fc9SDouglas Gilbert return check_condition_result; 2918c2248fc9SDouglas Gilbert } 2919c2248fc9SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 2920f46eb0e9SDouglas Gilbert if (unlikely(num > sdebug_store_sectors)) { 2921c2248fc9SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 2922c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 2923c2248fc9SDouglas Gilbert return check_condition_result; 2924c2248fc9SDouglas Gilbert } 29251da177e4SLinus Torvalds 29266c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 29276c78cc06SAkinobu Mita 2928c6a44287SMartin K. Petersen /* DIX + T10 DIF */ 2929f46eb0e9SDouglas Gilbert if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) { 2930c2248fc9SDouglas Gilbert int prot_ret = prot_verify_write(scp, lba, num, ei_lba); 2931c6a44287SMartin K. Petersen 2932c6a44287SMartin K. Petersen if (prot_ret) { 29336c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 2934c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret); 2935c6a44287SMartin K. Petersen return illegal_condition_result; 2936c6a44287SMartin K. Petersen } 2937c6a44287SMartin K. Petersen } 2938c6a44287SMartin K. Petersen 2939c2248fc9SDouglas Gilbert ret = do_device_access(scp, lba, num, true); 2940f46eb0e9SDouglas Gilbert if (unlikely(scsi_debug_lbp())) 294144d92694SMartin K. Petersen map_region(lba, num); 29421da177e4SLinus Torvalds write_unlock_irqrestore(&atomic_rw, iflags); 2943f46eb0e9SDouglas Gilbert if (unlikely(-1 == ret)) 2944773642d9SDouglas Gilbert return DID_ERROR << 16; 2945c4837394SDouglas Gilbert else if (unlikely(sdebug_verbose && 2946c4837394SDouglas Gilbert (ret < (num * sdebug_sector_size)))) 2947c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 2948cbf67842SDouglas Gilbert "%s: write: cdb indicated=%u, IO sent=%d bytes\n", 2949773642d9SDouglas Gilbert my_name, num * sdebug_sector_size, ret); 295044d92694SMartin K. Petersen 2951f46eb0e9SDouglas Gilbert if (unlikely(sdebug_any_injecting_opt)) { 2952c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp = 2953c4837394SDouglas Gilbert (struct sdebug_queued_cmd *)scp->host_scribble; 2954c2248fc9SDouglas Gilbert 2955c4837394SDouglas Gilbert if (sqcp) { 2956c4837394SDouglas Gilbert if (sqcp->inj_recovered) { 2957c2248fc9SDouglas Gilbert mk_sense_buffer(scp, RECOVERED_ERROR, 2958c2248fc9SDouglas Gilbert THRESHOLD_EXCEEDED, 0); 2959c2248fc9SDouglas Gilbert return check_condition_result; 2960c4837394SDouglas Gilbert } else if (sqcp->inj_dif) { 2961c2248fc9SDouglas Gilbert /* Logical block guard check failed */ 2962c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1); 2963c2248fc9SDouglas Gilbert return illegal_condition_result; 2964c4837394SDouglas Gilbert } else if (sqcp->inj_dix) { 2965c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1); 2966c2248fc9SDouglas Gilbert return illegal_condition_result; 2967c2248fc9SDouglas Gilbert } 2968c2248fc9SDouglas Gilbert } 2969c4837394SDouglas Gilbert } 29701da177e4SLinus Torvalds return 0; 29711da177e4SLinus Torvalds } 29721da177e4SLinus Torvalds 2973fd32119bSDouglas Gilbert static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, 2974fd32119bSDouglas Gilbert u32 ei_lba, bool unmap, bool ndob) 297544d92694SMartin K. Petersen { 297644d92694SMartin K. Petersen unsigned long iflags; 297744d92694SMartin K. Petersen unsigned long long i; 297844d92694SMartin K. Petersen int ret; 2979773642d9SDouglas Gilbert u64 lba_off; 298044d92694SMartin K. Petersen 2981c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 298244d92694SMartin K. Petersen if (ret) 298344d92694SMartin K. Petersen return ret; 298444d92694SMartin K. Petersen 298544d92694SMartin K. Petersen write_lock_irqsave(&atomic_rw, iflags); 298644d92694SMartin K. Petersen 29879ed8d3dcSAkinobu Mita if (unmap && scsi_debug_lbp()) { 298844d92694SMartin K. Petersen unmap_region(lba, num); 298944d92694SMartin K. Petersen goto out; 299044d92694SMartin K. Petersen } 299144d92694SMartin K. Petersen 2992773642d9SDouglas Gilbert lba_off = lba * sdebug_sector_size; 2993c2248fc9SDouglas Gilbert /* if ndob then zero 1 logical block, else fetch 1 logical block */ 2994c2248fc9SDouglas Gilbert if (ndob) { 2995773642d9SDouglas Gilbert memset(fake_storep + lba_off, 0, sdebug_sector_size); 2996c2248fc9SDouglas Gilbert ret = 0; 2997c2248fc9SDouglas Gilbert } else 2998773642d9SDouglas Gilbert ret = fetch_to_dev_buffer(scp, fake_storep + lba_off, 2999773642d9SDouglas Gilbert sdebug_sector_size); 300044d92694SMartin K. Petersen 300144d92694SMartin K. Petersen if (-1 == ret) { 300244d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 3003773642d9SDouglas Gilbert return DID_ERROR << 16; 3004773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (num * sdebug_sector_size))) 3005c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, 3006cbf67842SDouglas Gilbert "%s: %s: cdb indicated=%u, IO sent=%d bytes\n", 3007cbf67842SDouglas Gilbert my_name, "write same", 3008773642d9SDouglas Gilbert num * sdebug_sector_size, ret); 300944d92694SMartin K. Petersen 301044d92694SMartin K. Petersen /* Copy first sector to remaining blocks */ 301144d92694SMartin K. Petersen for (i = 1 ; i < num ; i++) 3012773642d9SDouglas Gilbert memcpy(fake_storep + ((lba + i) * sdebug_sector_size), 3013773642d9SDouglas Gilbert fake_storep + lba_off, 3014773642d9SDouglas Gilbert sdebug_sector_size); 301544d92694SMartin K. Petersen 30169ed8d3dcSAkinobu Mita if (scsi_debug_lbp()) 301744d92694SMartin K. Petersen map_region(lba, num); 301844d92694SMartin K. Petersen out: 301944d92694SMartin K. Petersen write_unlock_irqrestore(&atomic_rw, iflags); 302044d92694SMartin K. Petersen 302144d92694SMartin K. Petersen return 0; 302244d92694SMartin K. Petersen } 302344d92694SMartin K. Petersen 3024fd32119bSDouglas Gilbert static int resp_write_same_10(struct scsi_cmnd *scp, 3025fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3026c2248fc9SDouglas Gilbert { 3027c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3028c2248fc9SDouglas Gilbert u32 lba; 3029c2248fc9SDouglas Gilbert u16 num; 3030c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3031c2248fc9SDouglas Gilbert bool unmap = false; 3032c2248fc9SDouglas Gilbert 3033c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { 3034773642d9SDouglas Gilbert if (sdebug_lbpws10 == 0) { 3035c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3036c2248fc9SDouglas Gilbert return check_condition_result; 3037c2248fc9SDouglas Gilbert } else 3038c2248fc9SDouglas Gilbert unmap = true; 3039c2248fc9SDouglas Gilbert } 3040c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3041c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3042773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3043c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 3044c2248fc9SDouglas Gilbert return check_condition_result; 3045c2248fc9SDouglas Gilbert } 3046c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, false); 3047c2248fc9SDouglas Gilbert } 3048c2248fc9SDouglas Gilbert 3049fd32119bSDouglas Gilbert static int resp_write_same_16(struct scsi_cmnd *scp, 3050fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3051c2248fc9SDouglas Gilbert { 3052c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3053c2248fc9SDouglas Gilbert u64 lba; 3054c2248fc9SDouglas Gilbert u32 num; 3055c2248fc9SDouglas Gilbert u32 ei_lba = 0; 3056c2248fc9SDouglas Gilbert bool unmap = false; 3057c2248fc9SDouglas Gilbert bool ndob = false; 3058c2248fc9SDouglas Gilbert 3059c2248fc9SDouglas Gilbert if (cmd[1] & 0x8) { /* UNMAP */ 3060773642d9SDouglas Gilbert if (sdebug_lbpws == 0) { 3061c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3); 3062c2248fc9SDouglas Gilbert return check_condition_result; 3063c2248fc9SDouglas Gilbert } else 3064c2248fc9SDouglas Gilbert unmap = true; 3065c2248fc9SDouglas Gilbert } 3066c2248fc9SDouglas Gilbert if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */ 3067c2248fc9SDouglas Gilbert ndob = true; 3068c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3069c2248fc9SDouglas Gilbert num = get_unaligned_be32(cmd + 10); 3070773642d9SDouglas Gilbert if (num > sdebug_write_same_length) { 3071c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1); 3072c2248fc9SDouglas Gilbert return check_condition_result; 3073c2248fc9SDouglas Gilbert } 3074c2248fc9SDouglas Gilbert return resp_write_same(scp, lba, num, ei_lba, unmap, ndob); 3075c2248fc9SDouglas Gilbert } 3076c2248fc9SDouglas Gilbert 3077acafd0b9SEwan D. Milne /* Note the mode field is in the same position as the (lower) service action 3078acafd0b9SEwan D. Milne * field. For the Report supported operation codes command, SPC-4 suggests 3079acafd0b9SEwan D. Milne * each mode of this command should be reported separately; for future. */ 3080fd32119bSDouglas Gilbert static int resp_write_buffer(struct scsi_cmnd *scp, 3081fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3082acafd0b9SEwan D. Milne { 3083acafd0b9SEwan D. Milne u8 *cmd = scp->cmnd; 3084acafd0b9SEwan D. Milne struct scsi_device *sdp = scp->device; 3085acafd0b9SEwan D. Milne struct sdebug_dev_info *dp; 3086acafd0b9SEwan D. Milne u8 mode; 3087acafd0b9SEwan D. Milne 3088acafd0b9SEwan D. Milne mode = cmd[1] & 0x1f; 3089acafd0b9SEwan D. Milne switch (mode) { 3090acafd0b9SEwan D. Milne case 0x4: /* download microcode (MC) and activate (ACT) */ 3091acafd0b9SEwan D. Milne /* set UAs on this device only */ 3092acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3093acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm); 3094acafd0b9SEwan D. Milne break; 3095acafd0b9SEwan D. Milne case 0x5: /* download MC, save and ACT */ 3096acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm); 3097acafd0b9SEwan D. Milne break; 3098acafd0b9SEwan D. Milne case 0x6: /* download MC with offsets and ACT */ 3099acafd0b9SEwan D. Milne /* set UAs on most devices (LUs) in this target */ 3100acafd0b9SEwan D. Milne list_for_each_entry(dp, 3101acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3102acafd0b9SEwan D. Milne dev_list) 3103acafd0b9SEwan D. Milne if (dp->target == sdp->id) { 3104acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm); 3105acafd0b9SEwan D. Milne if (devip != dp) 3106acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED, 3107acafd0b9SEwan D. Milne dp->uas_bm); 3108acafd0b9SEwan D. Milne } 3109acafd0b9SEwan D. Milne break; 3110acafd0b9SEwan D. Milne case 0x7: /* download MC with offsets, save, and ACT */ 3111acafd0b9SEwan D. Milne /* set UA on all devices (LUs) in this target */ 3112acafd0b9SEwan D. Milne list_for_each_entry(dp, 3113acafd0b9SEwan D. Milne &devip->sdbg_host->dev_info_list, 3114acafd0b9SEwan D. Milne dev_list) 3115acafd0b9SEwan D. Milne if (dp->target == sdp->id) 3116acafd0b9SEwan D. Milne set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, 3117acafd0b9SEwan D. Milne dp->uas_bm); 3118acafd0b9SEwan D. Milne break; 3119acafd0b9SEwan D. Milne default: 3120acafd0b9SEwan D. Milne /* do nothing for this command for other mode values */ 3121acafd0b9SEwan D. Milne break; 3122acafd0b9SEwan D. Milne } 3123acafd0b9SEwan D. Milne return 0; 3124acafd0b9SEwan D. Milne } 3125acafd0b9SEwan D. Milne 3126fd32119bSDouglas Gilbert static int resp_comp_write(struct scsi_cmnd *scp, 3127fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 312838d5c833SDouglas Gilbert { 312938d5c833SDouglas Gilbert u8 *cmd = scp->cmnd; 313038d5c833SDouglas Gilbert u8 *arr; 313138d5c833SDouglas Gilbert u8 *fake_storep_hold; 313238d5c833SDouglas Gilbert u64 lba; 313338d5c833SDouglas Gilbert u32 dnum; 3134773642d9SDouglas Gilbert u32 lb_size = sdebug_sector_size; 313538d5c833SDouglas Gilbert u8 num; 313638d5c833SDouglas Gilbert unsigned long iflags; 313738d5c833SDouglas Gilbert int ret; 3138d467d31fSDouglas Gilbert int retval = 0; 313938d5c833SDouglas Gilbert 3140d467d31fSDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 314138d5c833SDouglas Gilbert num = cmd[13]; /* 1 to a maximum of 255 logical blocks */ 314238d5c833SDouglas Gilbert if (0 == num) 314338d5c833SDouglas Gilbert return 0; /* degenerate case, not an error */ 31448475c811SChristoph Hellwig if (sdebug_dif == T10_PI_TYPE2_PROTECTION && 314538d5c833SDouglas Gilbert (cmd[1] & 0xe0)) { 314638d5c833SDouglas Gilbert mk_sense_invalid_opcode(scp); 314738d5c833SDouglas Gilbert return check_condition_result; 314838d5c833SDouglas Gilbert } 31498475c811SChristoph Hellwig if ((sdebug_dif == T10_PI_TYPE1_PROTECTION || 31508475c811SChristoph Hellwig sdebug_dif == T10_PI_TYPE3_PROTECTION) && 315138d5c833SDouglas Gilbert (cmd[1] & 0xe0) == 0) 315238d5c833SDouglas Gilbert sdev_printk(KERN_ERR, scp->device, "Unprotected WR " 315338d5c833SDouglas Gilbert "to DIF device\n"); 315438d5c833SDouglas Gilbert 315538d5c833SDouglas Gilbert /* inline check_device_access_params() */ 315638d5c833SDouglas Gilbert if (lba + num > sdebug_capacity) { 315738d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0); 315838d5c833SDouglas Gilbert return check_condition_result; 315938d5c833SDouglas Gilbert } 316038d5c833SDouglas Gilbert /* transfer length excessive (tie in to block limits VPD page) */ 316138d5c833SDouglas Gilbert if (num > sdebug_store_sectors) { 316238d5c833SDouglas Gilbert /* needs work to find which cdb byte 'num' comes from */ 316338d5c833SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0); 316438d5c833SDouglas Gilbert return check_condition_result; 316538d5c833SDouglas Gilbert } 3166d467d31fSDouglas Gilbert dnum = 2 * num; 3167d467d31fSDouglas Gilbert arr = kzalloc(dnum * lb_size, GFP_ATOMIC); 3168d467d31fSDouglas Gilbert if (NULL == arr) { 3169d467d31fSDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3170d467d31fSDouglas Gilbert INSUFF_RES_ASCQ); 3171d467d31fSDouglas Gilbert return check_condition_result; 3172d467d31fSDouglas Gilbert } 317338d5c833SDouglas Gilbert 317438d5c833SDouglas Gilbert write_lock_irqsave(&atomic_rw, iflags); 317538d5c833SDouglas Gilbert 317638d5c833SDouglas Gilbert /* trick do_device_access() to fetch both compare and write buffers 317738d5c833SDouglas Gilbert * from data-in into arr. Safe (atomic) since write_lock held. */ 317838d5c833SDouglas Gilbert fake_storep_hold = fake_storep; 317938d5c833SDouglas Gilbert fake_storep = arr; 318038d5c833SDouglas Gilbert ret = do_device_access(scp, 0, dnum, true); 318138d5c833SDouglas Gilbert fake_storep = fake_storep_hold; 318238d5c833SDouglas Gilbert if (ret == -1) { 3183d467d31fSDouglas Gilbert retval = DID_ERROR << 16; 3184d467d31fSDouglas Gilbert goto cleanup; 3185773642d9SDouglas Gilbert } else if (sdebug_verbose && (ret < (dnum * lb_size))) 318638d5c833SDouglas Gilbert sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb " 318738d5c833SDouglas Gilbert "indicated=%u, IO sent=%d bytes\n", my_name, 318838d5c833SDouglas Gilbert dnum * lb_size, ret); 318938d5c833SDouglas Gilbert if (!comp_write_worker(lba, num, arr)) { 319038d5c833SDouglas Gilbert mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0); 3191d467d31fSDouglas Gilbert retval = check_condition_result; 3192d467d31fSDouglas Gilbert goto cleanup; 319338d5c833SDouglas Gilbert } 319438d5c833SDouglas Gilbert if (scsi_debug_lbp()) 319538d5c833SDouglas Gilbert map_region(lba, num); 3196d467d31fSDouglas Gilbert cleanup: 319738d5c833SDouglas Gilbert write_unlock_irqrestore(&atomic_rw, iflags); 3198d467d31fSDouglas Gilbert kfree(arr); 3199d467d31fSDouglas Gilbert return retval; 320038d5c833SDouglas Gilbert } 320138d5c833SDouglas Gilbert 320244d92694SMartin K. Petersen struct unmap_block_desc { 320344d92694SMartin K. Petersen __be64 lba; 320444d92694SMartin K. Petersen __be32 blocks; 320544d92694SMartin K. Petersen __be32 __reserved; 320644d92694SMartin K. Petersen }; 320744d92694SMartin K. Petersen 3208fd32119bSDouglas Gilbert static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip) 320944d92694SMartin K. Petersen { 321044d92694SMartin K. Petersen unsigned char *buf; 321144d92694SMartin K. Petersen struct unmap_block_desc *desc; 321244d92694SMartin K. Petersen unsigned int i, payload_len, descriptors; 321344d92694SMartin K. Petersen int ret; 32146c78cc06SAkinobu Mita unsigned long iflags; 321544d92694SMartin K. Petersen 321644d92694SMartin K. Petersen 3217c2248fc9SDouglas Gilbert if (!scsi_debug_lbp()) 3218c2248fc9SDouglas Gilbert return 0; /* fib and say its done */ 3219c2248fc9SDouglas Gilbert payload_len = get_unaligned_be16(scp->cmnd + 7); 3220c2248fc9SDouglas Gilbert BUG_ON(scsi_bufflen(scp) != payload_len); 322144d92694SMartin K. Petersen 322244d92694SMartin K. Petersen descriptors = (payload_len - 8) / 16; 3223773642d9SDouglas Gilbert if (descriptors > sdebug_unmap_max_desc) { 3224c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1); 322544d92694SMartin K. Petersen return check_condition_result; 3226c2248fc9SDouglas Gilbert } 322744d92694SMartin K. Petersen 3228b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3229c2248fc9SDouglas Gilbert if (!buf) { 3230c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3231c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3232c2248fc9SDouglas Gilbert return check_condition_result; 3233c2248fc9SDouglas Gilbert } 3234c2248fc9SDouglas Gilbert 3235c2248fc9SDouglas Gilbert scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 323644d92694SMartin K. Petersen 323744d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2); 323844d92694SMartin K. Petersen BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16); 323944d92694SMartin K. Petersen 324044d92694SMartin K. Petersen desc = (void *)&buf[8]; 324144d92694SMartin K. Petersen 32426c78cc06SAkinobu Mita write_lock_irqsave(&atomic_rw, iflags); 32436c78cc06SAkinobu Mita 324444d92694SMartin K. Petersen for (i = 0 ; i < descriptors ; i++) { 324544d92694SMartin K. Petersen unsigned long long lba = get_unaligned_be64(&desc[i].lba); 324644d92694SMartin K. Petersen unsigned int num = get_unaligned_be32(&desc[i].blocks); 324744d92694SMartin K. Petersen 3248c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, num); 324944d92694SMartin K. Petersen if (ret) 325044d92694SMartin K. Petersen goto out; 325144d92694SMartin K. Petersen 325244d92694SMartin K. Petersen unmap_region(lba, num); 325344d92694SMartin K. Petersen } 325444d92694SMartin K. Petersen 325544d92694SMartin K. Petersen ret = 0; 325644d92694SMartin K. Petersen 325744d92694SMartin K. Petersen out: 32586c78cc06SAkinobu Mita write_unlock_irqrestore(&atomic_rw, iflags); 325944d92694SMartin K. Petersen kfree(buf); 326044d92694SMartin K. Petersen 326144d92694SMartin K. Petersen return ret; 326244d92694SMartin K. Petersen } 326344d92694SMartin K. Petersen 326444d92694SMartin K. Petersen #define SDEBUG_GET_LBA_STATUS_LEN 32 326544d92694SMartin K. Petersen 3266fd32119bSDouglas Gilbert static int resp_get_lba_status(struct scsi_cmnd *scp, 3267fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 326844d92694SMartin K. Petersen { 3269c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3270c2248fc9SDouglas Gilbert u64 lba; 3271c2248fc9SDouglas Gilbert u32 alloc_len, mapped, num; 3272c2248fc9SDouglas Gilbert u8 arr[SDEBUG_GET_LBA_STATUS_LEN]; 327344d92694SMartin K. Petersen int ret; 327444d92694SMartin K. Petersen 3275c2248fc9SDouglas Gilbert lba = get_unaligned_be64(cmd + 2); 3276c2248fc9SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 10); 327744d92694SMartin K. Petersen 327844d92694SMartin K. Petersen if (alloc_len < 24) 327944d92694SMartin K. Petersen return 0; 328044d92694SMartin K. Petersen 3281c2248fc9SDouglas Gilbert ret = check_device_access_params(scp, lba, 1); 328244d92694SMartin K. Petersen if (ret) 328344d92694SMartin K. Petersen return ret; 328444d92694SMartin K. Petersen 3285c2248fc9SDouglas Gilbert if (scsi_debug_lbp()) 328644d92694SMartin K. Petersen mapped = map_state(lba, &num); 3287c2248fc9SDouglas Gilbert else { 3288c2248fc9SDouglas Gilbert mapped = 1; 3289c2248fc9SDouglas Gilbert /* following just in case virtual_gb changed */ 3290c2248fc9SDouglas Gilbert sdebug_capacity = get_sdebug_capacity(); 3291c2248fc9SDouglas Gilbert if (sdebug_capacity - lba <= 0xffffffff) 3292c2248fc9SDouglas Gilbert num = sdebug_capacity - lba; 3293c2248fc9SDouglas Gilbert else 3294c2248fc9SDouglas Gilbert num = 0xffffffff; 3295c2248fc9SDouglas Gilbert } 329644d92694SMartin K. Petersen 329744d92694SMartin K. Petersen memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN); 3298c2248fc9SDouglas Gilbert put_unaligned_be32(20, arr); /* Parameter Data Length */ 3299c2248fc9SDouglas Gilbert put_unaligned_be64(lba, arr + 8); /* LBA */ 3300c2248fc9SDouglas Gilbert put_unaligned_be32(num, arr + 16); /* Number of blocks */ 3301c2248fc9SDouglas Gilbert arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */ 330244d92694SMartin K. Petersen 3303c2248fc9SDouglas Gilbert return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN); 330444d92694SMartin K. Petersen } 330544d92694SMartin K. Petersen 3306fb0cc8d1SDouglas Gilbert #define RL_BUCKET_ELEMS 8 3307fb0cc8d1SDouglas Gilbert 33088d039e22SDouglas Gilbert /* Even though each pseudo target has a REPORT LUNS "well known logical unit" 33098d039e22SDouglas Gilbert * (W-LUN), the normal Linux scanning logic does not associate it with a 33108d039e22SDouglas Gilbert * device (e.g. /dev/sg7). The following magic will make that association: 33118d039e22SDouglas Gilbert * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan" 33128d039e22SDouglas Gilbert * where <n> is a host number. If there are multiple targets in a host then 33138d039e22SDouglas Gilbert * the above will associate a W-LUN to each target. To only get a W-LUN 33148d039e22SDouglas Gilbert * for target 2, then use "echo '- 2 49409' > scan" . 33158d039e22SDouglas Gilbert */ 33161da177e4SLinus Torvalds static int resp_report_luns(struct scsi_cmnd *scp, 33171da177e4SLinus Torvalds struct sdebug_dev_info *devip) 33181da177e4SLinus Torvalds { 331901123ef4SDouglas Gilbert unsigned char *cmd = scp->cmnd; 33208d039e22SDouglas Gilbert unsigned int alloc_len; 33218d039e22SDouglas Gilbert unsigned char select_report; 33228d039e22SDouglas Gilbert u64 lun; 33238d039e22SDouglas Gilbert struct scsi_lun *lun_p; 3324fb0cc8d1SDouglas Gilbert u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)]; 33258d039e22SDouglas Gilbert unsigned int lun_cnt; /* normal LUN count (max: 256) */ 33268d039e22SDouglas Gilbert unsigned int wlun_cnt; /* report luns W-LUN count */ 33278d039e22SDouglas Gilbert unsigned int tlun_cnt; /* total LUN count */ 33288d039e22SDouglas Gilbert unsigned int rlen; /* response length (in bytes) */ 3329fb0cc8d1SDouglas Gilbert int k, j, n, res; 3330fb0cc8d1SDouglas Gilbert unsigned int off_rsp = 0; 3331fb0cc8d1SDouglas Gilbert const int sz_lun = sizeof(struct scsi_lun); 33321da177e4SLinus Torvalds 333319c8ead7SEwan D. Milne clear_luns_changed_on_target(devip); 33348d039e22SDouglas Gilbert 33358d039e22SDouglas Gilbert select_report = cmd[2]; 33368d039e22SDouglas Gilbert alloc_len = get_unaligned_be32(cmd + 6); 33378d039e22SDouglas Gilbert 33388d039e22SDouglas Gilbert if (alloc_len < 4) { 33398d039e22SDouglas Gilbert pr_err("alloc len too small %d\n", alloc_len); 33408d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1); 33411da177e4SLinus Torvalds return check_condition_result; 33421da177e4SLinus Torvalds } 33438d039e22SDouglas Gilbert 33448d039e22SDouglas Gilbert switch (select_report) { 33458d039e22SDouglas Gilbert case 0: /* all LUNs apart from W-LUNs */ 3346773642d9SDouglas Gilbert lun_cnt = sdebug_max_luns; 33478d039e22SDouglas Gilbert wlun_cnt = 0; 33488d039e22SDouglas Gilbert break; 33498d039e22SDouglas Gilbert case 1: /* only W-LUNs */ 3350c65b1445SDouglas Gilbert lun_cnt = 0; 33518d039e22SDouglas Gilbert wlun_cnt = 1; 33528d039e22SDouglas Gilbert break; 33538d039e22SDouglas Gilbert case 2: /* all LUNs */ 33548d039e22SDouglas Gilbert lun_cnt = sdebug_max_luns; 33558d039e22SDouglas Gilbert wlun_cnt = 1; 33568d039e22SDouglas Gilbert break; 33578d039e22SDouglas Gilbert case 0x10: /* only administrative LUs */ 33588d039e22SDouglas Gilbert case 0x11: /* see SPC-5 */ 33598d039e22SDouglas Gilbert case 0x12: /* only subsiduary LUs owned by referenced LU */ 33608d039e22SDouglas Gilbert default: 33618d039e22SDouglas Gilbert pr_debug("select report invalid %d\n", select_report); 33628d039e22SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1); 33638d039e22SDouglas Gilbert return check_condition_result; 33648d039e22SDouglas Gilbert } 33658d039e22SDouglas Gilbert 33668d039e22SDouglas Gilbert if (sdebug_no_lun_0 && (lun_cnt > 0)) 3367c65b1445SDouglas Gilbert --lun_cnt; 33688d039e22SDouglas Gilbert 33698d039e22SDouglas Gilbert tlun_cnt = lun_cnt + wlun_cnt; 3370fb0cc8d1SDouglas Gilbert rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */ 3371fb0cc8d1SDouglas Gilbert scsi_set_resid(scp, scsi_bufflen(scp)); 33728d039e22SDouglas Gilbert pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n", 33738d039e22SDouglas Gilbert select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0); 33748d039e22SDouglas Gilbert 3375fb0cc8d1SDouglas Gilbert /* loops rely on sizeof response header same as sizeof lun (both 8) */ 33768d039e22SDouglas Gilbert lun = sdebug_no_lun_0 ? 1 : 0; 3377fb0cc8d1SDouglas Gilbert for (k = 0, j = 0, res = 0; true; ++k, j = 0) { 3378fb0cc8d1SDouglas Gilbert memset(arr, 0, sizeof(arr)); 3379fb0cc8d1SDouglas Gilbert lun_p = (struct scsi_lun *)&arr[0]; 3380fb0cc8d1SDouglas Gilbert if (k == 0) { 3381fb0cc8d1SDouglas Gilbert put_unaligned_be32(rlen, &arr[0]); 3382fb0cc8d1SDouglas Gilbert ++lun_p; 3383fb0cc8d1SDouglas Gilbert j = 1; 3384fb0cc8d1SDouglas Gilbert } 3385fb0cc8d1SDouglas Gilbert for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) { 3386fb0cc8d1SDouglas Gilbert if ((k * RL_BUCKET_ELEMS) + j > lun_cnt) 3387fb0cc8d1SDouglas Gilbert break; 3388fb0cc8d1SDouglas Gilbert int_to_scsilun(lun++, lun_p); 3389fb0cc8d1SDouglas Gilbert } 3390fb0cc8d1SDouglas Gilbert if (j < RL_BUCKET_ELEMS) 3391fb0cc8d1SDouglas Gilbert break; 3392fb0cc8d1SDouglas Gilbert n = j * sz_lun; 3393fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, n, off_rsp); 3394fb0cc8d1SDouglas Gilbert if (res) 3395fb0cc8d1SDouglas Gilbert return res; 3396fb0cc8d1SDouglas Gilbert off_rsp += n; 3397fb0cc8d1SDouglas Gilbert } 3398fb0cc8d1SDouglas Gilbert if (wlun_cnt) { 3399fb0cc8d1SDouglas Gilbert int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p); 3400fb0cc8d1SDouglas Gilbert ++j; 3401fb0cc8d1SDouglas Gilbert } 3402fb0cc8d1SDouglas Gilbert if (j > 0) 3403fb0cc8d1SDouglas Gilbert res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp); 34048d039e22SDouglas Gilbert return res; 34051da177e4SLinus Torvalds } 34061da177e4SLinus Torvalds 3407c639d14eSFUJITA Tomonori static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba, 3408c639d14eSFUJITA Tomonori unsigned int num, struct sdebug_dev_info *devip) 3409c639d14eSFUJITA Tomonori { 3410be4e11beSAkinobu Mita int j; 3411c639d14eSFUJITA Tomonori unsigned char *kaddr, *buf; 3412c639d14eSFUJITA Tomonori unsigned int offset; 3413c639d14eSFUJITA Tomonori struct scsi_data_buffer *sdb = scsi_in(scp); 3414be4e11beSAkinobu Mita struct sg_mapping_iter miter; 3415c639d14eSFUJITA Tomonori 3416c639d14eSFUJITA Tomonori /* better not to use temporary buffer. */ 3417b333a819SDouglas Gilbert buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC); 3418c5af0db9SAkinobu Mita if (!buf) { 341922017ed2SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 342022017ed2SDouglas Gilbert INSUFF_RES_ASCQ); 3421c5af0db9SAkinobu Mita return check_condition_result; 3422c5af0db9SAkinobu Mita } 3423c639d14eSFUJITA Tomonori 342421a61829SFUJITA Tomonori scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp)); 3425c639d14eSFUJITA Tomonori 3426c639d14eSFUJITA Tomonori offset = 0; 3427be4e11beSAkinobu Mita sg_miter_start(&miter, sdb->table.sgl, sdb->table.nents, 3428be4e11beSAkinobu Mita SG_MITER_ATOMIC | SG_MITER_TO_SG); 3429c639d14eSFUJITA Tomonori 3430be4e11beSAkinobu Mita while (sg_miter_next(&miter)) { 3431be4e11beSAkinobu Mita kaddr = miter.addr; 3432be4e11beSAkinobu Mita for (j = 0; j < miter.length; j++) 3433be4e11beSAkinobu Mita *(kaddr + j) ^= *(buf + offset + j); 3434c639d14eSFUJITA Tomonori 3435be4e11beSAkinobu Mita offset += miter.length; 3436c639d14eSFUJITA Tomonori } 3437be4e11beSAkinobu Mita sg_miter_stop(&miter); 3438c639d14eSFUJITA Tomonori kfree(buf); 3439c639d14eSFUJITA Tomonori 3440be4e11beSAkinobu Mita return 0; 3441c639d14eSFUJITA Tomonori } 3442c639d14eSFUJITA Tomonori 3443fd32119bSDouglas Gilbert static int resp_xdwriteread_10(struct scsi_cmnd *scp, 3444fd32119bSDouglas Gilbert struct sdebug_dev_info *devip) 3445c2248fc9SDouglas Gilbert { 3446c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 3447c2248fc9SDouglas Gilbert u64 lba; 3448c2248fc9SDouglas Gilbert u32 num; 3449c2248fc9SDouglas Gilbert int errsts; 3450c2248fc9SDouglas Gilbert 3451c2248fc9SDouglas Gilbert if (!scsi_bidi_cmnd(scp)) { 3452c2248fc9SDouglas Gilbert mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC, 3453c2248fc9SDouglas Gilbert INSUFF_RES_ASCQ); 3454c2248fc9SDouglas Gilbert return check_condition_result; 3455c2248fc9SDouglas Gilbert } 3456c2248fc9SDouglas Gilbert errsts = resp_read_dt0(scp, devip); 3457c2248fc9SDouglas Gilbert if (errsts) 3458c2248fc9SDouglas Gilbert return errsts; 3459c2248fc9SDouglas Gilbert if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */ 3460c2248fc9SDouglas Gilbert errsts = resp_write_dt0(scp, devip); 3461c2248fc9SDouglas Gilbert if (errsts) 3462c2248fc9SDouglas Gilbert return errsts; 3463c2248fc9SDouglas Gilbert } 3464c2248fc9SDouglas Gilbert lba = get_unaligned_be32(cmd + 2); 3465c2248fc9SDouglas Gilbert num = get_unaligned_be16(cmd + 7); 3466c2248fc9SDouglas Gilbert return resp_xdwriteread(scp, lba, num, devip); 3467c2248fc9SDouglas Gilbert } 3468c2248fc9SDouglas Gilbert 3469c4837394SDouglas Gilbert static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd) 3470c4837394SDouglas Gilbert { 3471c4837394SDouglas Gilbert struct sdebug_queue *sqp = sdebug_q_arr; 3472c4837394SDouglas Gilbert 3473c4837394SDouglas Gilbert if (sdebug_mq_active) { 3474c4837394SDouglas Gilbert u32 tag = blk_mq_unique_tag(cmnd->request); 3475c4837394SDouglas Gilbert u16 hwq = blk_mq_unique_tag_to_hwq(tag); 3476c4837394SDouglas Gilbert 3477c4837394SDouglas Gilbert if (unlikely(hwq >= submit_queues)) { 3478c4837394SDouglas Gilbert pr_warn("Unexpected hwq=%d, apply modulo\n", hwq); 3479c4837394SDouglas Gilbert hwq %= submit_queues; 3480c4837394SDouglas Gilbert } 3481c4837394SDouglas Gilbert pr_debug("tag=%u, hwq=%d\n", tag, hwq); 3482c4837394SDouglas Gilbert return sqp + hwq; 3483c4837394SDouglas Gilbert } else 3484c4837394SDouglas Gilbert return sqp; 3485c4837394SDouglas Gilbert } 3486c4837394SDouglas Gilbert 3487c4837394SDouglas Gilbert /* Queued (deferred) command completions converge here. */ 3488fd32119bSDouglas Gilbert static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp) 34891da177e4SLinus Torvalds { 3490c4837394SDouglas Gilbert int qc_idx; 3491cbf67842SDouglas Gilbert int retiring = 0; 34921da177e4SLinus Torvalds unsigned long iflags; 3493c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3494cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3495cbf67842SDouglas Gilbert struct scsi_cmnd *scp; 3496cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 34971da177e4SLinus Torvalds 3498c4837394SDouglas Gilbert qc_idx = sd_dp->qc_idx; 3499c4837394SDouglas Gilbert sqp = sdebug_q_arr + sd_dp->sqa_idx; 3500c4837394SDouglas Gilbert if (sdebug_statistics) { 3501cbf67842SDouglas Gilbert atomic_inc(&sdebug_completions); 3502c4837394SDouglas Gilbert if (raw_smp_processor_id() != sd_dp->issuing_cpu) 3503c4837394SDouglas Gilbert atomic_inc(&sdebug_miss_cpus); 3504c4837394SDouglas Gilbert } 3505c4837394SDouglas Gilbert if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) { 3506c4837394SDouglas Gilbert pr_err("wild qc_idx=%d\n", qc_idx); 35071da177e4SLinus Torvalds return; 35081da177e4SLinus Torvalds } 3509c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3510c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[qc_idx]; 3511cbf67842SDouglas Gilbert scp = sqcp->a_cmnd; 3512b01f6f83SDouglas Gilbert if (unlikely(scp == NULL)) { 3513c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3514c4837394SDouglas Gilbert pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n", 3515c4837394SDouglas Gilbert sd_dp->sqa_idx, qc_idx); 35161da177e4SLinus Torvalds return; 35171da177e4SLinus Torvalds } 3518cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)scp->device->hostdata; 3519f46eb0e9SDouglas Gilbert if (likely(devip)) 3520cbf67842SDouglas Gilbert atomic_dec(&devip->num_in_q); 3521cbf67842SDouglas Gilbert else 3522c1287970STomas Winkler pr_err("devip=NULL\n"); 3523f46eb0e9SDouglas Gilbert if (unlikely(atomic_read(&retired_max_queue) > 0)) 3524cbf67842SDouglas Gilbert retiring = 1; 3525cbf67842SDouglas Gilbert 3526cbf67842SDouglas Gilbert sqcp->a_cmnd = NULL; 3527c4837394SDouglas Gilbert if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) { 3528c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3529c1287970STomas Winkler pr_err("Unexpected completion\n"); 3530cbf67842SDouglas Gilbert return; 35311da177e4SLinus Torvalds } 35321da177e4SLinus Torvalds 3533cbf67842SDouglas Gilbert if (unlikely(retiring)) { /* user has reduced max_queue */ 3534cbf67842SDouglas Gilbert int k, retval; 3535cbf67842SDouglas Gilbert 3536cbf67842SDouglas Gilbert retval = atomic_read(&retired_max_queue); 3537c4837394SDouglas Gilbert if (qc_idx >= retval) { 3538c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3539c1287970STomas Winkler pr_err("index %d too large\n", retval); 3540cbf67842SDouglas Gilbert return; 3541cbf67842SDouglas Gilbert } 3542c4837394SDouglas Gilbert k = find_last_bit(sqp->in_use_bm, retval); 3543773642d9SDouglas Gilbert if ((k < sdebug_max_queue) || (k == retval)) 3544cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 3545cbf67842SDouglas Gilbert else 3546cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 3547cbf67842SDouglas Gilbert } 3548c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3549cbf67842SDouglas Gilbert scp->scsi_done(scp); /* callback to mid level */ 3550cbf67842SDouglas Gilbert } 3551cbf67842SDouglas Gilbert 3552cbf67842SDouglas Gilbert /* When high resolution timer goes off this function is called. */ 3553fd32119bSDouglas Gilbert static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer) 3554cbf67842SDouglas Gilbert { 3555a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer, 3556a10bc12aSDouglas Gilbert hrt); 3557a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3558cbf67842SDouglas Gilbert return HRTIMER_NORESTART; 3559cbf67842SDouglas Gilbert } 35601da177e4SLinus Torvalds 3561a10bc12aSDouglas Gilbert /* When work queue schedules work, it calls this function. */ 3562fd32119bSDouglas Gilbert static void sdebug_q_cmd_wq_complete(struct work_struct *work) 3563a10bc12aSDouglas Gilbert { 3564a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer, 3565a10bc12aSDouglas Gilbert ew.work); 3566a10bc12aSDouglas Gilbert sdebug_q_cmd_complete(sd_dp); 3567a10bc12aSDouglas Gilbert } 3568a10bc12aSDouglas Gilbert 356909ba24c1SDouglas Gilbert static bool got_shared_uuid; 3570bf476433SChristoph Hellwig static uuid_t shared_uuid; 357109ba24c1SDouglas Gilbert 3572fd32119bSDouglas Gilbert static struct sdebug_dev_info *sdebug_device_create( 3573fd32119bSDouglas Gilbert struct sdebug_host_info *sdbg_host, gfp_t flags) 35745cb2fc06SFUJITA Tomonori { 35755cb2fc06SFUJITA Tomonori struct sdebug_dev_info *devip; 35765cb2fc06SFUJITA Tomonori 35775cb2fc06SFUJITA Tomonori devip = kzalloc(sizeof(*devip), flags); 35785cb2fc06SFUJITA Tomonori if (devip) { 357909ba24c1SDouglas Gilbert if (sdebug_uuid_ctl == 1) 3580bf476433SChristoph Hellwig uuid_gen(&devip->lu_name); 358109ba24c1SDouglas Gilbert else if (sdebug_uuid_ctl == 2) { 358209ba24c1SDouglas Gilbert if (got_shared_uuid) 358309ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 358409ba24c1SDouglas Gilbert else { 3585bf476433SChristoph Hellwig uuid_gen(&shared_uuid); 358609ba24c1SDouglas Gilbert got_shared_uuid = true; 358709ba24c1SDouglas Gilbert devip->lu_name = shared_uuid; 358809ba24c1SDouglas Gilbert } 358909ba24c1SDouglas Gilbert } 35905cb2fc06SFUJITA Tomonori devip->sdbg_host = sdbg_host; 35915cb2fc06SFUJITA Tomonori list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list); 35925cb2fc06SFUJITA Tomonori } 35935cb2fc06SFUJITA Tomonori return devip; 35945cb2fc06SFUJITA Tomonori } 35955cb2fc06SFUJITA Tomonori 3596f46eb0e9SDouglas Gilbert static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev) 35971da177e4SLinus Torvalds { 35981da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 35991da177e4SLinus Torvalds struct sdebug_dev_info *open_devip = NULL; 3600f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip; 36011da177e4SLinus Torvalds 3602d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host); 36031da177e4SLinus Torvalds if (!sdbg_host) { 3604c1287970STomas Winkler pr_err("Host info NULL\n"); 36051da177e4SLinus Torvalds return NULL; 36061da177e4SLinus Torvalds } 36071da177e4SLinus Torvalds list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) { 36081da177e4SLinus Torvalds if ((devip->used) && (devip->channel == sdev->channel) && 36091da177e4SLinus Torvalds (devip->target == sdev->id) && 36101da177e4SLinus Torvalds (devip->lun == sdev->lun)) 36111da177e4SLinus Torvalds return devip; 36121da177e4SLinus Torvalds else { 36131da177e4SLinus Torvalds if ((!devip->used) && (!open_devip)) 36141da177e4SLinus Torvalds open_devip = devip; 36151da177e4SLinus Torvalds } 36161da177e4SLinus Torvalds } 36175cb2fc06SFUJITA Tomonori if (!open_devip) { /* try and make a new one */ 36185cb2fc06SFUJITA Tomonori open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC); 36195cb2fc06SFUJITA Tomonori if (!open_devip) { 3620c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 36211da177e4SLinus Torvalds return NULL; 36221da177e4SLinus Torvalds } 36231da177e4SLinus Torvalds } 3624a75869d1SFUJITA Tomonori 36251da177e4SLinus Torvalds open_devip->channel = sdev->channel; 36261da177e4SLinus Torvalds open_devip->target = sdev->id; 36271da177e4SLinus Torvalds open_devip->lun = sdev->lun; 36281da177e4SLinus Torvalds open_devip->sdbg_host = sdbg_host; 3629cbf67842SDouglas Gilbert atomic_set(&open_devip->num_in_q, 0); 3630cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, open_devip->uas_bm); 3631c2248fc9SDouglas Gilbert open_devip->used = true; 36321da177e4SLinus Torvalds return open_devip; 36331da177e4SLinus Torvalds } 36341da177e4SLinus Torvalds 36358dea0d02SFUJITA Tomonori static int scsi_debug_slave_alloc(struct scsi_device *sdp) 36361da177e4SLinus Torvalds { 3637773642d9SDouglas Gilbert if (sdebug_verbose) 3638c1287970STomas Winkler pr_info("slave_alloc <%u %u %u %llu>\n", 36398dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 364075ad23bcSNick Piggin queue_flag_set_unlocked(QUEUE_FLAG_BIDI, sdp->request_queue); 36418dea0d02SFUJITA Tomonori return 0; 36428dea0d02SFUJITA Tomonori } 36431da177e4SLinus Torvalds 36448dea0d02SFUJITA Tomonori static int scsi_debug_slave_configure(struct scsi_device *sdp) 36458dea0d02SFUJITA Tomonori { 3646f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3647f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3648a34c4e98SFUJITA Tomonori 3649773642d9SDouglas Gilbert if (sdebug_verbose) 3650c1287970STomas Winkler pr_info("slave_configure <%u %u %u %llu>\n", 36518dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 3652b01f6f83SDouglas Gilbert if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN) 3653b01f6f83SDouglas Gilbert sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN; 3654b01f6f83SDouglas Gilbert if (devip == NULL) { 3655f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 3656b01f6f83SDouglas Gilbert if (devip == NULL) 36578dea0d02SFUJITA Tomonori return 1; /* no resources, will be marked offline */ 3658f46eb0e9SDouglas Gilbert } 3659c8b09f6fSChristoph Hellwig sdp->hostdata = devip; 36606bb5e6e7SAkinobu Mita blk_queue_max_segment_size(sdp->request_queue, -1U); 3661773642d9SDouglas Gilbert if (sdebug_no_uld) 366278d4e5a0SDouglas Gilbert sdp->no_uld_attach = 1; 36638dea0d02SFUJITA Tomonori return 0; 36648dea0d02SFUJITA Tomonori } 36658dea0d02SFUJITA Tomonori 36668dea0d02SFUJITA Tomonori static void scsi_debug_slave_destroy(struct scsi_device *sdp) 36678dea0d02SFUJITA Tomonori { 36688dea0d02SFUJITA Tomonori struct sdebug_dev_info *devip = 36698dea0d02SFUJITA Tomonori (struct sdebug_dev_info *)sdp->hostdata; 36708dea0d02SFUJITA Tomonori 3671773642d9SDouglas Gilbert if (sdebug_verbose) 3672c1287970STomas Winkler pr_info("slave_destroy <%u %u %u %llu>\n", 36738dea0d02SFUJITA Tomonori sdp->host->host_no, sdp->channel, sdp->id, sdp->lun); 36748dea0d02SFUJITA Tomonori if (devip) { 367525985edcSLucas De Marchi /* make this slot available for re-use */ 3676c2248fc9SDouglas Gilbert devip->used = false; 36778dea0d02SFUJITA Tomonori sdp->hostdata = NULL; 36788dea0d02SFUJITA Tomonori } 36798dea0d02SFUJITA Tomonori } 36808dea0d02SFUJITA Tomonori 3681c4837394SDouglas Gilbert static void stop_qc_helper(struct sdebug_defer *sd_dp) 3682c4837394SDouglas Gilbert { 3683c4837394SDouglas Gilbert if (!sd_dp) 3684c4837394SDouglas Gilbert return; 3685c4837394SDouglas Gilbert if ((sdebug_jdelay > 0) || (sdebug_ndelay > 0)) 3686c4837394SDouglas Gilbert hrtimer_cancel(&sd_dp->hrt); 3687c4837394SDouglas Gilbert else if (sdebug_jdelay < 0) 3688c4837394SDouglas Gilbert cancel_work_sync(&sd_dp->ew.work); 3689c4837394SDouglas Gilbert } 3690c4837394SDouglas Gilbert 3691a10bc12aSDouglas Gilbert /* If @cmnd found deletes its timer or work queue and returns true; else 3692a10bc12aSDouglas Gilbert returns false */ 3693a10bc12aSDouglas Gilbert static bool stop_queued_cmnd(struct scsi_cmnd *cmnd) 36948dea0d02SFUJITA Tomonori { 36958dea0d02SFUJITA Tomonori unsigned long iflags; 3696c4837394SDouglas Gilbert int j, k, qmax, r_qmax; 3697c4837394SDouglas Gilbert struct sdebug_queue *sqp; 36988dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3699cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3700a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 37018dea0d02SFUJITA Tomonori 3702c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3703c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3704773642d9SDouglas Gilbert qmax = sdebug_max_queue; 3705cbf67842SDouglas Gilbert r_qmax = atomic_read(&retired_max_queue); 3706cbf67842SDouglas Gilbert if (r_qmax > qmax) 3707cbf67842SDouglas Gilbert qmax = r_qmax; 3708cbf67842SDouglas Gilbert for (k = 0; k < qmax; ++k) { 3709c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3710c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3711a10bc12aSDouglas Gilbert if (cmnd != sqcp->a_cmnd) 3712a10bc12aSDouglas Gilbert continue; 3713c4837394SDouglas Gilbert /* found */ 3714db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3715db525fceSDouglas Gilbert cmnd->device->hostdata; 3716db525fceSDouglas Gilbert if (devip) 3717db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3718db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3719a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3720c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3721c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3722c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3723a10bc12aSDouglas Gilbert return true; 37248dea0d02SFUJITA Tomonori } 3725cbf67842SDouglas Gilbert } 3726c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3727c4837394SDouglas Gilbert } 3728a10bc12aSDouglas Gilbert return false; 37298dea0d02SFUJITA Tomonori } 37308dea0d02SFUJITA Tomonori 3731a10bc12aSDouglas Gilbert /* Deletes (stops) timers or work queues of all queued commands */ 37328dea0d02SFUJITA Tomonori static void stop_all_queued(void) 37338dea0d02SFUJITA Tomonori { 37348dea0d02SFUJITA Tomonori unsigned long iflags; 3735c4837394SDouglas Gilbert int j, k; 3736c4837394SDouglas Gilbert struct sdebug_queue *sqp; 37378dea0d02SFUJITA Tomonori struct sdebug_queued_cmd *sqcp; 3738cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3739a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 37408dea0d02SFUJITA Tomonori 3741c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3742c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 3743c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3744c4837394SDouglas Gilbert if (test_bit(k, sqp->in_use_bm)) { 3745c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3746c4837394SDouglas Gilbert if (sqcp->a_cmnd == NULL) 3747a10bc12aSDouglas Gilbert continue; 3748db525fceSDouglas Gilbert devip = (struct sdebug_dev_info *) 3749db525fceSDouglas Gilbert sqcp->a_cmnd->device->hostdata; 3750db525fceSDouglas Gilbert if (devip) 3751db525fceSDouglas Gilbert atomic_dec(&devip->num_in_q); 3752db525fceSDouglas Gilbert sqcp->a_cmnd = NULL; 3753a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 3754c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3755c4837394SDouglas Gilbert stop_qc_helper(sd_dp); 3756c4837394SDouglas Gilbert clear_bit(k, sqp->in_use_bm); 3757c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 37588dea0d02SFUJITA Tomonori } 37598dea0d02SFUJITA Tomonori } 3760c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 3761c4837394SDouglas Gilbert } 3762cbf67842SDouglas Gilbert } 3763cbf67842SDouglas Gilbert 3764cbf67842SDouglas Gilbert /* Free queued command memory on heap */ 3765cbf67842SDouglas Gilbert static void free_all_queued(void) 3766cbf67842SDouglas Gilbert { 3767c4837394SDouglas Gilbert int j, k; 3768c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3769cbf67842SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 3770cbf67842SDouglas Gilbert 3771c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 3772c4837394SDouglas Gilbert for (k = 0; k < SDEBUG_CANQUEUE; ++k) { 3773c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 3774a10bc12aSDouglas Gilbert kfree(sqcp->sd_dp); 3775a10bc12aSDouglas Gilbert sqcp->sd_dp = NULL; 3776cbf67842SDouglas Gilbert } 37771da177e4SLinus Torvalds } 3778c4837394SDouglas Gilbert } 37791da177e4SLinus Torvalds 37801da177e4SLinus Torvalds static int scsi_debug_abort(struct scsi_cmnd *SCpnt) 37811da177e4SLinus Torvalds { 3782a10bc12aSDouglas Gilbert bool ok; 3783a10bc12aSDouglas Gilbert 37841da177e4SLinus Torvalds ++num_aborts; 3785cbf67842SDouglas Gilbert if (SCpnt) { 3786a10bc12aSDouglas Gilbert ok = stop_queued_cmnd(SCpnt); 3787a10bc12aSDouglas Gilbert if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3788a10bc12aSDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3789a10bc12aSDouglas Gilbert "%s: command%s found\n", __func__, 3790a10bc12aSDouglas Gilbert ok ? "" : " not"); 3791cbf67842SDouglas Gilbert } 37921da177e4SLinus Torvalds return SUCCESS; 37931da177e4SLinus Torvalds } 37941da177e4SLinus Torvalds 37951da177e4SLinus Torvalds static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt) 37961da177e4SLinus Torvalds { 37971da177e4SLinus Torvalds ++num_dev_resets; 3798cbf67842SDouglas Gilbert if (SCpnt && SCpnt->device) { 3799cbf67842SDouglas Gilbert struct scsi_device *sdp = SCpnt->device; 3800f46eb0e9SDouglas Gilbert struct sdebug_dev_info *devip = 3801f46eb0e9SDouglas Gilbert (struct sdebug_dev_info *)sdp->hostdata; 3802cbf67842SDouglas Gilbert 3803773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3804cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 38051da177e4SLinus Torvalds if (devip) 3806cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_POR, devip->uas_bm); 38071da177e4SLinus Torvalds } 38081da177e4SLinus Torvalds return SUCCESS; 38091da177e4SLinus Torvalds } 38101da177e4SLinus Torvalds 3811cbf67842SDouglas Gilbert static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt) 3812cbf67842SDouglas Gilbert { 3813cbf67842SDouglas Gilbert struct sdebug_host_info *sdbg_host; 3814cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3815cbf67842SDouglas Gilbert struct scsi_device *sdp; 3816cbf67842SDouglas Gilbert struct Scsi_Host *hp; 3817cbf67842SDouglas Gilbert int k = 0; 3818cbf67842SDouglas Gilbert 3819cbf67842SDouglas Gilbert ++num_target_resets; 3820cbf67842SDouglas Gilbert if (!SCpnt) 3821cbf67842SDouglas Gilbert goto lie; 3822cbf67842SDouglas Gilbert sdp = SCpnt->device; 3823cbf67842SDouglas Gilbert if (!sdp) 3824cbf67842SDouglas Gilbert goto lie; 3825773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3826cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3827cbf67842SDouglas Gilbert hp = sdp->host; 3828cbf67842SDouglas Gilbert if (!hp) 3829cbf67842SDouglas Gilbert goto lie; 3830cbf67842SDouglas Gilbert sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 3831cbf67842SDouglas Gilbert if (sdbg_host) { 3832cbf67842SDouglas Gilbert list_for_each_entry(devip, 3833cbf67842SDouglas Gilbert &sdbg_host->dev_info_list, 3834cbf67842SDouglas Gilbert dev_list) 3835cbf67842SDouglas Gilbert if (devip->target == sdp->id) { 3836cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3837cbf67842SDouglas Gilbert ++k; 3838cbf67842SDouglas Gilbert } 3839cbf67842SDouglas Gilbert } 3840773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3841cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3842cbf67842SDouglas Gilbert "%s: %d device(s) found in target\n", __func__, k); 3843cbf67842SDouglas Gilbert lie: 3844cbf67842SDouglas Gilbert return SUCCESS; 3845cbf67842SDouglas Gilbert } 3846cbf67842SDouglas Gilbert 38471da177e4SLinus Torvalds static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt) 38481da177e4SLinus Torvalds { 38491da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 3850cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 38511da177e4SLinus Torvalds struct scsi_device * sdp; 38521da177e4SLinus Torvalds struct Scsi_Host * hp; 3853cbf67842SDouglas Gilbert int k = 0; 38541da177e4SLinus Torvalds 38551da177e4SLinus Torvalds ++num_bus_resets; 3856cbf67842SDouglas Gilbert if (!(SCpnt && SCpnt->device)) 3857cbf67842SDouglas Gilbert goto lie; 3858cbf67842SDouglas Gilbert sdp = SCpnt->device; 3859773642d9SDouglas Gilbert if (SDEBUG_OPT_ALL_NOISE & sdebug_opts) 3860cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s\n", __func__); 3861cbf67842SDouglas Gilbert hp = sdp->host; 3862cbf67842SDouglas Gilbert if (hp) { 3863d1e4c9c5SFUJITA Tomonori sdbg_host = *(struct sdebug_host_info **)shost_priv(hp); 38641da177e4SLinus Torvalds if (sdbg_host) { 3865cbf67842SDouglas Gilbert list_for_each_entry(devip, 38661da177e4SLinus Torvalds &sdbg_host->dev_info_list, 3867cbf67842SDouglas Gilbert dev_list) { 3868cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3869cbf67842SDouglas Gilbert ++k; 38701da177e4SLinus Torvalds } 38711da177e4SLinus Torvalds } 3872cbf67842SDouglas Gilbert } 3873773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3874cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 3875cbf67842SDouglas Gilbert "%s: %d device(s) found in host\n", __func__, k); 3876cbf67842SDouglas Gilbert lie: 38771da177e4SLinus Torvalds return SUCCESS; 38781da177e4SLinus Torvalds } 38791da177e4SLinus Torvalds 38801da177e4SLinus Torvalds static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt) 38811da177e4SLinus Torvalds { 38821da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host; 3883cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 3884cbf67842SDouglas Gilbert int k = 0; 38851da177e4SLinus Torvalds 38861da177e4SLinus Torvalds ++num_host_resets; 3887773642d9SDouglas Gilbert if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts)) 3888cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__); 38891da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 38901da177e4SLinus Torvalds list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { 3891cbf67842SDouglas Gilbert list_for_each_entry(devip, &sdbg_host->dev_info_list, 3892cbf67842SDouglas Gilbert dev_list) { 3893cbf67842SDouglas Gilbert set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm); 3894cbf67842SDouglas Gilbert ++k; 3895cbf67842SDouglas Gilbert } 38961da177e4SLinus Torvalds } 38971da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 38981da177e4SLinus Torvalds stop_all_queued(); 3899773642d9SDouglas Gilbert if (SDEBUG_OPT_RESET_NOISE & sdebug_opts) 3900cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, SCpnt->device, 3901cbf67842SDouglas Gilbert "%s: %d device(s) found\n", __func__, k); 39021da177e4SLinus Torvalds return SUCCESS; 39031da177e4SLinus Torvalds } 39041da177e4SLinus Torvalds 3905f58b0efbSFUJITA Tomonori static void __init sdebug_build_parts(unsigned char *ramp, 39065f2578e5SFUJITA Tomonori unsigned long store_size) 39071da177e4SLinus Torvalds { 39081da177e4SLinus Torvalds struct partition * pp; 39091da177e4SLinus Torvalds int starts[SDEBUG_MAX_PARTS + 2]; 39101da177e4SLinus Torvalds int sectors_per_part, num_sectors, k; 39111da177e4SLinus Torvalds int heads_by_sects, start_sec, end_sec; 39121da177e4SLinus Torvalds 39131da177e4SLinus Torvalds /* assume partition table already zeroed */ 3914773642d9SDouglas Gilbert if ((sdebug_num_parts < 1) || (store_size < 1048576)) 39151da177e4SLinus Torvalds return; 3916773642d9SDouglas Gilbert if (sdebug_num_parts > SDEBUG_MAX_PARTS) { 3917773642d9SDouglas Gilbert sdebug_num_parts = SDEBUG_MAX_PARTS; 3918c1287970STomas Winkler pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS); 39191da177e4SLinus Torvalds } 3920c65b1445SDouglas Gilbert num_sectors = (int)sdebug_store_sectors; 39211da177e4SLinus Torvalds sectors_per_part = (num_sectors - sdebug_sectors_per) 3922773642d9SDouglas Gilbert / sdebug_num_parts; 39231da177e4SLinus Torvalds heads_by_sects = sdebug_heads * sdebug_sectors_per; 39241da177e4SLinus Torvalds starts[0] = sdebug_sectors_per; 3925773642d9SDouglas Gilbert for (k = 1; k < sdebug_num_parts; ++k) 39261da177e4SLinus Torvalds starts[k] = ((k * sectors_per_part) / heads_by_sects) 39271da177e4SLinus Torvalds * heads_by_sects; 3928773642d9SDouglas Gilbert starts[sdebug_num_parts] = num_sectors; 3929773642d9SDouglas Gilbert starts[sdebug_num_parts + 1] = 0; 39301da177e4SLinus Torvalds 39311da177e4SLinus Torvalds ramp[510] = 0x55; /* magic partition markings */ 39321da177e4SLinus Torvalds ramp[511] = 0xAA; 39331da177e4SLinus Torvalds pp = (struct partition *)(ramp + 0x1be); 39341da177e4SLinus Torvalds for (k = 0; starts[k + 1]; ++k, ++pp) { 39351da177e4SLinus Torvalds start_sec = starts[k]; 39361da177e4SLinus Torvalds end_sec = starts[k + 1] - 1; 39371da177e4SLinus Torvalds pp->boot_ind = 0; 39381da177e4SLinus Torvalds 39391da177e4SLinus Torvalds pp->cyl = start_sec / heads_by_sects; 39401da177e4SLinus Torvalds pp->head = (start_sec - (pp->cyl * heads_by_sects)) 39411da177e4SLinus Torvalds / sdebug_sectors_per; 39421da177e4SLinus Torvalds pp->sector = (start_sec % sdebug_sectors_per) + 1; 39431da177e4SLinus Torvalds 39441da177e4SLinus Torvalds pp->end_cyl = end_sec / heads_by_sects; 39451da177e4SLinus Torvalds pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects)) 39461da177e4SLinus Torvalds / sdebug_sectors_per; 39471da177e4SLinus Torvalds pp->end_sector = (end_sec % sdebug_sectors_per) + 1; 39481da177e4SLinus Torvalds 3949150c3544SAkinobu Mita pp->start_sect = cpu_to_le32(start_sec); 3950150c3544SAkinobu Mita pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1); 39511da177e4SLinus Torvalds pp->sys_ind = 0x83; /* plain Linux partition */ 39521da177e4SLinus Torvalds } 39531da177e4SLinus Torvalds } 39541da177e4SLinus Torvalds 3955c4837394SDouglas Gilbert static void block_unblock_all_queues(bool block) 3956c4837394SDouglas Gilbert { 3957c4837394SDouglas Gilbert int j; 3958c4837394SDouglas Gilbert struct sdebug_queue *sqp; 3959c4837394SDouglas Gilbert 3960c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) 3961c4837394SDouglas Gilbert atomic_set(&sqp->blocked, (int)block); 3962c4837394SDouglas Gilbert } 3963c4837394SDouglas Gilbert 3964c4837394SDouglas Gilbert /* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1 3965c4837394SDouglas Gilbert * commands will be processed normally before triggers occur. 3966c4837394SDouglas Gilbert */ 3967c4837394SDouglas Gilbert static void tweak_cmnd_count(void) 3968c4837394SDouglas Gilbert { 3969c4837394SDouglas Gilbert int count, modulo; 3970c4837394SDouglas Gilbert 3971c4837394SDouglas Gilbert modulo = abs(sdebug_every_nth); 3972c4837394SDouglas Gilbert if (modulo < 2) 3973c4837394SDouglas Gilbert return; 3974c4837394SDouglas Gilbert block_unblock_all_queues(true); 3975c4837394SDouglas Gilbert count = atomic_read(&sdebug_cmnd_count); 3976c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo); 3977c4837394SDouglas Gilbert block_unblock_all_queues(false); 3978c4837394SDouglas Gilbert } 3979c4837394SDouglas Gilbert 3980c4837394SDouglas Gilbert static void clear_queue_stats(void) 3981c4837394SDouglas Gilbert { 3982c4837394SDouglas Gilbert atomic_set(&sdebug_cmnd_count, 0); 3983c4837394SDouglas Gilbert atomic_set(&sdebug_completions, 0); 3984c4837394SDouglas Gilbert atomic_set(&sdebug_miss_cpus, 0); 3985c4837394SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 3986c4837394SDouglas Gilbert } 3987c4837394SDouglas Gilbert 3988c4837394SDouglas Gilbert static void setup_inject(struct sdebug_queue *sqp, 3989c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp) 3990c4837394SDouglas Gilbert { 3991c4837394SDouglas Gilbert if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) 3992c4837394SDouglas Gilbert return; 3993c4837394SDouglas Gilbert sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts); 3994c4837394SDouglas Gilbert sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts); 3995c4837394SDouglas Gilbert sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts); 3996c4837394SDouglas Gilbert sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts); 3997c4837394SDouglas Gilbert sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts); 3998c4837394SDouglas Gilbert } 3999c4837394SDouglas Gilbert 4000c4837394SDouglas Gilbert /* Complete the processing of the thread that queued a SCSI command to this 4001c4837394SDouglas Gilbert * driver. It either completes the command by calling cmnd_done() or 4002c4837394SDouglas Gilbert * schedules a hr timer or work queue then returns 0. Returns 4003c4837394SDouglas Gilbert * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources. 4004c4837394SDouglas Gilbert */ 4005fd32119bSDouglas Gilbert static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip, 4006cbf67842SDouglas Gilbert int scsi_result, int delta_jiff) 40071da177e4SLinus Torvalds { 4008cbf67842SDouglas Gilbert unsigned long iflags; 4009cd62b7daSDouglas Gilbert int k, num_in_q, qdepth, inject; 4010c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4011c4837394SDouglas Gilbert struct sdebug_queued_cmd *sqcp; 4012299b6c07STomas Winkler struct scsi_device *sdp; 4013a10bc12aSDouglas Gilbert struct sdebug_defer *sd_dp; 40141da177e4SLinus Torvalds 4015b01f6f83SDouglas Gilbert if (unlikely(devip == NULL)) { 4016b01f6f83SDouglas Gilbert if (scsi_result == 0) 4017f46eb0e9SDouglas Gilbert scsi_result = DID_NO_CONNECT << 16; 4018f46eb0e9SDouglas Gilbert goto respond_in_thread; 40191da177e4SLinus Torvalds } 4020299b6c07STomas Winkler sdp = cmnd->device; 4021299b6c07STomas Winkler 4022f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && scsi_result)) 4023cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n", 4024cbf67842SDouglas Gilbert __func__, scsi_result); 4025cd62b7daSDouglas Gilbert if (delta_jiff == 0) 4026cd62b7daSDouglas Gilbert goto respond_in_thread; 40271da177e4SLinus Torvalds 4028cd62b7daSDouglas Gilbert /* schedule the response at a later time if resources permit */ 4029c4837394SDouglas Gilbert sqp = get_queue(cmnd); 4030c4837394SDouglas Gilbert spin_lock_irqsave(&sqp->qc_lock, iflags); 4031c4837394SDouglas Gilbert if (unlikely(atomic_read(&sqp->blocked))) { 4032c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4033c4837394SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4034c4837394SDouglas Gilbert } 4035cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 4036cbf67842SDouglas Gilbert qdepth = cmnd->device->queue_depth; 4037cbf67842SDouglas Gilbert inject = 0; 4038f46eb0e9SDouglas Gilbert if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) { 4039cd62b7daSDouglas Gilbert if (scsi_result) { 4040c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4041cd62b7daSDouglas Gilbert goto respond_in_thread; 4042cd62b7daSDouglas Gilbert } else 4043cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4044c4837394SDouglas Gilbert } else if (unlikely(sdebug_every_nth && 4045773642d9SDouglas Gilbert (SDEBUG_OPT_RARE_TSF & sdebug_opts) && 4046f46eb0e9SDouglas Gilbert (scsi_result == 0))) { 4047cbf67842SDouglas Gilbert if ((num_in_q == (qdepth - 1)) && 4048cbf67842SDouglas Gilbert (atomic_inc_return(&sdebug_a_tsf) >= 4049773642d9SDouglas Gilbert abs(sdebug_every_nth))) { 4050cbf67842SDouglas Gilbert atomic_set(&sdebug_a_tsf, 0); 4051cbf67842SDouglas Gilbert inject = 1; 4052cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 40531da177e4SLinus Torvalds } 4054cbf67842SDouglas Gilbert } 4055cbf67842SDouglas Gilbert 4056c4837394SDouglas Gilbert k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue); 4057f46eb0e9SDouglas Gilbert if (unlikely(k >= sdebug_max_queue)) { 4058c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4059cd62b7daSDouglas Gilbert if (scsi_result) 4060cd62b7daSDouglas Gilbert goto respond_in_thread; 4061773642d9SDouglas Gilbert else if (SDEBUG_OPT_ALL_TSF & sdebug_opts) 4062cd62b7daSDouglas Gilbert scsi_result = device_qfull_result; 4063773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) 4064cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4065cd62b7daSDouglas Gilbert "%s: max_queue=%d exceeded, %s\n", 4066773642d9SDouglas Gilbert __func__, sdebug_max_queue, 4067cd62b7daSDouglas Gilbert (scsi_result ? "status: TASK SET FULL" : 4068cbf67842SDouglas Gilbert "report: host busy")); 4069cd62b7daSDouglas Gilbert if (scsi_result) 4070cd62b7daSDouglas Gilbert goto respond_in_thread; 4071cd62b7daSDouglas Gilbert else 4072cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 40731da177e4SLinus Torvalds } 4074c4837394SDouglas Gilbert __set_bit(k, sqp->in_use_bm); 4075cbf67842SDouglas Gilbert atomic_inc(&devip->num_in_q); 4076c4837394SDouglas Gilbert sqcp = &sqp->qc_arr[k]; 40771da177e4SLinus Torvalds sqcp->a_cmnd = cmnd; 4078c4837394SDouglas Gilbert cmnd->host_scribble = (unsigned char *)sqcp; 4079cbf67842SDouglas Gilbert cmnd->result = scsi_result; 4080a10bc12aSDouglas Gilbert sd_dp = sqcp->sd_dp; 4081c4837394SDouglas Gilbert spin_unlock_irqrestore(&sqp->qc_lock, iflags); 4082c4837394SDouglas Gilbert if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt)) 4083c4837394SDouglas Gilbert setup_inject(sqp, sqcp); 4084b01f6f83SDouglas Gilbert if (delta_jiff > 0 || sdebug_ndelay > 0) { 4085b333a819SDouglas Gilbert ktime_t kt; 4086cbf67842SDouglas Gilbert 4087b333a819SDouglas Gilbert if (delta_jiff > 0) { 4088b333a819SDouglas Gilbert struct timespec ts; 4089b333a819SDouglas Gilbert 4090b333a819SDouglas Gilbert jiffies_to_timespec(delta_jiff, &ts); 4091b333a819SDouglas Gilbert kt = ktime_set(ts.tv_sec, ts.tv_nsec); 4092b333a819SDouglas Gilbert } else 40938b0e1953SThomas Gleixner kt = sdebug_ndelay; 4094a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4095a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC); 4096a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4097cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4098a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4099a10bc12aSDouglas Gilbert hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC, 4100c4837394SDouglas Gilbert HRTIMER_MODE_REL_PINNED); 4101a10bc12aSDouglas Gilbert sd_dp->hrt.function = sdebug_q_cmd_hrt_complete; 4102c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4103c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4104cbf67842SDouglas Gilbert } 4105c4837394SDouglas Gilbert if (sdebug_statistics) 4106c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4107c4837394SDouglas Gilbert hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED); 4108c4837394SDouglas Gilbert } else { /* jdelay < 0, use work queue */ 4109a10bc12aSDouglas Gilbert if (NULL == sd_dp) { 4110a10bc12aSDouglas Gilbert sd_dp = kzalloc(sizeof(*sqcp->sd_dp), GFP_ATOMIC); 4111a10bc12aSDouglas Gilbert if (NULL == sd_dp) 4112cbf67842SDouglas Gilbert return SCSI_MLQUEUE_HOST_BUSY; 4113a10bc12aSDouglas Gilbert sqcp->sd_dp = sd_dp; 4114c4837394SDouglas Gilbert sd_dp->sqa_idx = sqp - sdebug_q_arr; 4115c4837394SDouglas Gilbert sd_dp->qc_idx = k; 4116a10bc12aSDouglas Gilbert INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete); 4117cbf67842SDouglas Gilbert } 4118c4837394SDouglas Gilbert if (sdebug_statistics) 4119c4837394SDouglas Gilbert sd_dp->issuing_cpu = raw_smp_processor_id(); 4120a10bc12aSDouglas Gilbert schedule_work(&sd_dp->ew.work); 4121cbf67842SDouglas Gilbert } 4122f46eb0e9SDouglas Gilbert if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) && 4123f46eb0e9SDouglas Gilbert (scsi_result == device_qfull_result))) 4124cbf67842SDouglas Gilbert sdev_printk(KERN_INFO, sdp, 4125cbf67842SDouglas Gilbert "%s: num_in_q=%d +1, %s%s\n", __func__, 4126cbf67842SDouglas Gilbert num_in_q, (inject ? "<inject> " : ""), 4127cbf67842SDouglas Gilbert "status: TASK SET FULL"); 41281da177e4SLinus Torvalds return 0; 4129cd62b7daSDouglas Gilbert 4130cd62b7daSDouglas Gilbert respond_in_thread: /* call back to mid-layer using invocation thread */ 4131cd62b7daSDouglas Gilbert cmnd->result = scsi_result; 4132cd62b7daSDouglas Gilbert cmnd->scsi_done(cmnd); 4133cd62b7daSDouglas Gilbert return 0; 41341da177e4SLinus Torvalds } 4135cbf67842SDouglas Gilbert 413623183910SDouglas Gilbert /* Note: The following macros create attribute files in the 413723183910SDouglas Gilbert /sys/module/scsi_debug/parameters directory. Unfortunately this 413823183910SDouglas Gilbert driver is unaware of a change and cannot trigger auxiliary actions 413923183910SDouglas Gilbert as it can when the corresponding attribute in the 414023183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory is changed. 414123183910SDouglas Gilbert */ 4142773642d9SDouglas Gilbert module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR); 4143773642d9SDouglas Gilbert module_param_named(ato, sdebug_ato, int, S_IRUGO); 4144773642d9SDouglas Gilbert module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR); 4145c2206098SDouglas Gilbert module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR); 4146773642d9SDouglas Gilbert module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO); 4147773642d9SDouglas Gilbert module_param_named(dif, sdebug_dif, int, S_IRUGO); 4148773642d9SDouglas Gilbert module_param_named(dix, sdebug_dix, int, S_IRUGO); 4149773642d9SDouglas Gilbert module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR); 4150773642d9SDouglas Gilbert module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR); 4151773642d9SDouglas Gilbert module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR); 4152773642d9SDouglas Gilbert module_param_named(guard, sdebug_guard, uint, S_IRUGO); 4153773642d9SDouglas Gilbert module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR); 4154e5203cf0SHannes Reinecke module_param_string(inq_vendor, sdebug_inq_vendor_id, 4155e5203cf0SHannes Reinecke sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR); 4156e5203cf0SHannes Reinecke module_param_string(inq_product, sdebug_inq_product_id, 4157e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR); 4158e5203cf0SHannes Reinecke module_param_string(inq_rev, sdebug_inq_product_rev, 4159e5203cf0SHannes Reinecke sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR); 4160773642d9SDouglas Gilbert module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO); 4161773642d9SDouglas Gilbert module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO); 4162773642d9SDouglas Gilbert module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO); 4163773642d9SDouglas Gilbert module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO); 4164773642d9SDouglas Gilbert module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO); 4165773642d9SDouglas Gilbert module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR); 4166773642d9SDouglas Gilbert module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR); 4167773642d9SDouglas Gilbert module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR); 4168773642d9SDouglas Gilbert module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR); 4169773642d9SDouglas Gilbert module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO); 4170773642d9SDouglas Gilbert module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO); 4171773642d9SDouglas Gilbert module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR); 4172773642d9SDouglas Gilbert module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO); 4173773642d9SDouglas Gilbert module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR); 4174773642d9SDouglas Gilbert module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO); 417586e6828aSLukas Herbolt module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO); 4176773642d9SDouglas Gilbert module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR); 4177773642d9SDouglas Gilbert module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR); 4178773642d9SDouglas Gilbert module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO); 4179773642d9SDouglas Gilbert module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO); 4180c4837394SDouglas Gilbert module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR); 4181773642d9SDouglas Gilbert module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR); 4182c4837394SDouglas Gilbert module_param_named(submit_queues, submit_queues, int, S_IRUGO); 4183773642d9SDouglas Gilbert module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO); 4184773642d9SDouglas Gilbert module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO); 4185773642d9SDouglas Gilbert module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO); 4186773642d9SDouglas Gilbert module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO); 4187773642d9SDouglas Gilbert module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR); 418809ba24c1SDouglas Gilbert module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO); 4189773642d9SDouglas Gilbert module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int, 419023183910SDouglas Gilbert S_IRUGO | S_IWUSR); 4191773642d9SDouglas Gilbert module_param_named(write_same_length, sdebug_write_same_length, int, 41925b94e232SMartin K. Petersen S_IRUGO | S_IWUSR); 41931da177e4SLinus Torvalds 41941da177e4SLinus Torvalds MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert"); 41951da177e4SLinus Torvalds MODULE_DESCRIPTION("SCSI debug adapter driver"); 41961da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 4197b01f6f83SDouglas Gilbert MODULE_VERSION(SDEBUG_VERSION); 41981da177e4SLinus Torvalds 41991da177e4SLinus Torvalds MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)"); 42005b94e232SMartin K. Petersen MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)"); 42010759c666SAkinobu Mita MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)"); 4202cbf67842SDouglas Gilbert MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny"); 4203c2248fc9SDouglas Gilbert MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)"); 42045b94e232SMartin K. Petersen MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)"); 42055b94e232SMartin K. Petersen MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)"); 4206c65b1445SDouglas Gilbert MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)"); 4207beb87c33SRandy Dunlap MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)"); 420823183910SDouglas Gilbert MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)"); 42095b94e232SMartin K. Petersen MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)"); 4210185dd232SDouglas Gilbert MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)"); 4211e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")"); 4212e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")"); 4213e5203cf0SHannes Reinecke MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\"0186\")"); 42145b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)"); 42155b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)"); 42165b94e232SMartin K. Petersen MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)"); 4217760f3b03SDouglas Gilbert MODULE_PARM_DESC(lbprz, 4218760f3b03SDouglas Gilbert "on read unmapped LBs return 0 when 1 (def), return 0xff when 2"); 42195b94e232SMartin K. Petersen MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)"); 4220c65b1445SDouglas Gilbert MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)"); 4221cbf67842SDouglas Gilbert MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))"); 4222cbf67842SDouglas Gilbert MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)"); 4223c65b1445SDouglas Gilbert MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)"); 422478d4e5a0SDouglas Gilbert MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))"); 42251da177e4SLinus Torvalds MODULE_PARM_DESC(num_parts, "number of partitions(def=0)"); 4226c65b1445SDouglas Gilbert MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)"); 422732c5844aSMartin K. Petersen MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)"); 42286f3cbf55SDouglas Gilbert MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)"); 42295b94e232SMartin K. Petersen MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)"); 423086e6828aSLukas Herbolt MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)"); 42311da177e4SLinus Torvalds MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])"); 4232d986788bSMartin Pitt MODULE_PARM_DESC(removable, "claim to have removable media (def=0)"); 4233760f3b03SDouglas Gilbert MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])"); 4234ea61fca5SMartin K. Petersen MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)"); 4235c4837394SDouglas Gilbert MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)"); 4236c2248fc9SDouglas Gilbert MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)"); 4237c4837394SDouglas Gilbert MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)"); 42385b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)"); 42395b94e232SMartin K. Petersen MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)"); 42406014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)"); 42416014759cSMartin K. Petersen MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)"); 424209ba24c1SDouglas Gilbert MODULE_PARM_DESC(uuid_ctl, 424309ba24c1SDouglas Gilbert "1->use uuid for lu name, 0->don't, 2->all use same (def=0)"); 4244c2248fc9SDouglas Gilbert MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)"); 42455b94e232SMartin K. Petersen MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)"); 42465b94e232SMartin K. Petersen MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)"); 42471da177e4SLinus Torvalds 4248760f3b03SDouglas Gilbert #define SDEBUG_INFO_LEN 256 4249760f3b03SDouglas Gilbert static char sdebug_info[SDEBUG_INFO_LEN]; 42501da177e4SLinus Torvalds 42511da177e4SLinus Torvalds static const char * scsi_debug_info(struct Scsi_Host * shp) 42521da177e4SLinus Torvalds { 4253c4837394SDouglas Gilbert int k; 4254c4837394SDouglas Gilbert 4255760f3b03SDouglas Gilbert k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n", 4256760f3b03SDouglas Gilbert my_name, SDEBUG_VERSION, sdebug_version_date); 4257760f3b03SDouglas Gilbert if (k >= (SDEBUG_INFO_LEN - 1)) 4258c4837394SDouglas Gilbert return sdebug_info; 4259760f3b03SDouglas Gilbert scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k, 4260760f3b03SDouglas Gilbert " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d", 4261760f3b03SDouglas Gilbert sdebug_dev_size_mb, sdebug_opts, submit_queues, 4262760f3b03SDouglas Gilbert "statistics", (int)sdebug_statistics); 42631da177e4SLinus Torvalds return sdebug_info; 42641da177e4SLinus Torvalds } 42651da177e4SLinus Torvalds 4266cbf67842SDouglas Gilbert /* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */ 4267fd32119bSDouglas Gilbert static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer, 4268fd32119bSDouglas Gilbert int length) 42691da177e4SLinus Torvalds { 42701da177e4SLinus Torvalds char arr[16]; 4271c8ed555aSAl Viro int opts; 42721da177e4SLinus Torvalds int minLen = length > 15 ? 15 : length; 42731da177e4SLinus Torvalds 42741da177e4SLinus Torvalds if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) 42751da177e4SLinus Torvalds return -EACCES; 42761da177e4SLinus Torvalds memcpy(arr, buffer, minLen); 42771da177e4SLinus Torvalds arr[minLen] = '\0'; 4278c8ed555aSAl Viro if (1 != sscanf(arr, "%d", &opts)) 42791da177e4SLinus Torvalds return -EINVAL; 4280773642d9SDouglas Gilbert sdebug_opts = opts; 4281773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4282773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4283773642d9SDouglas Gilbert if (sdebug_every_nth != 0) 4284c4837394SDouglas Gilbert tweak_cmnd_count(); 42851da177e4SLinus Torvalds return length; 42861da177e4SLinus Torvalds } 4287c8ed555aSAl Viro 4288cbf67842SDouglas Gilbert /* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the 4289cbf67842SDouglas Gilbert * same for each scsi_debug host (if more than one). Some of the counters 4290cbf67842SDouglas Gilbert * output are not atomics so might be inaccurate in a busy system. */ 4291c8ed555aSAl Viro static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host) 4292c8ed555aSAl Viro { 4293c4837394SDouglas Gilbert int f, j, l; 4294c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4295cbf67842SDouglas Gilbert 4296c4837394SDouglas Gilbert seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n", 4297c4837394SDouglas Gilbert SDEBUG_VERSION, sdebug_version_date); 4298c4837394SDouglas Gilbert seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n", 4299c4837394SDouglas Gilbert sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb, 4300c4837394SDouglas Gilbert sdebug_opts, sdebug_every_nth); 4301c4837394SDouglas Gilbert seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n", 4302c4837394SDouglas Gilbert sdebug_jdelay, sdebug_ndelay, sdebug_max_luns, 4303c4837394SDouglas Gilbert sdebug_sector_size, "bytes"); 4304c4837394SDouglas Gilbert seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n", 4305c4837394SDouglas Gilbert sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per, 4306c4837394SDouglas Gilbert num_aborts); 4307c4837394SDouglas Gilbert seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n", 4308c4837394SDouglas Gilbert num_dev_resets, num_target_resets, num_bus_resets, 4309c4837394SDouglas Gilbert num_host_resets); 4310c4837394SDouglas Gilbert seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n", 4311c4837394SDouglas Gilbert dix_reads, dix_writes, dif_errors); 4312c4837394SDouglas Gilbert seq_printf(m, "usec_in_jiffy=%lu, %s=%d, mq_active=%d\n", 4313c4837394SDouglas Gilbert TICK_NSEC / 1000, "statistics", sdebug_statistics, 4314c4837394SDouglas Gilbert sdebug_mq_active); 4315c4837394SDouglas Gilbert seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n", 4316c4837394SDouglas Gilbert atomic_read(&sdebug_cmnd_count), 4317c4837394SDouglas Gilbert atomic_read(&sdebug_completions), 4318c4837394SDouglas Gilbert "miss_cpus", atomic_read(&sdebug_miss_cpus), 4319c4837394SDouglas Gilbert atomic_read(&sdebug_a_tsf)); 4320cbf67842SDouglas Gilbert 4321c4837394SDouglas Gilbert seq_printf(m, "submit_queues=%d\n", submit_queues); 4322c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) { 4323c4837394SDouglas Gilbert seq_printf(m, " queue %d:\n", j); 4324c4837394SDouglas Gilbert f = find_first_bit(sqp->in_use_bm, sdebug_max_queue); 4325773642d9SDouglas Gilbert if (f != sdebug_max_queue) { 4326c4837394SDouglas Gilbert l = find_last_bit(sqp->in_use_bm, sdebug_max_queue); 4327c4837394SDouglas Gilbert seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n", 4328c4837394SDouglas Gilbert "first,last bits", f, l); 4329c4837394SDouglas Gilbert } 4330cbf67842SDouglas Gilbert } 4331c8ed555aSAl Viro return 0; 43321da177e4SLinus Torvalds } 43331da177e4SLinus Torvalds 433482069379SAkinobu Mita static ssize_t delay_show(struct device_driver *ddp, char *buf) 43351da177e4SLinus Torvalds { 4336c2206098SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay); 43371da177e4SLinus Torvalds } 4338c4837394SDouglas Gilbert /* Returns -EBUSY if jdelay is being changed and commands are queued. The unit 4339c4837394SDouglas Gilbert * of delay is jiffies. 4340c4837394SDouglas Gilbert */ 434182069379SAkinobu Mita static ssize_t delay_store(struct device_driver *ddp, const char *buf, 434282069379SAkinobu Mita size_t count) 43431da177e4SLinus Torvalds { 4344c2206098SDouglas Gilbert int jdelay, res; 43451da177e4SLinus Torvalds 4346b01f6f83SDouglas Gilbert if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) { 4347cbf67842SDouglas Gilbert res = count; 4348c2206098SDouglas Gilbert if (sdebug_jdelay != jdelay) { 4349c4837394SDouglas Gilbert int j, k; 4350c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4351cbf67842SDouglas Gilbert 4352c4837394SDouglas Gilbert block_unblock_all_queues(true); 4353c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4354c4837394SDouglas Gilbert ++j, ++sqp) { 4355c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4356c4837394SDouglas Gilbert sdebug_max_queue); 4357c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4358c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4359c4837394SDouglas Gilbert break; 4360c4837394SDouglas Gilbert } 4361c4837394SDouglas Gilbert } 4362c4837394SDouglas Gilbert if (res > 0) { 4363a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4364a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4365a10bc12aSDouglas Gilbert free_all_queued(); 4366c2206098SDouglas Gilbert sdebug_jdelay = jdelay; 4367773642d9SDouglas Gilbert sdebug_ndelay = 0; 43681da177e4SLinus Torvalds } 4369c4837394SDouglas Gilbert block_unblock_all_queues(false); 4370cbf67842SDouglas Gilbert } 4371cbf67842SDouglas Gilbert return res; 43721da177e4SLinus Torvalds } 43731da177e4SLinus Torvalds return -EINVAL; 43741da177e4SLinus Torvalds } 437582069379SAkinobu Mita static DRIVER_ATTR_RW(delay); 43761da177e4SLinus Torvalds 4377cbf67842SDouglas Gilbert static ssize_t ndelay_show(struct device_driver *ddp, char *buf) 4378cbf67842SDouglas Gilbert { 4379773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay); 4380cbf67842SDouglas Gilbert } 4381cbf67842SDouglas Gilbert /* Returns -EBUSY if ndelay is being changed and commands are queued */ 4382c2206098SDouglas Gilbert /* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */ 4383cbf67842SDouglas Gilbert static ssize_t ndelay_store(struct device_driver *ddp, const char *buf, 4384cbf67842SDouglas Gilbert size_t count) 4385cbf67842SDouglas Gilbert { 4386c4837394SDouglas Gilbert int ndelay, res; 4387cbf67842SDouglas Gilbert 4388cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) && 4389c4837394SDouglas Gilbert (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) { 4390cbf67842SDouglas Gilbert res = count; 4391773642d9SDouglas Gilbert if (sdebug_ndelay != ndelay) { 4392c4837394SDouglas Gilbert int j, k; 4393c4837394SDouglas Gilbert struct sdebug_queue *sqp; 4394c4837394SDouglas Gilbert 4395c4837394SDouglas Gilbert block_unblock_all_queues(true); 4396c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4397c4837394SDouglas Gilbert ++j, ++sqp) { 4398c4837394SDouglas Gilbert k = find_first_bit(sqp->in_use_bm, 4399c4837394SDouglas Gilbert sdebug_max_queue); 4400c4837394SDouglas Gilbert if (k != sdebug_max_queue) { 4401c4837394SDouglas Gilbert res = -EBUSY; /* queued commands */ 4402c4837394SDouglas Gilbert break; 4403c4837394SDouglas Gilbert } 4404c4837394SDouglas Gilbert } 4405c4837394SDouglas Gilbert if (res > 0) { 4406a10bc12aSDouglas Gilbert /* make sure sdebug_defer instances get 4407a10bc12aSDouglas Gilbert * re-allocated for new delay variant */ 4408a10bc12aSDouglas Gilbert free_all_queued(); 4409773642d9SDouglas Gilbert sdebug_ndelay = ndelay; 4410c2206098SDouglas Gilbert sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN 4411c2206098SDouglas Gilbert : DEF_JDELAY; 4412cbf67842SDouglas Gilbert } 4413c4837394SDouglas Gilbert block_unblock_all_queues(false); 4414cbf67842SDouglas Gilbert } 4415cbf67842SDouglas Gilbert return res; 4416cbf67842SDouglas Gilbert } 4417cbf67842SDouglas Gilbert return -EINVAL; 4418cbf67842SDouglas Gilbert } 4419cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(ndelay); 4420cbf67842SDouglas Gilbert 442182069379SAkinobu Mita static ssize_t opts_show(struct device_driver *ddp, char *buf) 44221da177e4SLinus Torvalds { 4423773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts); 44241da177e4SLinus Torvalds } 44251da177e4SLinus Torvalds 442682069379SAkinobu Mita static ssize_t opts_store(struct device_driver *ddp, const char *buf, 442782069379SAkinobu Mita size_t count) 44281da177e4SLinus Torvalds { 44291da177e4SLinus Torvalds int opts; 44301da177e4SLinus Torvalds char work[20]; 44311da177e4SLinus Torvalds 44321da177e4SLinus Torvalds if (1 == sscanf(buf, "%10s", work)) { 443348a96876SRasmus Villemoes if (0 == strncasecmp(work,"0x", 2)) { 44341da177e4SLinus Torvalds if (1 == sscanf(&work[2], "%x", &opts)) 44351da177e4SLinus Torvalds goto opts_done; 44361da177e4SLinus Torvalds } else { 44371da177e4SLinus Torvalds if (1 == sscanf(work, "%d", &opts)) 44381da177e4SLinus Torvalds goto opts_done; 44391da177e4SLinus Torvalds } 44401da177e4SLinus Torvalds } 44411da177e4SLinus Torvalds return -EINVAL; 44421da177e4SLinus Torvalds opts_done: 4443773642d9SDouglas Gilbert sdebug_opts = opts; 4444773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts); 4445773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts); 4446c4837394SDouglas Gilbert tweak_cmnd_count(); 44471da177e4SLinus Torvalds return count; 44481da177e4SLinus Torvalds } 444982069379SAkinobu Mita static DRIVER_ATTR_RW(opts); 44501da177e4SLinus Torvalds 445182069379SAkinobu Mita static ssize_t ptype_show(struct device_driver *ddp, char *buf) 44521da177e4SLinus Torvalds { 4453773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype); 44541da177e4SLinus Torvalds } 445582069379SAkinobu Mita static ssize_t ptype_store(struct device_driver *ddp, const char *buf, 445682069379SAkinobu Mita size_t count) 44571da177e4SLinus Torvalds { 44581da177e4SLinus Torvalds int n; 44591da177e4SLinus Torvalds 44601da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4461773642d9SDouglas Gilbert sdebug_ptype = n; 44621da177e4SLinus Torvalds return count; 44631da177e4SLinus Torvalds } 44641da177e4SLinus Torvalds return -EINVAL; 44651da177e4SLinus Torvalds } 446682069379SAkinobu Mita static DRIVER_ATTR_RW(ptype); 44671da177e4SLinus Torvalds 446882069379SAkinobu Mita static ssize_t dsense_show(struct device_driver *ddp, char *buf) 44691da177e4SLinus Torvalds { 4470773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense); 44711da177e4SLinus Torvalds } 447282069379SAkinobu Mita static ssize_t dsense_store(struct device_driver *ddp, const char *buf, 447382069379SAkinobu Mita size_t count) 44741da177e4SLinus Torvalds { 44751da177e4SLinus Torvalds int n; 44761da177e4SLinus Torvalds 44771da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4478773642d9SDouglas Gilbert sdebug_dsense = n; 44791da177e4SLinus Torvalds return count; 44801da177e4SLinus Torvalds } 44811da177e4SLinus Torvalds return -EINVAL; 44821da177e4SLinus Torvalds } 448382069379SAkinobu Mita static DRIVER_ATTR_RW(dsense); 44841da177e4SLinus Torvalds 448582069379SAkinobu Mita static ssize_t fake_rw_show(struct device_driver *ddp, char *buf) 448623183910SDouglas Gilbert { 4487773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw); 448823183910SDouglas Gilbert } 448982069379SAkinobu Mita static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf, 449082069379SAkinobu Mita size_t count) 449123183910SDouglas Gilbert { 449223183910SDouglas Gilbert int n; 449323183910SDouglas Gilbert 449423183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4495cbf67842SDouglas Gilbert n = (n > 0); 4496773642d9SDouglas Gilbert sdebug_fake_rw = (sdebug_fake_rw > 0); 4497773642d9SDouglas Gilbert if (sdebug_fake_rw != n) { 4498cbf67842SDouglas Gilbert if ((0 == n) && (NULL == fake_storep)) { 4499cbf67842SDouglas Gilbert unsigned long sz = 4500773642d9SDouglas Gilbert (unsigned long)sdebug_dev_size_mb * 4501cbf67842SDouglas Gilbert 1048576; 4502cbf67842SDouglas Gilbert 4503cbf67842SDouglas Gilbert fake_storep = vmalloc(sz); 4504cbf67842SDouglas Gilbert if (NULL == fake_storep) { 4505c1287970STomas Winkler pr_err("out of memory, 9\n"); 4506cbf67842SDouglas Gilbert return -ENOMEM; 4507cbf67842SDouglas Gilbert } 4508cbf67842SDouglas Gilbert memset(fake_storep, 0, sz); 4509cbf67842SDouglas Gilbert } 4510773642d9SDouglas Gilbert sdebug_fake_rw = n; 4511cbf67842SDouglas Gilbert } 451223183910SDouglas Gilbert return count; 451323183910SDouglas Gilbert } 451423183910SDouglas Gilbert return -EINVAL; 451523183910SDouglas Gilbert } 451682069379SAkinobu Mita static DRIVER_ATTR_RW(fake_rw); 451723183910SDouglas Gilbert 451882069379SAkinobu Mita static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf) 4519c65b1445SDouglas Gilbert { 4520773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0); 4521c65b1445SDouglas Gilbert } 452282069379SAkinobu Mita static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf, 452382069379SAkinobu Mita size_t count) 4524c65b1445SDouglas Gilbert { 4525c65b1445SDouglas Gilbert int n; 4526c65b1445SDouglas Gilbert 4527c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4528773642d9SDouglas Gilbert sdebug_no_lun_0 = n; 4529c65b1445SDouglas Gilbert return count; 4530c65b1445SDouglas Gilbert } 4531c65b1445SDouglas Gilbert return -EINVAL; 4532c65b1445SDouglas Gilbert } 453382069379SAkinobu Mita static DRIVER_ATTR_RW(no_lun_0); 4534c65b1445SDouglas Gilbert 453582069379SAkinobu Mita static ssize_t num_tgts_show(struct device_driver *ddp, char *buf) 45361da177e4SLinus Torvalds { 4537773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts); 45381da177e4SLinus Torvalds } 453982069379SAkinobu Mita static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf, 454082069379SAkinobu Mita size_t count) 45411da177e4SLinus Torvalds { 45421da177e4SLinus Torvalds int n; 45431da177e4SLinus Torvalds 45441da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4545773642d9SDouglas Gilbert sdebug_num_tgts = n; 45461da177e4SLinus Torvalds sdebug_max_tgts_luns(); 45471da177e4SLinus Torvalds return count; 45481da177e4SLinus Torvalds } 45491da177e4SLinus Torvalds return -EINVAL; 45501da177e4SLinus Torvalds } 455182069379SAkinobu Mita static DRIVER_ATTR_RW(num_tgts); 45521da177e4SLinus Torvalds 455382069379SAkinobu Mita static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf) 45541da177e4SLinus Torvalds { 4555773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb); 45561da177e4SLinus Torvalds } 455782069379SAkinobu Mita static DRIVER_ATTR_RO(dev_size_mb); 45581da177e4SLinus Torvalds 455982069379SAkinobu Mita static ssize_t num_parts_show(struct device_driver *ddp, char *buf) 45601da177e4SLinus Torvalds { 4561773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts); 45621da177e4SLinus Torvalds } 456382069379SAkinobu Mita static DRIVER_ATTR_RO(num_parts); 45641da177e4SLinus Torvalds 456582069379SAkinobu Mita static ssize_t every_nth_show(struct device_driver *ddp, char *buf) 45661da177e4SLinus Torvalds { 4567773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth); 45681da177e4SLinus Torvalds } 456982069379SAkinobu Mita static ssize_t every_nth_store(struct device_driver *ddp, const char *buf, 457082069379SAkinobu Mita size_t count) 45711da177e4SLinus Torvalds { 45721da177e4SLinus Torvalds int nth; 45731da177e4SLinus Torvalds 45741da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) { 4575773642d9SDouglas Gilbert sdebug_every_nth = nth; 4576c4837394SDouglas Gilbert if (nth && !sdebug_statistics) { 4577c4837394SDouglas Gilbert pr_info("every_nth needs statistics=1, set it\n"); 4578c4837394SDouglas Gilbert sdebug_statistics = true; 4579c4837394SDouglas Gilbert } 4580c4837394SDouglas Gilbert tweak_cmnd_count(); 45811da177e4SLinus Torvalds return count; 45821da177e4SLinus Torvalds } 45831da177e4SLinus Torvalds return -EINVAL; 45841da177e4SLinus Torvalds } 458582069379SAkinobu Mita static DRIVER_ATTR_RW(every_nth); 45861da177e4SLinus Torvalds 458782069379SAkinobu Mita static ssize_t max_luns_show(struct device_driver *ddp, char *buf) 45881da177e4SLinus Torvalds { 4589773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns); 45901da177e4SLinus Torvalds } 459182069379SAkinobu Mita static ssize_t max_luns_store(struct device_driver *ddp, const char *buf, 459282069379SAkinobu Mita size_t count) 45931da177e4SLinus Torvalds { 45941da177e4SLinus Torvalds int n; 459519c8ead7SEwan D. Milne bool changed; 45961da177e4SLinus Torvalds 45971da177e4SLinus Torvalds if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 45988d039e22SDouglas Gilbert if (n > 256) { 45998d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256\n"); 46008d039e22SDouglas Gilbert return -EINVAL; 46018d039e22SDouglas Gilbert } 4602773642d9SDouglas Gilbert changed = (sdebug_max_luns != n); 4603773642d9SDouglas Gilbert sdebug_max_luns = n; 46041da177e4SLinus Torvalds sdebug_max_tgts_luns(); 4605773642d9SDouglas Gilbert if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */ 460619c8ead7SEwan D. Milne struct sdebug_host_info *sdhp; 460719c8ead7SEwan D. Milne struct sdebug_dev_info *dp; 460819c8ead7SEwan D. Milne 460919c8ead7SEwan D. Milne spin_lock(&sdebug_host_list_lock); 461019c8ead7SEwan D. Milne list_for_each_entry(sdhp, &sdebug_host_list, 461119c8ead7SEwan D. Milne host_list) { 461219c8ead7SEwan D. Milne list_for_each_entry(dp, &sdhp->dev_info_list, 461319c8ead7SEwan D. Milne dev_list) { 461419c8ead7SEwan D. Milne set_bit(SDEBUG_UA_LUNS_CHANGED, 461519c8ead7SEwan D. Milne dp->uas_bm); 461619c8ead7SEwan D. Milne } 461719c8ead7SEwan D. Milne } 461819c8ead7SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 461919c8ead7SEwan D. Milne } 46201da177e4SLinus Torvalds return count; 46211da177e4SLinus Torvalds } 46221da177e4SLinus Torvalds return -EINVAL; 46231da177e4SLinus Torvalds } 462482069379SAkinobu Mita static DRIVER_ATTR_RW(max_luns); 46251da177e4SLinus Torvalds 462682069379SAkinobu Mita static ssize_t max_queue_show(struct device_driver *ddp, char *buf) 462778d4e5a0SDouglas Gilbert { 4628773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue); 462978d4e5a0SDouglas Gilbert } 4630cbf67842SDouglas Gilbert /* N.B. max_queue can be changed while there are queued commands. In flight 4631cbf67842SDouglas Gilbert * commands beyond the new max_queue will be completed. */ 463282069379SAkinobu Mita static ssize_t max_queue_store(struct device_driver *ddp, const char *buf, 463382069379SAkinobu Mita size_t count) 463478d4e5a0SDouglas Gilbert { 4635c4837394SDouglas Gilbert int j, n, k, a; 4636c4837394SDouglas Gilbert struct sdebug_queue *sqp; 463778d4e5a0SDouglas Gilbert 463878d4e5a0SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) && 4639c4837394SDouglas Gilbert (n <= SDEBUG_CANQUEUE)) { 4640c4837394SDouglas Gilbert block_unblock_all_queues(true); 4641c4837394SDouglas Gilbert k = 0; 4642c4837394SDouglas Gilbert for (j = 0, sqp = sdebug_q_arr; j < submit_queues; 4643c4837394SDouglas Gilbert ++j, ++sqp) { 4644c4837394SDouglas Gilbert a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE); 4645c4837394SDouglas Gilbert if (a > k) 4646c4837394SDouglas Gilbert k = a; 4647c4837394SDouglas Gilbert } 4648773642d9SDouglas Gilbert sdebug_max_queue = n; 4649c4837394SDouglas Gilbert if (k == SDEBUG_CANQUEUE) 4650cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4651cbf67842SDouglas Gilbert else if (k >= n) 4652cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, k + 1); 4653cbf67842SDouglas Gilbert else 4654cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4655c4837394SDouglas Gilbert block_unblock_all_queues(false); 465678d4e5a0SDouglas Gilbert return count; 465778d4e5a0SDouglas Gilbert } 465878d4e5a0SDouglas Gilbert return -EINVAL; 465978d4e5a0SDouglas Gilbert } 466082069379SAkinobu Mita static DRIVER_ATTR_RW(max_queue); 466178d4e5a0SDouglas Gilbert 466282069379SAkinobu Mita static ssize_t no_uld_show(struct device_driver *ddp, char *buf) 466378d4e5a0SDouglas Gilbert { 4664773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld); 466578d4e5a0SDouglas Gilbert } 466682069379SAkinobu Mita static DRIVER_ATTR_RO(no_uld); 466778d4e5a0SDouglas Gilbert 466882069379SAkinobu Mita static ssize_t scsi_level_show(struct device_driver *ddp, char *buf) 46691da177e4SLinus Torvalds { 4670773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level); 46711da177e4SLinus Torvalds } 467282069379SAkinobu Mita static DRIVER_ATTR_RO(scsi_level); 46731da177e4SLinus Torvalds 467482069379SAkinobu Mita static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf) 4675c65b1445SDouglas Gilbert { 4676773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb); 4677c65b1445SDouglas Gilbert } 467882069379SAkinobu Mita static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf, 467982069379SAkinobu Mita size_t count) 4680c65b1445SDouglas Gilbert { 4681c65b1445SDouglas Gilbert int n; 46820d01c5dfSDouglas Gilbert bool changed; 4683c65b1445SDouglas Gilbert 4684c65b1445SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4685773642d9SDouglas Gilbert changed = (sdebug_virtual_gb != n); 4686773642d9SDouglas Gilbert sdebug_virtual_gb = n; 468728898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 46880d01c5dfSDouglas Gilbert if (changed) { 46890d01c5dfSDouglas Gilbert struct sdebug_host_info *sdhp; 46900d01c5dfSDouglas Gilbert struct sdebug_dev_info *dp; 469128898873SFUJITA Tomonori 46924bc6b634SEwan D. Milne spin_lock(&sdebug_host_list_lock); 46930d01c5dfSDouglas Gilbert list_for_each_entry(sdhp, &sdebug_host_list, 46940d01c5dfSDouglas Gilbert host_list) { 46950d01c5dfSDouglas Gilbert list_for_each_entry(dp, &sdhp->dev_info_list, 46960d01c5dfSDouglas Gilbert dev_list) { 46970d01c5dfSDouglas Gilbert set_bit(SDEBUG_UA_CAPACITY_CHANGED, 46980d01c5dfSDouglas Gilbert dp->uas_bm); 46990d01c5dfSDouglas Gilbert } 47000d01c5dfSDouglas Gilbert } 47014bc6b634SEwan D. Milne spin_unlock(&sdebug_host_list_lock); 47020d01c5dfSDouglas Gilbert } 4703c65b1445SDouglas Gilbert return count; 4704c65b1445SDouglas Gilbert } 4705c65b1445SDouglas Gilbert return -EINVAL; 4706c65b1445SDouglas Gilbert } 470782069379SAkinobu Mita static DRIVER_ATTR_RW(virtual_gb); 4708c65b1445SDouglas Gilbert 470982069379SAkinobu Mita static ssize_t add_host_show(struct device_driver *ddp, char *buf) 47101da177e4SLinus Torvalds { 4711773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host); 47121da177e4SLinus Torvalds } 47131da177e4SLinus Torvalds 4714fd32119bSDouglas Gilbert static int sdebug_add_adapter(void); 4715fd32119bSDouglas Gilbert static void sdebug_remove_adapter(void); 4716fd32119bSDouglas Gilbert 471782069379SAkinobu Mita static ssize_t add_host_store(struct device_driver *ddp, const char *buf, 471882069379SAkinobu Mita size_t count) 47191da177e4SLinus Torvalds { 47201da177e4SLinus Torvalds int delta_hosts; 47211da177e4SLinus Torvalds 4722f3df41cfSFUJITA Tomonori if (sscanf(buf, "%d", &delta_hosts) != 1) 47231da177e4SLinus Torvalds return -EINVAL; 47241da177e4SLinus Torvalds if (delta_hosts > 0) { 47251da177e4SLinus Torvalds do { 47261da177e4SLinus Torvalds sdebug_add_adapter(); 47271da177e4SLinus Torvalds } while (--delta_hosts); 47281da177e4SLinus Torvalds } else if (delta_hosts < 0) { 47291da177e4SLinus Torvalds do { 47301da177e4SLinus Torvalds sdebug_remove_adapter(); 47311da177e4SLinus Torvalds } while (++delta_hosts); 47321da177e4SLinus Torvalds } 47331da177e4SLinus Torvalds return count; 47341da177e4SLinus Torvalds } 473582069379SAkinobu Mita static DRIVER_ATTR_RW(add_host); 47361da177e4SLinus Torvalds 473782069379SAkinobu Mita static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf) 473823183910SDouglas Gilbert { 4739773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno); 474023183910SDouglas Gilbert } 474182069379SAkinobu Mita static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf, 474282069379SAkinobu Mita size_t count) 474323183910SDouglas Gilbert { 474423183910SDouglas Gilbert int n; 474523183910SDouglas Gilbert 474623183910SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4747773642d9SDouglas Gilbert sdebug_vpd_use_hostno = n; 474823183910SDouglas Gilbert return count; 474923183910SDouglas Gilbert } 475023183910SDouglas Gilbert return -EINVAL; 475123183910SDouglas Gilbert } 475282069379SAkinobu Mita static DRIVER_ATTR_RW(vpd_use_hostno); 475323183910SDouglas Gilbert 4754c4837394SDouglas Gilbert static ssize_t statistics_show(struct device_driver *ddp, char *buf) 4755c4837394SDouglas Gilbert { 4756c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics); 4757c4837394SDouglas Gilbert } 4758c4837394SDouglas Gilbert static ssize_t statistics_store(struct device_driver *ddp, const char *buf, 4759c4837394SDouglas Gilbert size_t count) 4760c4837394SDouglas Gilbert { 4761c4837394SDouglas Gilbert int n; 4762c4837394SDouglas Gilbert 4763c4837394SDouglas Gilbert if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) { 4764c4837394SDouglas Gilbert if (n > 0) 4765c4837394SDouglas Gilbert sdebug_statistics = true; 4766c4837394SDouglas Gilbert else { 4767c4837394SDouglas Gilbert clear_queue_stats(); 4768c4837394SDouglas Gilbert sdebug_statistics = false; 4769c4837394SDouglas Gilbert } 4770c4837394SDouglas Gilbert return count; 4771c4837394SDouglas Gilbert } 4772c4837394SDouglas Gilbert return -EINVAL; 4773c4837394SDouglas Gilbert } 4774c4837394SDouglas Gilbert static DRIVER_ATTR_RW(statistics); 4775c4837394SDouglas Gilbert 477682069379SAkinobu Mita static ssize_t sector_size_show(struct device_driver *ddp, char *buf) 4777597136abSMartin K. Petersen { 4778773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size); 4779597136abSMartin K. Petersen } 478082069379SAkinobu Mita static DRIVER_ATTR_RO(sector_size); 4781597136abSMartin K. Petersen 4782c4837394SDouglas Gilbert static ssize_t submit_queues_show(struct device_driver *ddp, char *buf) 4783c4837394SDouglas Gilbert { 4784c4837394SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues); 4785c4837394SDouglas Gilbert } 4786c4837394SDouglas Gilbert static DRIVER_ATTR_RO(submit_queues); 4787c4837394SDouglas Gilbert 478882069379SAkinobu Mita static ssize_t dix_show(struct device_driver *ddp, char *buf) 4789c6a44287SMartin K. Petersen { 4790773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix); 4791c6a44287SMartin K. Petersen } 479282069379SAkinobu Mita static DRIVER_ATTR_RO(dix); 4793c6a44287SMartin K. Petersen 479482069379SAkinobu Mita static ssize_t dif_show(struct device_driver *ddp, char *buf) 4795c6a44287SMartin K. Petersen { 4796773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif); 4797c6a44287SMartin K. Petersen } 479882069379SAkinobu Mita static DRIVER_ATTR_RO(dif); 4799c6a44287SMartin K. Petersen 480082069379SAkinobu Mita static ssize_t guard_show(struct device_driver *ddp, char *buf) 4801c6a44287SMartin K. Petersen { 4802773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard); 4803c6a44287SMartin K. Petersen } 480482069379SAkinobu Mita static DRIVER_ATTR_RO(guard); 4805c6a44287SMartin K. Petersen 480682069379SAkinobu Mita static ssize_t ato_show(struct device_driver *ddp, char *buf) 4807c6a44287SMartin K. Petersen { 4808773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato); 4809c6a44287SMartin K. Petersen } 481082069379SAkinobu Mita static DRIVER_ATTR_RO(ato); 4811c6a44287SMartin K. Petersen 481282069379SAkinobu Mita static ssize_t map_show(struct device_driver *ddp, char *buf) 481344d92694SMartin K. Petersen { 481444d92694SMartin K. Petersen ssize_t count; 481544d92694SMartin K. Petersen 48165b94e232SMartin K. Petersen if (!scsi_debug_lbp()) 481744d92694SMartin K. Petersen return scnprintf(buf, PAGE_SIZE, "0-%u\n", 481844d92694SMartin K. Petersen sdebug_store_sectors); 481944d92694SMartin K. Petersen 4820c7badc90STejun Heo count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", 4821c7badc90STejun Heo (int)map_size, map_storep); 482244d92694SMartin K. Petersen buf[count++] = '\n'; 4823c7badc90STejun Heo buf[count] = '\0'; 482444d92694SMartin K. Petersen 482544d92694SMartin K. Petersen return count; 482644d92694SMartin K. Petersen } 482782069379SAkinobu Mita static DRIVER_ATTR_RO(map); 482844d92694SMartin K. Petersen 482982069379SAkinobu Mita static ssize_t removable_show(struct device_driver *ddp, char *buf) 4830d986788bSMartin Pitt { 4831773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0); 4832d986788bSMartin Pitt } 483382069379SAkinobu Mita static ssize_t removable_store(struct device_driver *ddp, const char *buf, 483482069379SAkinobu Mita size_t count) 4835d986788bSMartin Pitt { 4836d986788bSMartin Pitt int n; 4837d986788bSMartin Pitt 4838d986788bSMartin Pitt if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4839773642d9SDouglas Gilbert sdebug_removable = (n > 0); 4840d986788bSMartin Pitt return count; 4841d986788bSMartin Pitt } 4842d986788bSMartin Pitt return -EINVAL; 4843d986788bSMartin Pitt } 484482069379SAkinobu Mita static DRIVER_ATTR_RW(removable); 4845d986788bSMartin Pitt 4846cbf67842SDouglas Gilbert static ssize_t host_lock_show(struct device_driver *ddp, char *buf) 4847cbf67842SDouglas Gilbert { 4848773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock); 4849cbf67842SDouglas Gilbert } 4850185dd232SDouglas Gilbert /* N.B. sdebug_host_lock does nothing, kept for backward compatibility */ 4851cbf67842SDouglas Gilbert static ssize_t host_lock_store(struct device_driver *ddp, const char *buf, 4852cbf67842SDouglas Gilbert size_t count) 4853cbf67842SDouglas Gilbert { 4854185dd232SDouglas Gilbert int n; 4855cbf67842SDouglas Gilbert 4856cbf67842SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4857185dd232SDouglas Gilbert sdebug_host_lock = (n > 0); 4858185dd232SDouglas Gilbert return count; 4859cbf67842SDouglas Gilbert } 4860cbf67842SDouglas Gilbert return -EINVAL; 4861cbf67842SDouglas Gilbert } 4862cbf67842SDouglas Gilbert static DRIVER_ATTR_RW(host_lock); 4863cbf67842SDouglas Gilbert 4864c2248fc9SDouglas Gilbert static ssize_t strict_show(struct device_driver *ddp, char *buf) 4865c2248fc9SDouglas Gilbert { 4866773642d9SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict); 4867c2248fc9SDouglas Gilbert } 4868c2248fc9SDouglas Gilbert static ssize_t strict_store(struct device_driver *ddp, const char *buf, 4869c2248fc9SDouglas Gilbert size_t count) 4870c2248fc9SDouglas Gilbert { 4871c2248fc9SDouglas Gilbert int n; 4872c2248fc9SDouglas Gilbert 4873c2248fc9SDouglas Gilbert if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { 4874773642d9SDouglas Gilbert sdebug_strict = (n > 0); 4875c2248fc9SDouglas Gilbert return count; 4876c2248fc9SDouglas Gilbert } 4877c2248fc9SDouglas Gilbert return -EINVAL; 4878c2248fc9SDouglas Gilbert } 4879c2248fc9SDouglas Gilbert static DRIVER_ATTR_RW(strict); 4880c2248fc9SDouglas Gilbert 488109ba24c1SDouglas Gilbert static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf) 488209ba24c1SDouglas Gilbert { 488309ba24c1SDouglas Gilbert return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl); 488409ba24c1SDouglas Gilbert } 488509ba24c1SDouglas Gilbert static DRIVER_ATTR_RO(uuid_ctl); 488609ba24c1SDouglas Gilbert 4887cbf67842SDouglas Gilbert 488882069379SAkinobu Mita /* Note: The following array creates attribute files in the 488923183910SDouglas Gilbert /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these 489023183910SDouglas Gilbert files (over those found in the /sys/module/scsi_debug/parameters 489123183910SDouglas Gilbert directory) is that auxiliary actions can be triggered when an attribute 489223183910SDouglas Gilbert is changed. For example see: sdebug_add_host_store() above. 489323183910SDouglas Gilbert */ 48946ecaff7fSRandy Dunlap 489582069379SAkinobu Mita static struct attribute *sdebug_drv_attrs[] = { 489682069379SAkinobu Mita &driver_attr_delay.attr, 489782069379SAkinobu Mita &driver_attr_opts.attr, 489882069379SAkinobu Mita &driver_attr_ptype.attr, 489982069379SAkinobu Mita &driver_attr_dsense.attr, 490082069379SAkinobu Mita &driver_attr_fake_rw.attr, 490182069379SAkinobu Mita &driver_attr_no_lun_0.attr, 490282069379SAkinobu Mita &driver_attr_num_tgts.attr, 490382069379SAkinobu Mita &driver_attr_dev_size_mb.attr, 490482069379SAkinobu Mita &driver_attr_num_parts.attr, 490582069379SAkinobu Mita &driver_attr_every_nth.attr, 490682069379SAkinobu Mita &driver_attr_max_luns.attr, 490782069379SAkinobu Mita &driver_attr_max_queue.attr, 490882069379SAkinobu Mita &driver_attr_no_uld.attr, 490982069379SAkinobu Mita &driver_attr_scsi_level.attr, 491082069379SAkinobu Mita &driver_attr_virtual_gb.attr, 491182069379SAkinobu Mita &driver_attr_add_host.attr, 491282069379SAkinobu Mita &driver_attr_vpd_use_hostno.attr, 491382069379SAkinobu Mita &driver_attr_sector_size.attr, 4914c4837394SDouglas Gilbert &driver_attr_statistics.attr, 4915c4837394SDouglas Gilbert &driver_attr_submit_queues.attr, 491682069379SAkinobu Mita &driver_attr_dix.attr, 491782069379SAkinobu Mita &driver_attr_dif.attr, 491882069379SAkinobu Mita &driver_attr_guard.attr, 491982069379SAkinobu Mita &driver_attr_ato.attr, 492082069379SAkinobu Mita &driver_attr_map.attr, 492182069379SAkinobu Mita &driver_attr_removable.attr, 4922cbf67842SDouglas Gilbert &driver_attr_host_lock.attr, 4923cbf67842SDouglas Gilbert &driver_attr_ndelay.attr, 4924c2248fc9SDouglas Gilbert &driver_attr_strict.attr, 492509ba24c1SDouglas Gilbert &driver_attr_uuid_ctl.attr, 492682069379SAkinobu Mita NULL, 492782069379SAkinobu Mita }; 492882069379SAkinobu Mita ATTRIBUTE_GROUPS(sdebug_drv); 49291da177e4SLinus Torvalds 493011ddcecaSAkinobu Mita static struct device *pseudo_primary; 49318dea0d02SFUJITA Tomonori 49321da177e4SLinus Torvalds static int __init scsi_debug_init(void) 49331da177e4SLinus Torvalds { 49345f2578e5SFUJITA Tomonori unsigned long sz; 49351da177e4SLinus Torvalds int host_to_add; 49361da177e4SLinus Torvalds int k; 49376ecaff7fSRandy Dunlap int ret; 49381da177e4SLinus Torvalds 4939cbf67842SDouglas Gilbert atomic_set(&retired_max_queue, 0); 4940cbf67842SDouglas Gilbert 4941773642d9SDouglas Gilbert if (sdebug_ndelay >= 1000 * 1000 * 1000) { 4942c1287970STomas Winkler pr_warn("ndelay must be less than 1 second, ignored\n"); 4943773642d9SDouglas Gilbert sdebug_ndelay = 0; 4944773642d9SDouglas Gilbert } else if (sdebug_ndelay > 0) 4945c2206098SDouglas Gilbert sdebug_jdelay = JDELAY_OVERRIDDEN; 4946cbf67842SDouglas Gilbert 4947773642d9SDouglas Gilbert switch (sdebug_sector_size) { 4948597136abSMartin K. Petersen case 512: 4949597136abSMartin K. Petersen case 1024: 4950597136abSMartin K. Petersen case 2048: 4951597136abSMartin K. Petersen case 4096: 4952597136abSMartin K. Petersen break; 4953597136abSMartin K. Petersen default: 4954773642d9SDouglas Gilbert pr_err("invalid sector_size %d\n", sdebug_sector_size); 4955597136abSMartin K. Petersen return -EINVAL; 4956597136abSMartin K. Petersen } 4957597136abSMartin K. Petersen 4958773642d9SDouglas Gilbert switch (sdebug_dif) { 49598475c811SChristoph Hellwig case T10_PI_TYPE0_PROTECTION: 4960f46eb0e9SDouglas Gilbert break; 49618475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 49628475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 49638475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 4964f46eb0e9SDouglas Gilbert have_dif_prot = true; 4965c6a44287SMartin K. Petersen break; 4966c6a44287SMartin K. Petersen 4967c6a44287SMartin K. Petersen default: 4968c1287970STomas Winkler pr_err("dif must be 0, 1, 2 or 3\n"); 4969c6a44287SMartin K. Petersen return -EINVAL; 4970c6a44287SMartin K. Petersen } 4971c6a44287SMartin K. Petersen 4972773642d9SDouglas Gilbert if (sdebug_guard > 1) { 4973c1287970STomas Winkler pr_err("guard must be 0 or 1\n"); 4974c6a44287SMartin K. Petersen return -EINVAL; 4975c6a44287SMartin K. Petersen } 4976c6a44287SMartin K. Petersen 4977773642d9SDouglas Gilbert if (sdebug_ato > 1) { 4978c1287970STomas Winkler pr_err("ato must be 0 or 1\n"); 4979c6a44287SMartin K. Petersen return -EINVAL; 4980c6a44287SMartin K. Petersen } 4981c6a44287SMartin K. Petersen 4982773642d9SDouglas Gilbert if (sdebug_physblk_exp > 15) { 4983773642d9SDouglas Gilbert pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp); 4984ea61fca5SMartin K. Petersen return -EINVAL; 4985ea61fca5SMartin K. Petersen } 49868d039e22SDouglas Gilbert if (sdebug_max_luns > 256) { 49878d039e22SDouglas Gilbert pr_warn("max_luns can be no more than 256, use default\n"); 49888d039e22SDouglas Gilbert sdebug_max_luns = DEF_MAX_LUNS; 49898d039e22SDouglas Gilbert } 4990ea61fca5SMartin K. Petersen 4991773642d9SDouglas Gilbert if (sdebug_lowest_aligned > 0x3fff) { 4992773642d9SDouglas Gilbert pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned); 4993ea61fca5SMartin K. Petersen return -EINVAL; 4994ea61fca5SMartin K. Petersen } 4995ea61fca5SMartin K. Petersen 4996c4837394SDouglas Gilbert if (submit_queues < 1) { 4997c4837394SDouglas Gilbert pr_err("submit_queues must be 1 or more\n"); 4998c4837394SDouglas Gilbert return -EINVAL; 4999c4837394SDouglas Gilbert } 5000c4837394SDouglas Gilbert sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue), 5001c4837394SDouglas Gilbert GFP_KERNEL); 5002c4837394SDouglas Gilbert if (sdebug_q_arr == NULL) 5003c4837394SDouglas Gilbert return -ENOMEM; 5004c4837394SDouglas Gilbert for (k = 0; k < submit_queues; ++k) 5005c4837394SDouglas Gilbert spin_lock_init(&sdebug_q_arr[k].qc_lock); 5006c4837394SDouglas Gilbert 5007773642d9SDouglas Gilbert if (sdebug_dev_size_mb < 1) 5008773642d9SDouglas Gilbert sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ 5009773642d9SDouglas Gilbert sz = (unsigned long)sdebug_dev_size_mb * 1048576; 5010773642d9SDouglas Gilbert sdebug_store_sectors = sz / sdebug_sector_size; 501128898873SFUJITA Tomonori sdebug_capacity = get_sdebug_capacity(); 50121da177e4SLinus Torvalds 50131da177e4SLinus Torvalds /* play around with geometry, don't waste too much on track 0 */ 50141da177e4SLinus Torvalds sdebug_heads = 8; 50151da177e4SLinus Torvalds sdebug_sectors_per = 32; 5016773642d9SDouglas Gilbert if (sdebug_dev_size_mb >= 256) 50171da177e4SLinus Torvalds sdebug_heads = 64; 5018773642d9SDouglas Gilbert else if (sdebug_dev_size_mb >= 16) 5019fa785f0aSAndy Shevchenko sdebug_heads = 32; 50201da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 50211da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 50221da177e4SLinus Torvalds if (sdebug_cylinders_per >= 1024) { 50231da177e4SLinus Torvalds /* other LLDs do this; implies >= 1GB ram disk ... */ 50241da177e4SLinus Torvalds sdebug_heads = 255; 50251da177e4SLinus Torvalds sdebug_sectors_per = 63; 50261da177e4SLinus Torvalds sdebug_cylinders_per = (unsigned long)sdebug_capacity / 50271da177e4SLinus Torvalds (sdebug_sectors_per * sdebug_heads); 50281da177e4SLinus Torvalds } 50291da177e4SLinus Torvalds 5030b01f6f83SDouglas Gilbert if (sdebug_fake_rw == 0) { 50311da177e4SLinus Torvalds fake_storep = vmalloc(sz); 50321da177e4SLinus Torvalds if (NULL == fake_storep) { 5033c1287970STomas Winkler pr_err("out of memory, 1\n"); 5034c4837394SDouglas Gilbert ret = -ENOMEM; 5035c4837394SDouglas Gilbert goto free_q_arr; 50361da177e4SLinus Torvalds } 50371da177e4SLinus Torvalds memset(fake_storep, 0, sz); 5038773642d9SDouglas Gilbert if (sdebug_num_parts > 0) 5039f58b0efbSFUJITA Tomonori sdebug_build_parts(fake_storep, sz); 5040cbf67842SDouglas Gilbert } 50411da177e4SLinus Torvalds 5042773642d9SDouglas Gilbert if (sdebug_dix) { 5043c6a44287SMartin K. Petersen int dif_size; 5044c6a44287SMartin K. Petersen 50456ebf105cSChristoph Hellwig dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple); 5046c6a44287SMartin K. Petersen dif_storep = vmalloc(dif_size); 5047c6a44287SMartin K. Petersen 5048c1287970STomas Winkler pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep); 5049c6a44287SMartin K. Petersen 5050c6a44287SMartin K. Petersen if (dif_storep == NULL) { 5051c1287970STomas Winkler pr_err("out of mem. (DIX)\n"); 5052c6a44287SMartin K. Petersen ret = -ENOMEM; 5053c6a44287SMartin K. Petersen goto free_vm; 5054c6a44287SMartin K. Petersen } 5055c6a44287SMartin K. Petersen 5056c6a44287SMartin K. Petersen memset(dif_storep, 0xff, dif_size); 5057c6a44287SMartin K. Petersen } 5058c6a44287SMartin K. Petersen 50595b94e232SMartin K. Petersen /* Logical Block Provisioning */ 50605b94e232SMartin K. Petersen if (scsi_debug_lbp()) { 5061773642d9SDouglas Gilbert sdebug_unmap_max_blocks = 5062773642d9SDouglas Gilbert clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU); 50636014759cSMartin K. Petersen 5064773642d9SDouglas Gilbert sdebug_unmap_max_desc = 5065773642d9SDouglas Gilbert clamp(sdebug_unmap_max_desc, 0U, 256U); 50666014759cSMartin K. Petersen 5067773642d9SDouglas Gilbert sdebug_unmap_granularity = 5068773642d9SDouglas Gilbert clamp(sdebug_unmap_granularity, 1U, 0xffffffffU); 50696014759cSMartin K. Petersen 5070773642d9SDouglas Gilbert if (sdebug_unmap_alignment && 5071773642d9SDouglas Gilbert sdebug_unmap_granularity <= 5072773642d9SDouglas Gilbert sdebug_unmap_alignment) { 5073c1287970STomas Winkler pr_err("ERR: unmap_granularity <= unmap_alignment\n"); 5074c4837394SDouglas Gilbert ret = -EINVAL; 5075c4837394SDouglas Gilbert goto free_vm; 507644d92694SMartin K. Petersen } 507744d92694SMartin K. Petersen 5078b90ebc3dSAkinobu Mita map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1; 5079b90ebc3dSAkinobu Mita map_storep = vmalloc(BITS_TO_LONGS(map_size) * sizeof(long)); 508044d92694SMartin K. Petersen 5081c1287970STomas Winkler pr_info("%lu provisioning blocks\n", map_size); 508244d92694SMartin K. Petersen 508344d92694SMartin K. Petersen if (map_storep == NULL) { 5084c1287970STomas Winkler pr_err("out of mem. (MAP)\n"); 508544d92694SMartin K. Petersen ret = -ENOMEM; 508644d92694SMartin K. Petersen goto free_vm; 508744d92694SMartin K. Petersen } 508844d92694SMartin K. Petersen 5089b90ebc3dSAkinobu Mita bitmap_zero(map_storep, map_size); 509044d92694SMartin K. Petersen 509144d92694SMartin K. Petersen /* Map first 1KB for partition table */ 5092773642d9SDouglas Gilbert if (sdebug_num_parts) 509344d92694SMartin K. Petersen map_region(0, 2); 509444d92694SMartin K. Petersen } 509544d92694SMartin K. Petersen 50969b906779SNicholas Bellinger pseudo_primary = root_device_register("pseudo_0"); 50979b906779SNicholas Bellinger if (IS_ERR(pseudo_primary)) { 5098c1287970STomas Winkler pr_warn("root_device_register() error\n"); 50999b906779SNicholas Bellinger ret = PTR_ERR(pseudo_primary); 51006ecaff7fSRandy Dunlap goto free_vm; 51016ecaff7fSRandy Dunlap } 51026ecaff7fSRandy Dunlap ret = bus_register(&pseudo_lld_bus); 51036ecaff7fSRandy Dunlap if (ret < 0) { 5104c1287970STomas Winkler pr_warn("bus_register error: %d\n", ret); 51056ecaff7fSRandy Dunlap goto dev_unreg; 51066ecaff7fSRandy Dunlap } 51076ecaff7fSRandy Dunlap ret = driver_register(&sdebug_driverfs_driver); 51086ecaff7fSRandy Dunlap if (ret < 0) { 5109c1287970STomas Winkler pr_warn("driver_register error: %d\n", ret); 51106ecaff7fSRandy Dunlap goto bus_unreg; 51116ecaff7fSRandy Dunlap } 51121da177e4SLinus Torvalds 5113773642d9SDouglas Gilbert host_to_add = sdebug_add_host; 5114773642d9SDouglas Gilbert sdebug_add_host = 0; 51151da177e4SLinus Torvalds 51161da177e4SLinus Torvalds for (k = 0; k < host_to_add; k++) { 51171da177e4SLinus Torvalds if (sdebug_add_adapter()) { 5118c1287970STomas Winkler pr_err("sdebug_add_adapter failed k=%d\n", k); 51191da177e4SLinus Torvalds break; 51201da177e4SLinus Torvalds } 51211da177e4SLinus Torvalds } 51221da177e4SLinus Torvalds 5123773642d9SDouglas Gilbert if (sdebug_verbose) 5124773642d9SDouglas Gilbert pr_info("built %d host(s)\n", sdebug_add_host); 5125c1287970STomas Winkler 51261da177e4SLinus Torvalds return 0; 51276ecaff7fSRandy Dunlap 51286ecaff7fSRandy Dunlap bus_unreg: 51296ecaff7fSRandy Dunlap bus_unregister(&pseudo_lld_bus); 51306ecaff7fSRandy Dunlap dev_unreg: 51319b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 51326ecaff7fSRandy Dunlap free_vm: 513344d92694SMartin K. Petersen vfree(map_storep); 5134c6a44287SMartin K. Petersen vfree(dif_storep); 51356ecaff7fSRandy Dunlap vfree(fake_storep); 5136c4837394SDouglas Gilbert free_q_arr: 5137c4837394SDouglas Gilbert kfree(sdebug_q_arr); 51386ecaff7fSRandy Dunlap return ret; 51391da177e4SLinus Torvalds } 51401da177e4SLinus Torvalds 51411da177e4SLinus Torvalds static void __exit scsi_debug_exit(void) 51421da177e4SLinus Torvalds { 5143773642d9SDouglas Gilbert int k = sdebug_add_host; 51441da177e4SLinus Torvalds 51451da177e4SLinus Torvalds stop_all_queued(); 5146cbf67842SDouglas Gilbert free_all_queued(); 51471da177e4SLinus Torvalds for (; k; k--) 51481da177e4SLinus Torvalds sdebug_remove_adapter(); 51491da177e4SLinus Torvalds driver_unregister(&sdebug_driverfs_driver); 51501da177e4SLinus Torvalds bus_unregister(&pseudo_lld_bus); 51519b906779SNicholas Bellinger root_device_unregister(pseudo_primary); 51521da177e4SLinus Torvalds 51534d2b496fSEwan D. Milne vfree(map_storep); 5154c6a44287SMartin K. Petersen vfree(dif_storep); 51551da177e4SLinus Torvalds vfree(fake_storep); 5156c4837394SDouglas Gilbert kfree(sdebug_q_arr); 51571da177e4SLinus Torvalds } 51581da177e4SLinus Torvalds 51591da177e4SLinus Torvalds device_initcall(scsi_debug_init); 51601da177e4SLinus Torvalds module_exit(scsi_debug_exit); 51611da177e4SLinus Torvalds 51621da177e4SLinus Torvalds static void sdebug_release_adapter(struct device * dev) 51631da177e4SLinus Torvalds { 51641da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51651da177e4SLinus Torvalds 51661da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 51671da177e4SLinus Torvalds kfree(sdbg_host); 51681da177e4SLinus Torvalds } 51691da177e4SLinus Torvalds 51701da177e4SLinus Torvalds static int sdebug_add_adapter(void) 51711da177e4SLinus Torvalds { 51721da177e4SLinus Torvalds int k, devs_per_host; 51731da177e4SLinus Torvalds int error = 0; 51741da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 51758b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 51761da177e4SLinus Torvalds 517724669f75SJes Sorensen sdbg_host = kzalloc(sizeof(*sdbg_host),GFP_KERNEL); 51781da177e4SLinus Torvalds if (NULL == sdbg_host) { 5179c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51801da177e4SLinus Torvalds return -ENOMEM; 51811da177e4SLinus Torvalds } 51821da177e4SLinus Torvalds 51831da177e4SLinus Torvalds INIT_LIST_HEAD(&sdbg_host->dev_info_list); 51841da177e4SLinus Torvalds 5185773642d9SDouglas Gilbert devs_per_host = sdebug_num_tgts * sdebug_max_luns; 51861da177e4SLinus Torvalds for (k = 0; k < devs_per_host; k++) { 51875cb2fc06SFUJITA Tomonori sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL); 51885cb2fc06SFUJITA Tomonori if (!sdbg_devinfo) { 5189c1287970STomas Winkler pr_err("out of memory at line %d\n", __LINE__); 51901da177e4SLinus Torvalds error = -ENOMEM; 51911da177e4SLinus Torvalds goto clean; 51921da177e4SLinus Torvalds } 51931da177e4SLinus Torvalds } 51941da177e4SLinus Torvalds 51951da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 51961da177e4SLinus Torvalds list_add_tail(&sdbg_host->host_list, &sdebug_host_list); 51971da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 51981da177e4SLinus Torvalds 51991da177e4SLinus Torvalds sdbg_host->dev.bus = &pseudo_lld_bus; 52009b906779SNicholas Bellinger sdbg_host->dev.parent = pseudo_primary; 52011da177e4SLinus Torvalds sdbg_host->dev.release = &sdebug_release_adapter; 5202773642d9SDouglas Gilbert dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host); 52031da177e4SLinus Torvalds 52041da177e4SLinus Torvalds error = device_register(&sdbg_host->dev); 52051da177e4SLinus Torvalds 52061da177e4SLinus Torvalds if (error) 52071da177e4SLinus Torvalds goto clean; 52081da177e4SLinus Torvalds 5209773642d9SDouglas Gilbert ++sdebug_add_host; 52101da177e4SLinus Torvalds return error; 52111da177e4SLinus Torvalds 52121da177e4SLinus Torvalds clean: 52138b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 52148b40228fSFUJITA Tomonori dev_list) { 52151da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 52161da177e4SLinus Torvalds kfree(sdbg_devinfo); 52171da177e4SLinus Torvalds } 52181da177e4SLinus Torvalds 52191da177e4SLinus Torvalds kfree(sdbg_host); 52201da177e4SLinus Torvalds return error; 52211da177e4SLinus Torvalds } 52221da177e4SLinus Torvalds 52231da177e4SLinus Torvalds static void sdebug_remove_adapter(void) 52241da177e4SLinus Torvalds { 52251da177e4SLinus Torvalds struct sdebug_host_info * sdbg_host = NULL; 52261da177e4SLinus Torvalds 52271da177e4SLinus Torvalds spin_lock(&sdebug_host_list_lock); 52281da177e4SLinus Torvalds if (!list_empty(&sdebug_host_list)) { 52291da177e4SLinus Torvalds sdbg_host = list_entry(sdebug_host_list.prev, 52301da177e4SLinus Torvalds struct sdebug_host_info, host_list); 52311da177e4SLinus Torvalds list_del(&sdbg_host->host_list); 52321da177e4SLinus Torvalds } 52331da177e4SLinus Torvalds spin_unlock(&sdebug_host_list_lock); 52341da177e4SLinus Torvalds 52351da177e4SLinus Torvalds if (!sdbg_host) 52361da177e4SLinus Torvalds return; 52371da177e4SLinus Torvalds 52381da177e4SLinus Torvalds device_unregister(&sdbg_host->dev); 5239773642d9SDouglas Gilbert --sdebug_add_host; 52401da177e4SLinus Torvalds } 52411da177e4SLinus Torvalds 5242fd32119bSDouglas Gilbert static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth) 5243cbf67842SDouglas Gilbert { 5244cbf67842SDouglas Gilbert int num_in_q = 0; 5245cbf67842SDouglas Gilbert struct sdebug_dev_info *devip; 5246cbf67842SDouglas Gilbert 5247c4837394SDouglas Gilbert block_unblock_all_queues(true); 5248cbf67842SDouglas Gilbert devip = (struct sdebug_dev_info *)sdev->hostdata; 5249cbf67842SDouglas Gilbert if (NULL == devip) { 5250c4837394SDouglas Gilbert block_unblock_all_queues(false); 5251cbf67842SDouglas Gilbert return -ENODEV; 5252cbf67842SDouglas Gilbert } 5253cbf67842SDouglas Gilbert num_in_q = atomic_read(&devip->num_in_q); 5254c40ecc12SChristoph Hellwig 5255cbf67842SDouglas Gilbert if (qdepth < 1) 5256cbf67842SDouglas Gilbert qdepth = 1; 5257c4837394SDouglas Gilbert /* allow to exceed max host qc_arr elements for testing */ 5258c4837394SDouglas Gilbert if (qdepth > SDEBUG_CANQUEUE + 10) 5259c4837394SDouglas Gilbert qdepth = SDEBUG_CANQUEUE + 10; 5260db5ed4dfSChristoph Hellwig scsi_change_queue_depth(sdev, qdepth); 5261cbf67842SDouglas Gilbert 5262773642d9SDouglas Gilbert if (SDEBUG_OPT_Q_NOISE & sdebug_opts) { 5263c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n", 5264c40ecc12SChristoph Hellwig __func__, qdepth, num_in_q); 5265cbf67842SDouglas Gilbert } 5266c4837394SDouglas Gilbert block_unblock_all_queues(false); 5267cbf67842SDouglas Gilbert return sdev->queue_depth; 5268cbf67842SDouglas Gilbert } 5269cbf67842SDouglas Gilbert 5270c4837394SDouglas Gilbert static bool fake_timeout(struct scsi_cmnd *scp) 5271817fd66bSDouglas Gilbert { 5272c4837394SDouglas Gilbert if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) { 5273773642d9SDouglas Gilbert if (sdebug_every_nth < -1) 5274773642d9SDouglas Gilbert sdebug_every_nth = -1; 5275773642d9SDouglas Gilbert if (SDEBUG_OPT_TIMEOUT & sdebug_opts) 5276c4837394SDouglas Gilbert return true; /* ignore command causing timeout */ 5277773642d9SDouglas Gilbert else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts && 5278817fd66bSDouglas Gilbert scsi_medium_access_command(scp)) 5279c4837394SDouglas Gilbert return true; /* time out reads and writes */ 5280817fd66bSDouglas Gilbert } 5281c4837394SDouglas Gilbert return false; 5282817fd66bSDouglas Gilbert } 5283817fd66bSDouglas Gilbert 5284fd32119bSDouglas Gilbert static int scsi_debug_queuecommand(struct Scsi_Host *shost, 5285fd32119bSDouglas Gilbert struct scsi_cmnd *scp) 5286c2248fc9SDouglas Gilbert { 5287c2248fc9SDouglas Gilbert u8 sdeb_i; 5288c2248fc9SDouglas Gilbert struct scsi_device *sdp = scp->device; 5289c2248fc9SDouglas Gilbert const struct opcode_info_t *oip; 5290c2248fc9SDouglas Gilbert const struct opcode_info_t *r_oip; 5291c2248fc9SDouglas Gilbert struct sdebug_dev_info *devip; 5292c2248fc9SDouglas Gilbert u8 *cmd = scp->cmnd; 5293c2248fc9SDouglas Gilbert int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *); 5294c2248fc9SDouglas Gilbert int k, na; 5295c2248fc9SDouglas Gilbert int errsts = 0; 5296c2248fc9SDouglas Gilbert u32 flags; 5297c2248fc9SDouglas Gilbert u16 sa; 5298c2248fc9SDouglas Gilbert u8 opcode = cmd[0]; 5299c2248fc9SDouglas Gilbert bool has_wlun_rl; 5300c2248fc9SDouglas Gilbert 5301c2248fc9SDouglas Gilbert scsi_set_resid(scp, 0); 5302c4837394SDouglas Gilbert if (sdebug_statistics) 5303c4837394SDouglas Gilbert atomic_inc(&sdebug_cmnd_count); 5304f46eb0e9SDouglas Gilbert if (unlikely(sdebug_verbose && 5305f46eb0e9SDouglas Gilbert !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) { 5306c2248fc9SDouglas Gilbert char b[120]; 5307c2248fc9SDouglas Gilbert int n, len, sb; 5308c2248fc9SDouglas Gilbert 5309c2248fc9SDouglas Gilbert len = scp->cmd_len; 5310c2248fc9SDouglas Gilbert sb = (int)sizeof(b); 5311c2248fc9SDouglas Gilbert if (len > 32) 5312c2248fc9SDouglas Gilbert strcpy(b, "too long, over 32 bytes"); 5313c2248fc9SDouglas Gilbert else { 5314c2248fc9SDouglas Gilbert for (k = 0, n = 0; k < len && n < sb; ++k) 5315c2248fc9SDouglas Gilbert n += scnprintf(b + n, sb - n, "%02x ", 5316c2248fc9SDouglas Gilbert (u32)cmd[k]); 5317c2248fc9SDouglas Gilbert } 5318c4837394SDouglas Gilbert if (sdebug_mq_active) 5319c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: tag=%u, cmd %s\n", 5320c4837394SDouglas Gilbert my_name, blk_mq_unique_tag(scp->request), 5321c4837394SDouglas Gilbert b); 5322c4837394SDouglas Gilbert else 5323c4837394SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, 5324c4837394SDouglas Gilbert b); 5325c2248fc9SDouglas Gilbert } 532634d55434STomas Winkler has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS); 5327f46eb0e9SDouglas Gilbert if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl)) 5328f46eb0e9SDouglas Gilbert goto err_out; 5329c2248fc9SDouglas Gilbert 5330c2248fc9SDouglas Gilbert sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */ 5331c2248fc9SDouglas Gilbert oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */ 5332c2248fc9SDouglas Gilbert devip = (struct sdebug_dev_info *)sdp->hostdata; 5333f46eb0e9SDouglas Gilbert if (unlikely(!devip)) { 5334f46eb0e9SDouglas Gilbert devip = find_build_dev_info(sdp); 5335c2248fc9SDouglas Gilbert if (NULL == devip) 5336f46eb0e9SDouglas Gilbert goto err_out; 5337c2248fc9SDouglas Gilbert } 5338c2248fc9SDouglas Gilbert na = oip->num_attached; 5339c2248fc9SDouglas Gilbert r_pfp = oip->pfp; 5340c2248fc9SDouglas Gilbert if (na) { /* multiple commands with this opcode */ 5341c2248fc9SDouglas Gilbert r_oip = oip; 5342c2248fc9SDouglas Gilbert if (FF_SA & r_oip->flags) { 5343c2248fc9SDouglas Gilbert if (F_SA_LOW & oip->flags) 5344c2248fc9SDouglas Gilbert sa = 0x1f & cmd[1]; 5345c2248fc9SDouglas Gilbert else 5346c2248fc9SDouglas Gilbert sa = get_unaligned_be16(cmd + 8); 5347c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5348c2248fc9SDouglas Gilbert if (opcode == oip->opcode && sa == oip->sa) 5349c2248fc9SDouglas Gilbert break; 5350c2248fc9SDouglas Gilbert } 5351c2248fc9SDouglas Gilbert } else { /* since no service action only check opcode */ 5352c2248fc9SDouglas Gilbert for (k = 0; k <= na; oip = r_oip->arrp + k++) { 5353c2248fc9SDouglas Gilbert if (opcode == oip->opcode) 5354c2248fc9SDouglas Gilbert break; 5355c2248fc9SDouglas Gilbert } 5356c2248fc9SDouglas Gilbert } 5357c2248fc9SDouglas Gilbert if (k > na) { 5358c2248fc9SDouglas Gilbert if (F_SA_LOW & r_oip->flags) 5359c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4); 5360c2248fc9SDouglas Gilbert else if (F_SA_HIGH & r_oip->flags) 5361c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7); 5362c2248fc9SDouglas Gilbert else 5363c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5364c2248fc9SDouglas Gilbert goto check_cond; 5365c2248fc9SDouglas Gilbert } 5366c2248fc9SDouglas Gilbert } /* else (when na==0) we assume the oip is a match */ 5367c2248fc9SDouglas Gilbert flags = oip->flags; 5368f46eb0e9SDouglas Gilbert if (unlikely(F_INV_OP & flags)) { 5369c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5370c2248fc9SDouglas Gilbert goto check_cond; 5371c2248fc9SDouglas Gilbert } 5372f46eb0e9SDouglas Gilbert if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) { 5373773642d9SDouglas Gilbert if (sdebug_verbose) 5374773642d9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n", 5375773642d9SDouglas Gilbert my_name, opcode, " supported for wlun"); 5376c2248fc9SDouglas Gilbert mk_sense_invalid_opcode(scp); 5377c2248fc9SDouglas Gilbert goto check_cond; 5378c2248fc9SDouglas Gilbert } 5379f46eb0e9SDouglas Gilbert if (unlikely(sdebug_strict)) { /* check cdb against mask */ 5380c2248fc9SDouglas Gilbert u8 rem; 5381c2248fc9SDouglas Gilbert int j; 5382c2248fc9SDouglas Gilbert 5383c2248fc9SDouglas Gilbert for (k = 1; k < oip->len_mask[0] && k < 16; ++k) { 5384c2248fc9SDouglas Gilbert rem = ~oip->len_mask[k] & cmd[k]; 5385c2248fc9SDouglas Gilbert if (rem) { 5386c2248fc9SDouglas Gilbert for (j = 7; j >= 0; --j, rem <<= 1) { 5387c2248fc9SDouglas Gilbert if (0x80 & rem) 5388c2248fc9SDouglas Gilbert break; 5389c2248fc9SDouglas Gilbert } 5390c2248fc9SDouglas Gilbert mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j); 5391c2248fc9SDouglas Gilbert goto check_cond; 5392c2248fc9SDouglas Gilbert } 5393c2248fc9SDouglas Gilbert } 5394c2248fc9SDouglas Gilbert } 5395f46eb0e9SDouglas Gilbert if (unlikely(!(F_SKIP_UA & flags) && 5396b01f6f83SDouglas Gilbert find_first_bit(devip->uas_bm, 5397b01f6f83SDouglas Gilbert SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) { 5398f46eb0e9SDouglas Gilbert errsts = make_ua(scp, devip); 5399c2248fc9SDouglas Gilbert if (errsts) 5400c2248fc9SDouglas Gilbert goto check_cond; 5401c2248fc9SDouglas Gilbert } 5402c4837394SDouglas Gilbert if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) { 5403c2248fc9SDouglas Gilbert mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2); 5404773642d9SDouglas Gilbert if (sdebug_verbose) 5405c2248fc9SDouglas Gilbert sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: " 5406c2248fc9SDouglas Gilbert "%s\n", my_name, "initializing command " 5407c2248fc9SDouglas Gilbert "required"); 5408c2248fc9SDouglas Gilbert errsts = check_condition_result; 5409c2248fc9SDouglas Gilbert goto fini; 5410c2248fc9SDouglas Gilbert } 5411773642d9SDouglas Gilbert if (sdebug_fake_rw && (F_FAKE_RW & flags)) 5412c2248fc9SDouglas Gilbert goto fini; 5413f46eb0e9SDouglas Gilbert if (unlikely(sdebug_every_nth)) { 5414c4837394SDouglas Gilbert if (fake_timeout(scp)) 5415c2248fc9SDouglas Gilbert return 0; /* ignore command: make trouble */ 5416c2248fc9SDouglas Gilbert } 5417f46eb0e9SDouglas Gilbert if (likely(oip->pfp)) 5418f46eb0e9SDouglas Gilbert errsts = oip->pfp(scp, devip); /* calls a resp_* function */ 5419c2248fc9SDouglas Gilbert else if (r_pfp) /* if leaf function ptr NULL, try the root's */ 5420c2248fc9SDouglas Gilbert errsts = r_pfp(scp, devip); 5421c2248fc9SDouglas Gilbert 5422c2248fc9SDouglas Gilbert fini: 5423c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, errsts, 5424c2206098SDouglas Gilbert ((F_DELAY_OVERR & flags) ? 0 : sdebug_jdelay)); 5425c2248fc9SDouglas Gilbert check_cond: 5426c2248fc9SDouglas Gilbert return schedule_resp(scp, devip, check_condition_result, 0); 5427f46eb0e9SDouglas Gilbert err_out: 5428f46eb0e9SDouglas Gilbert return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, 0); 5429c2248fc9SDouglas Gilbert } 5430c2248fc9SDouglas Gilbert 54319e603ca0SFUJITA Tomonori static struct scsi_host_template sdebug_driver_template = { 5432c8ed555aSAl Viro .show_info = scsi_debug_show_info, 5433c8ed555aSAl Viro .write_info = scsi_debug_write_info, 54349e603ca0SFUJITA Tomonori .proc_name = sdebug_proc_name, 54359e603ca0SFUJITA Tomonori .name = "SCSI DEBUG", 54369e603ca0SFUJITA Tomonori .info = scsi_debug_info, 54379e603ca0SFUJITA Tomonori .slave_alloc = scsi_debug_slave_alloc, 54389e603ca0SFUJITA Tomonori .slave_configure = scsi_debug_slave_configure, 54399e603ca0SFUJITA Tomonori .slave_destroy = scsi_debug_slave_destroy, 54409e603ca0SFUJITA Tomonori .ioctl = scsi_debug_ioctl, 5441185dd232SDouglas Gilbert .queuecommand = scsi_debug_queuecommand, 5442cbf67842SDouglas Gilbert .change_queue_depth = sdebug_change_qdepth, 54439e603ca0SFUJITA Tomonori .eh_abort_handler = scsi_debug_abort, 54449e603ca0SFUJITA Tomonori .eh_device_reset_handler = scsi_debug_device_reset, 5445cbf67842SDouglas Gilbert .eh_target_reset_handler = scsi_debug_target_reset, 5446cbf67842SDouglas Gilbert .eh_bus_reset_handler = scsi_debug_bus_reset, 54479e603ca0SFUJITA Tomonori .eh_host_reset_handler = scsi_debug_host_reset, 5448c4837394SDouglas Gilbert .can_queue = SDEBUG_CANQUEUE, 54499e603ca0SFUJITA Tomonori .this_id = 7, 545065e8617fSMing Lin .sg_tablesize = SG_MAX_SEGMENTS, 5451cbf67842SDouglas Gilbert .cmd_per_lun = DEF_CMD_PER_LUN, 54526bb5e6e7SAkinobu Mita .max_sectors = -1U, 54539e603ca0SFUJITA Tomonori .use_clustering = DISABLE_CLUSTERING, 54549e603ca0SFUJITA Tomonori .module = THIS_MODULE, 5455c40ecc12SChristoph Hellwig .track_queue_depth = 1, 54569e603ca0SFUJITA Tomonori }; 54579e603ca0SFUJITA Tomonori 54581da177e4SLinus Torvalds static int sdebug_driver_probe(struct device * dev) 54591da177e4SLinus Torvalds { 54601da177e4SLinus Torvalds int error = 0; 54611da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 54621da177e4SLinus Torvalds struct Scsi_Host *hpnt; 5463f46eb0e9SDouglas Gilbert int hprot; 54641da177e4SLinus Torvalds 54651da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 54661da177e4SLinus Torvalds 5467773642d9SDouglas Gilbert sdebug_driver_template.can_queue = sdebug_max_queue; 5468773642d9SDouglas Gilbert if (sdebug_clustering) 54690759c666SAkinobu Mita sdebug_driver_template.use_clustering = ENABLE_CLUSTERING; 54701da177e4SLinus Torvalds hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); 54711da177e4SLinus Torvalds if (NULL == hpnt) { 5472c1287970STomas Winkler pr_err("scsi_host_alloc failed\n"); 54731da177e4SLinus Torvalds error = -ENODEV; 54741da177e4SLinus Torvalds return error; 54751da177e4SLinus Torvalds } 5476c4837394SDouglas Gilbert if (submit_queues > nr_cpu_ids) { 54779b130ad5SAlexey Dobriyan pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n", 5478c4837394SDouglas Gilbert my_name, submit_queues, nr_cpu_ids); 5479c4837394SDouglas Gilbert submit_queues = nr_cpu_ids; 5480c4837394SDouglas Gilbert } 5481c4837394SDouglas Gilbert /* Decide whether to tell scsi subsystem that we want mq */ 5482c4837394SDouglas Gilbert /* Following should give the same answer for each host */ 5483c4837394SDouglas Gilbert sdebug_mq_active = shost_use_blk_mq(hpnt) && (submit_queues > 1); 5484c4837394SDouglas Gilbert if (sdebug_mq_active) 5485c4837394SDouglas Gilbert hpnt->nr_hw_queues = submit_queues; 54861da177e4SLinus Torvalds 54871da177e4SLinus Torvalds sdbg_host->shost = hpnt; 54881da177e4SLinus Torvalds *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; 5489773642d9SDouglas Gilbert if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id)) 5490773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts + 1; 54911da177e4SLinus Torvalds else 5492773642d9SDouglas Gilbert hpnt->max_id = sdebug_num_tgts; 5493773642d9SDouglas Gilbert /* = sdebug_max_luns; */ 5494f2d3fd29STomas Winkler hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1; 54951da177e4SLinus Torvalds 5496f46eb0e9SDouglas Gilbert hprot = 0; 5497c6a44287SMartin K. Petersen 5498773642d9SDouglas Gilbert switch (sdebug_dif) { 5499c6a44287SMartin K. Petersen 55008475c811SChristoph Hellwig case T10_PI_TYPE1_PROTECTION: 5501f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE1_PROTECTION; 5502773642d9SDouglas Gilbert if (sdebug_dix) 5503f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE1_PROTECTION; 5504c6a44287SMartin K. Petersen break; 5505c6a44287SMartin K. Petersen 55068475c811SChristoph Hellwig case T10_PI_TYPE2_PROTECTION: 5507f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE2_PROTECTION; 5508773642d9SDouglas Gilbert if (sdebug_dix) 5509f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE2_PROTECTION; 5510c6a44287SMartin K. Petersen break; 5511c6a44287SMartin K. Petersen 55128475c811SChristoph Hellwig case T10_PI_TYPE3_PROTECTION: 5513f46eb0e9SDouglas Gilbert hprot = SHOST_DIF_TYPE3_PROTECTION; 5514773642d9SDouglas Gilbert if (sdebug_dix) 5515f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE3_PROTECTION; 5516c6a44287SMartin K. Petersen break; 5517c6a44287SMartin K. Petersen 5518c6a44287SMartin K. Petersen default: 5519773642d9SDouglas Gilbert if (sdebug_dix) 5520f46eb0e9SDouglas Gilbert hprot |= SHOST_DIX_TYPE0_PROTECTION; 5521c6a44287SMartin K. Petersen break; 5522c6a44287SMartin K. Petersen } 5523c6a44287SMartin K. Petersen 5524f46eb0e9SDouglas Gilbert scsi_host_set_prot(hpnt, hprot); 5525c6a44287SMartin K. Petersen 5526f46eb0e9SDouglas Gilbert if (have_dif_prot || sdebug_dix) 5527c1287970STomas Winkler pr_info("host protection%s%s%s%s%s%s%s\n", 5528f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "", 5529f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "", 5530f46eb0e9SDouglas Gilbert (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "", 5531f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "", 5532f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "", 5533f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "", 5534f46eb0e9SDouglas Gilbert (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : ""); 5535c6a44287SMartin K. Petersen 5536773642d9SDouglas Gilbert if (sdebug_guard == 1) 5537c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP); 5538c6a44287SMartin K. Petersen else 5539c6a44287SMartin K. Petersen scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC); 5540c6a44287SMartin K. Petersen 5541773642d9SDouglas Gilbert sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts); 5542773642d9SDouglas Gilbert sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts); 5543c4837394SDouglas Gilbert if (sdebug_every_nth) /* need stats counters for every_nth */ 5544c4837394SDouglas Gilbert sdebug_statistics = true; 55451da177e4SLinus Torvalds error = scsi_add_host(hpnt, &sdbg_host->dev); 55461da177e4SLinus Torvalds if (error) { 5547c1287970STomas Winkler pr_err("scsi_add_host failed\n"); 55481da177e4SLinus Torvalds error = -ENODEV; 55491da177e4SLinus Torvalds scsi_host_put(hpnt); 55501da177e4SLinus Torvalds } else 55511da177e4SLinus Torvalds scsi_scan_host(hpnt); 55521da177e4SLinus Torvalds 55531da177e4SLinus Torvalds return error; 55541da177e4SLinus Torvalds } 55551da177e4SLinus Torvalds 55561da177e4SLinus Torvalds static int sdebug_driver_remove(struct device * dev) 55571da177e4SLinus Torvalds { 55581da177e4SLinus Torvalds struct sdebug_host_info *sdbg_host; 55598b40228fSFUJITA Tomonori struct sdebug_dev_info *sdbg_devinfo, *tmp; 55601da177e4SLinus Torvalds 55611da177e4SLinus Torvalds sdbg_host = to_sdebug_host(dev); 55621da177e4SLinus Torvalds 55631da177e4SLinus Torvalds if (!sdbg_host) { 5564c1287970STomas Winkler pr_err("Unable to locate host info\n"); 55651da177e4SLinus Torvalds return -ENODEV; 55661da177e4SLinus Torvalds } 55671da177e4SLinus Torvalds 55681da177e4SLinus Torvalds scsi_remove_host(sdbg_host->shost); 55691da177e4SLinus Torvalds 55708b40228fSFUJITA Tomonori list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list, 55718b40228fSFUJITA Tomonori dev_list) { 55721da177e4SLinus Torvalds list_del(&sdbg_devinfo->dev_list); 55731da177e4SLinus Torvalds kfree(sdbg_devinfo); 55741da177e4SLinus Torvalds } 55751da177e4SLinus Torvalds 55761da177e4SLinus Torvalds scsi_host_put(sdbg_host->shost); 55771da177e4SLinus Torvalds return 0; 55781da177e4SLinus Torvalds } 55791da177e4SLinus Torvalds 55808dea0d02SFUJITA Tomonori static int pseudo_lld_bus_match(struct device *dev, 55818dea0d02SFUJITA Tomonori struct device_driver *dev_driver) 55821da177e4SLinus Torvalds { 55838dea0d02SFUJITA Tomonori return 1; 55848dea0d02SFUJITA Tomonori } 55851da177e4SLinus Torvalds 55868dea0d02SFUJITA Tomonori static struct bus_type pseudo_lld_bus = { 55878dea0d02SFUJITA Tomonori .name = "pseudo", 55888dea0d02SFUJITA Tomonori .match = pseudo_lld_bus_match, 55898dea0d02SFUJITA Tomonori .probe = sdebug_driver_probe, 55908dea0d02SFUJITA Tomonori .remove = sdebug_driver_remove, 559182069379SAkinobu Mita .drv_groups = sdebug_drv_groups, 55928dea0d02SFUJITA Tomonori }; 5593