blob: d323523f5f9de9255b0e474bd1f1da228f038688 [file] [log] [blame]
Thomas Gleixner8d7c56d2019-05-20 19:08:10 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
4 * Copyright (C) 1992 Eric Youngdale
5 * Simulate a host adapter with 2 disks attached. Do a lot of checking
6 * to make sure that we are not getting blocks mixed up, and PANIC if
7 * anything out of the ordinary is seen.
8 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
9 *
Douglas Gilbert80c49562018-02-09 21:36:39 -050010 * Copyright (C) 2001 - 2018 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070011 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040012 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 */
14
Tomas Winklerc12879702015-07-28 16:54:20 +030015
16#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/module.h>
19
20#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070021#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040022#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090023#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include <linux/types.h>
25#include <linux/string.h>
26#include <linux/genhd.h>
27#include <linux/fs.h>
28#include <linux/init.h>
29#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/vmalloc.h>
31#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020032#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070033#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050034#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040035#include <linux/spinlock.h>
36#include <linux/interrupt.h>
37#include <linux/atomic.h>
38#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040039#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020040#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050041
42#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090043
Martin K. Petersen44d92692009-10-15 14:45:27 -040044#include <asm/unaligned.h>
45
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090046#include <scsi/scsi.h>
47#include <scsi/scsi_cmnd.h>
48#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070049#include <scsi/scsi_host.h>
50#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090051#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040052#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040053#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054
Martin K. Petersenc6a44282009-01-04 03:08:19 -050055#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Douglas Gilbert773642d2016-04-25 12:16:28 -040058/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert80c49562018-02-09 21:36:39 -050059#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */
Douglas Gilbert40d07b52019-01-25 12:46:09 -050060static const char *sdebug_version_date = "20190125";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040061
62#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050064/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040065#define NO_ADDITIONAL_SENSE 0x0
66#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050067#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070068#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040069#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070070#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050071#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070072#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040073#define INVALID_FIELD_IN_PARAM_LIST 0x26
Martin K. Petersen9447b6c2019-02-08 18:37:25 -050074#define WRITE_PROTECTED 0x27
Douglas Gilbertcbf67842014-07-26 11:55:35 -040075#define UA_RESET_ASC 0x29
76#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050077#define TARGET_CHANGED_ASC 0x3f
78#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050079#define INSUFF_RES_ASC 0x55
80#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040081#define POWER_ON_RESET_ASCQ 0x0
82#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
83#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050084#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070085#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050086#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040087#define THRESHOLD_EXCEEDED 0x5d
88#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050089#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050090#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
91#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Douglas Gilbert481b5e52017-12-23 12:48:14 -050092#define WRITE_ERROR_ASC 0xc
Linus Torvalds1da177e2005-04-16 15:20:36 -070093
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050094/* Additional Sense Code Qualifier (ASCQ) */
95#define ACK_NAK_TO 0x3
96
Linus Torvalds1da177e2005-04-16 15:20:36 -070097/* Default values for driver parameters */
98#define DEF_NUM_HOST 1
99#define DEF_NUM_TGTS 1
100#define DEF_MAX_LUNS 1
101/* With these defaults, this driver will make 1 host with 1 target
102 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
103 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500104#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500105#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400106#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_DIF 0
109#define DEF_DIX 0
110#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_FAKE_RW 0
113#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400114#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500115#define DEF_LBPU 0
116#define DEF_LBPWS 0
117#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600118#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400120#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500121#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122#define DEF_NUM_PARTS 0
123#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500124#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100126#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400127#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200128#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400129#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500130#define DEF_SECTOR_SIZE 512
131#define DEF_UNMAP_ALIGNMENT 0
132#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400133#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
134#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500135#define DEF_VIRTUAL_GB 0
136#define DEF_VPD_USE_HOSTNO 1
137#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500138#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400139#define DEF_STATISTICS false
140#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400141#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400142#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400144#define SDEBUG_LUN_0_VAL 0
145
Douglas Gilbert773642d2016-04-25 12:16:28 -0400146/* bit mask values for sdebug_opts */
147#define SDEBUG_OPT_NOISE 1
148#define SDEBUG_OPT_MEDIUM_ERR 2
149#define SDEBUG_OPT_TIMEOUT 4
150#define SDEBUG_OPT_RECOVERED_ERR 8
151#define SDEBUG_OPT_TRANSPORT_ERR 16
152#define SDEBUG_OPT_DIF_ERR 32
153#define SDEBUG_OPT_DIX_ERR 64
154#define SDEBUG_OPT_MAC_TIMEOUT 128
155#define SDEBUG_OPT_SHORT_TRANSFER 0x100
156#define SDEBUG_OPT_Q_NOISE 0x200
157#define SDEBUG_OPT_ALL_TSF 0x400
158#define SDEBUG_OPT_RARE_TSF 0x800
159#define SDEBUG_OPT_N_WCE 0x1000
160#define SDEBUG_OPT_RESET_NOISE 0x2000
161#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800162#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400163#define SDEBUG_OPT_CMD_ABORT 0x10000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400164#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
165 SDEBUG_OPT_RESET_NOISE)
166#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
167 SDEBUG_OPT_TRANSPORT_ERR | \
168 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800169 SDEBUG_OPT_SHORT_TRANSFER | \
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400170 SDEBUG_OPT_HOST_BUSY | \
171 SDEBUG_OPT_CMD_ABORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400173 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400175 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500176 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400177 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400178 * - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
179 * CMD_ABORT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 *
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400181 * When "every_nth" < 0 then after "- every_nth" commands the selected
182 * error will be injected. The error will be injected on every subsequent
183 * command until some other action occurs; for example, the user writing
184 * a new value (other than -1 or 1) to every_nth:
185 * echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 */
187
Douglas Gilbertfd321192016-04-25 12:16:33 -0400188/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400189 * priority order. In the subset implemented here lower numbers have higher
190 * priority. The UA numbers should be a sequence starting from 0 with
191 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
192#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
193#define SDEBUG_UA_BUS_RESET 1
194#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500195#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500196#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500197#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
198#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
199#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400200
Douglas Gilbert773642d2016-04-25 12:16:28 -0400201/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 * sector on read commands: */
203#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500204#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205
206/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
207 * or "peripheral device" addressing (value 0) */
208#define SAM2_LUN_ADDRESS_METHOD 0
209
Douglas Gilbertc4837392016-05-06 00:40:26 -0400210/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
211 * (for response) per submit queue at one time. Can be reduced by max_queue
212 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
213 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
214 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
215 * but cannot exceed SDEBUG_CANQUEUE .
216 */
217#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
218#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400219#define DEF_CMD_PER_LUN 255
220
Douglas Gilbertfd321192016-04-25 12:16:33 -0400221#define F_D_IN 1
222#define F_D_OUT 2
223#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
224#define F_D_UNKN 8
225#define F_RL_WLUN_OK 0x10
226#define F_SKIP_UA 0x20
227#define F_DELAY_OVERR 0x40
228#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
229#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
230#define F_INV_OP 0x200
231#define F_FAKE_RW 0x400
232#define F_M_ACCESS 0x800 /* media access */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400233#define F_SSU_DELAY 0x1000
234#define F_SYNC_DELAY 0x2000
Douglas Gilbertfd321192016-04-25 12:16:33 -0400235
236#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500237#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400238#define FF_SA (F_SA_HIGH | F_SA_LOW)
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400239#define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400240
241#define SDEBUG_MAX_PARTS 4
242
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400243#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400244
245
246struct sdebug_dev_info {
247 struct list_head dev_list;
248 unsigned int channel;
249 unsigned int target;
250 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200251 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400252 struct sdebug_host_info *sdbg_host;
253 unsigned long uas_bm[1];
254 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400255 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400256 bool used;
257};
258
259struct sdebug_host_info {
260 struct list_head host_list;
261 struct Scsi_Host *shost;
262 struct device dev;
263 struct list_head dev_info_list;
264};
265
266#define to_sdebug_host(d) \
267 container_of(d, struct sdebug_host_info, dev)
268
Douglas Gilbert10bde982018-01-10 16:57:31 -0500269enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
270 SDEB_DEFER_WQ = 2};
271
Douglas Gilbertfd321192016-04-25 12:16:33 -0400272struct sdebug_defer {
273 struct hrtimer hrt;
274 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400275 int sqa_idx; /* index of sdebug_queue array */
276 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
277 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500278 bool init_hrt;
279 bool init_wq;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400280 bool aborted; /* true when blk_abort_request() already called */
Douglas Gilbert10bde982018-01-10 16:57:31 -0500281 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400282};
283
284struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400285 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
286 * instance indicates this slot is in use.
287 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400288 struct sdebug_defer *sd_dp;
289 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400290 unsigned int inj_recovered:1;
291 unsigned int inj_transport:1;
292 unsigned int inj_dif:1;
293 unsigned int inj_dix:1;
294 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800295 unsigned int inj_host_busy:1;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400296 unsigned int inj_cmd_abort:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400297};
298
Douglas Gilbertc4837392016-05-06 00:40:26 -0400299struct sdebug_queue {
300 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
301 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
302 spinlock_t qc_lock;
303 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400304};
305
Douglas Gilbertc4837392016-05-06 00:40:26 -0400306static atomic_t sdebug_cmnd_count; /* number of incoming commands */
307static atomic_t sdebug_completions; /* count of deferred completions */
308static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
309static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
310
Douglas Gilbertfd321192016-04-25 12:16:33 -0400311struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400312 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
313 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400314 u8 opcode; /* if num_attached > 0, preferred */
315 u16 sa; /* service action */
316 u32 flags; /* OR-ed set of SDEB_F_* */
317 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
318 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500319 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
320 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400321};
322
323/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500324enum sdeb_opcode_index {
325 SDEB_I_INVALID_OPCODE = 0,
326 SDEB_I_INQUIRY = 1,
327 SDEB_I_REPORT_LUNS = 2,
328 SDEB_I_REQUEST_SENSE = 3,
329 SDEB_I_TEST_UNIT_READY = 4,
330 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
331 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
332 SDEB_I_LOG_SENSE = 7,
333 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
334 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
335 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
336 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500337 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
338 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500339 SDEB_I_MAINT_IN = 14,
340 SDEB_I_MAINT_OUT = 15,
341 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500342 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500343 SDEB_I_RESERVE = 18, /* 6, 10 */
344 SDEB_I_RELEASE = 19, /* 6, 10 */
345 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
346 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
347 SDEB_I_ATA_PT = 22, /* 12, 16 */
348 SDEB_I_SEND_DIAG = 23,
349 SDEB_I_UNMAP = 24,
Bart Van Asschec2085562019-02-08 13:21:27 -0800350 SDEB_I_WRITE_BUFFER = 25,
351 SDEB_I_WRITE_SAME = 26, /* 10, 16 */
352 SDEB_I_SYNC_CACHE = 27, /* 10, 16 */
353 SDEB_I_COMP_WRITE = 28,
354 SDEB_I_LAST_ELEMENT = 29, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500355};
356
Douglas Gilbertc4837392016-05-06 00:40:26 -0400357
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500358static const unsigned char opcode_ind_arr[256] = {
359/* 0x0; 0x0->0x1f: 6 byte cdbs */
360 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
361 0, 0, 0, 0,
362 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
363 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
364 SDEB_I_RELEASE,
365 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
366 SDEB_I_ALLOW_REMOVAL, 0,
367/* 0x20; 0x20->0x3f: 10 byte cdbs */
368 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
369 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
370 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
371 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
372/* 0x40; 0x40->0x5f: 10 byte cdbs */
373 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
374 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
Bart Van Asschec2085562019-02-08 13:21:27 -0800375 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500376 SDEB_I_RELEASE,
377 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400378/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
381 0, SDEB_I_VARIABLE_LEN,
382/* 0x80; 0x80->0x9f: 16 byte cdbs */
383 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
384 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500385 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500386 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN_16, SDEB_I_SERV_ACT_OUT_16,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500387/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
388 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
389 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500390 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
391 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500392 0, 0, 0, 0, 0, 0, 0, 0,
393 0, 0, 0, 0, 0, 0, 0, 0,
394/* 0xc0; 0xc0->0xff: vendor specific */
395 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
396 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
398 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
399};
400
Douglas Gilbert80c49562018-02-09 21:36:39 -0500401/*
402 * The following "response" functions return the SCSI mid-level's 4 byte
403 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
404 * command completion, they can mask their return value with
405 * SDEG_RES_IMMED_MASK .
406 */
407#define SDEG_RES_IMMED_MASK 0x40000000
408
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500409static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
410static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
411static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
412static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
413static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
416static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500418static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500419static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
420static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
421static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
422static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
423static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500424static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
425static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500426static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
427static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500428static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500429static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500430static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500431
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500432/*
433 * The following are overflow arrays for cdbs that "hit" the same index in
434 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
435 * should be placed in opcode_info_arr[], the others should be placed here.
436 */
437static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500438 {0, 0x1a, 0, F_D_IN, NULL, NULL,
439 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
440};
441
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500442static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500443 {0, 0x15, 0, F_D_OUT, NULL, NULL,
444 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
445};
446
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500447static const struct opcode_info_t read_iarr[] = {
448 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500449 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500450 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500451 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500452 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500453 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500454 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500455 0xc7, 0, 0, 0, 0} },
456};
457
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500458static const struct opcode_info_t write_iarr[] = {
459 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
460 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
461 0, 0, 0, 0, 0, 0} },
462 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
463 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
464 0, 0, 0} },
465 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
466 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
467 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500468};
469
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500470static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500471 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
472 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500473 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500474};
475
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500476static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
477 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500478 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500479 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500480 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
481 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
482 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500483};
484
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500485static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500486 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500487 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500488 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500489 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500490 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500491 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500492};
493
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500494static const struct opcode_info_t write_same_iarr[] = {
495 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500496 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500497 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500498};
499
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500500static const struct opcode_info_t reserve_iarr[] = {
501 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500502 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
503};
504
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500505static const struct opcode_info_t release_iarr[] = {
506 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500507 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
508};
509
Douglas Gilbert80c49562018-02-09 21:36:39 -0500510static const struct opcode_info_t sync_cache_iarr[] = {
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400511 {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500512 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
513 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
514};
515
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500516
517/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
518 * plus the terminating elements for logic that scans this table such as
519 * REPORT SUPPORTED OPERATION CODES. */
520static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
521/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500522 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500523 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500524 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500525 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
526 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
527 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500528 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500529 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
530 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
531 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
532 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500533/* 5 */
534 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
535 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
536 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
537 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
538 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
539 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
540 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500541 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
542 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500543 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500544 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
545 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500546 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
547 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
548 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500549/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500550 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
551 resp_write_dt0, write_iarr, /* WRITE(16) */
552 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500553 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400554 {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500555 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500556 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
557 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
558 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
559 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500560 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
561 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
562 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500563 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
564 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
565 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
566 0xff, 0, 0xc7, 0, 0, 0, 0} },
567/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500568 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
569 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500570 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500571 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
572 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500573 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
574 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
575 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
576 0xff, 0xff} },
577 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
578 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500579 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
580 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500581 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
582 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500583 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
584 0} },
585/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500586 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
587 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500588 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
589 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
590 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
591 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
592 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
593 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500594 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500595 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500596/* 25 */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500597 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
598 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
599 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500600 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
601 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
602 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
603 0, 0, 0, 0, 0} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400604 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500605 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500606 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500607 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500608 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500609 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500610 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500611
Bart Van Asschec2085562019-02-08 13:21:27 -0800612/* 29 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500613 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
614 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
615};
616
Douglas Gilbert773642d2016-04-25 12:16:28 -0400617static int sdebug_add_host = DEF_NUM_HOST;
618static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500619static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400620static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400621static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
622static int sdebug_dif = DEF_DIF;
623static int sdebug_dix = DEF_DIX;
624static int sdebug_dsense = DEF_D_SENSE;
625static int sdebug_every_nth = DEF_EVERY_NTH;
626static int sdebug_fake_rw = DEF_FAKE_RW;
627static unsigned int sdebug_guard = DEF_GUARD;
628static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
629static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400630static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500631static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
632static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400633static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400634static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400635static int sdebug_no_lun_0 = DEF_NO_LUN_0;
636static int sdebug_no_uld;
637static int sdebug_num_parts = DEF_NUM_PARTS;
638static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
639static int sdebug_opt_blks = DEF_OPT_BLKS;
640static int sdebug_opts = DEF_OPTS;
641static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100642static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400643static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400644static int sdebug_scsi_level = DEF_SCSI_LEVEL;
645static int sdebug_sector_size = DEF_SECTOR_SIZE;
646static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
647static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
648static unsigned int sdebug_lbpu = DEF_LBPU;
649static unsigned int sdebug_lbpws = DEF_LBPWS;
650static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
651static unsigned int sdebug_lbprz = DEF_LBPRZ;
652static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
653static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
654static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
655static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
656static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400657static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400658static bool sdebug_removable = DEF_REMOVABLE;
659static bool sdebug_clustering;
660static bool sdebug_host_lock = DEF_HOST_LOCK;
661static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500662static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400663static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400664static bool have_dif_prot;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400665static bool write_since_sync;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400666static bool sdebug_statistics = DEF_STATISTICS;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -0500667static bool sdebug_wp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400669static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670static sector_t sdebug_capacity; /* in sectors */
671
672/* old BIOS stuff, kernel may get rid of them but some mode sense pages
673 may still need them */
674static int sdebug_heads; /* heads per disk */
675static int sdebug_cylinders_per; /* cylinders per surface */
676static int sdebug_sectors_per; /* sectors per cylinder */
677
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678static LIST_HEAD(sdebug_host_list);
679static DEFINE_SPINLOCK(sdebug_host_list_lock);
680
Douglas Gilbertfd321192016-04-25 12:16:33 -0400681static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200682static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400683static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
Martin K. Petersen44d92692009-10-15 14:45:27 -0400685static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400686static int num_aborts;
687static int num_dev_resets;
688static int num_target_resets;
689static int num_bus_resets;
690static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500691static int dix_writes;
692static int dix_reads;
693static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
Douglas Gilbertc4837392016-05-06 00:40:26 -0400695static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
696static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400697
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698static DEFINE_RWLOCK(atomic_rw);
699
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400700static char sdebug_proc_name[] = MY_NAME;
701static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703static struct bus_type pseudo_lld_bus;
704
705static struct device_driver sdebug_driverfs_driver = {
706 .name = sdebug_proc_name,
707 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708};
709
710static const int check_condition_result =
711 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
712
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500713static const int illegal_condition_result =
714 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
715
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400716static const int device_qfull_result =
717 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
718
Douglas Gilbertfd321192016-04-25 12:16:33 -0400719
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400720/* Only do the extra work involved in logical block provisioning if one or
721 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
722 * real reads and writes (i.e. not skipping them for speed).
723 */
724static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400725{
726 return 0 == sdebug_fake_rw &&
727 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
728}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400729
Douglas Gilbert40d07b52019-01-25 12:46:09 -0500730static void *lba2fake_store(unsigned long long lba)
Akinobu Mita14faa942013-09-18 21:27:24 +0900731{
732 lba = do_div(lba, sdebug_store_sectors);
733
Douglas Gilbert773642d2016-04-25 12:16:28 -0400734 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900735}
736
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200737static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900738{
Arnd Bergmann49413112015-11-20 17:38:28 +0100739 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900740
741 return dif_storep + sector;
742}
743
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900744static void sdebug_max_tgts_luns(void)
745{
746 struct sdebug_host_info *sdbg_host;
747 struct Scsi_Host *hpnt;
748
749 spin_lock(&sdebug_host_list_lock);
750 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
751 hpnt = sdbg_host->shost;
752 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400753 (sdebug_num_tgts > hpnt->this_id))
754 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900755 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400756 hpnt->max_id = sdebug_num_tgts;
757 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300758 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900759 }
760 spin_unlock(&sdebug_host_list_lock);
761}
762
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500763enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
764
765/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400766static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
767 enum sdeb_cmd_data c_d,
768 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500769{
770 unsigned char *sbuff;
771 u8 sks[4];
772 int sl, asc;
773
774 sbuff = scp->sense_buffer;
775 if (!sbuff) {
776 sdev_printk(KERN_ERR, scp->device,
777 "%s: sense_buffer is NULL\n", __func__);
778 return;
779 }
780 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
781 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400782 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500783 memset(sks, 0, sizeof(sks));
784 sks[0] = 0x80;
785 if (c_d)
786 sks[0] |= 0x40;
787 if (in_bit >= 0) {
788 sks[0] |= 0x8;
789 sks[0] |= 0x7 & in_bit;
790 }
791 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400792 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500793 sl = sbuff[7] + 8;
794 sbuff[7] = sl;
795 sbuff[sl] = 0x2;
796 sbuff[sl + 1] = 0x6;
797 memcpy(sbuff + sl + 4, sks, 3);
798 } else
799 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400800 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500801 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
802 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
803 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
804}
805
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400806static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900807{
808 unsigned char *sbuff;
809
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400810 sbuff = scp->sense_buffer;
811 if (!sbuff) {
812 sdev_printk(KERN_ERR, scp->device,
813 "%s: sense_buffer is NULL\n", __func__);
814 return;
815 }
816 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900817
Douglas Gilbert773642d2016-04-25 12:16:28 -0400818 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900819
Douglas Gilbert773642d2016-04-25 12:16:28 -0400820 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400821 sdev_printk(KERN_INFO, scp->device,
822 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
823 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900824}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825
Douglas Gilbertfd321192016-04-25 12:16:33 -0400826static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500827{
828 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
829}
830
Nathan Chancellor6f4e6262019-02-07 09:07:20 -0700831static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
832 void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400834 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400835 if (0x1261 == cmd)
836 sdev_printk(KERN_INFO, dev,
837 "%s: BLKFLSBUF [0x1261]\n", __func__);
838 else if (0x5331 == cmd)
839 sdev_printk(KERN_INFO, dev,
840 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
841 __func__);
842 else
843 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
844 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 }
846 return -EINVAL;
847 /* return -ENOTTY; // correct return but upsets fdisk */
848}
849
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500850static void config_cdb_len(struct scsi_device *sdev)
851{
852 switch (sdebug_cdb_len) {
853 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
854 sdev->use_10_for_rw = false;
855 sdev->use_16_for_rw = false;
856 sdev->use_10_for_ms = false;
857 break;
858 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
859 sdev->use_10_for_rw = true;
860 sdev->use_16_for_rw = false;
861 sdev->use_10_for_ms = false;
862 break;
863 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
864 sdev->use_10_for_rw = true;
865 sdev->use_16_for_rw = false;
866 sdev->use_10_for_ms = true;
867 break;
868 case 16:
869 sdev->use_10_for_rw = false;
870 sdev->use_16_for_rw = true;
871 sdev->use_10_for_ms = true;
872 break;
873 case 32: /* No knobs to suggest this so same as 16 for now */
874 sdev->use_10_for_rw = false;
875 sdev->use_16_for_rw = true;
876 sdev->use_10_for_ms = true;
877 break;
878 default:
879 pr_warn("unexpected cdb_len=%d, force to 10\n",
880 sdebug_cdb_len);
881 sdev->use_10_for_rw = true;
882 sdev->use_16_for_rw = false;
883 sdev->use_10_for_ms = false;
884 sdebug_cdb_len = 10;
885 break;
886 }
887}
888
889static void all_config_cdb_len(void)
890{
891 struct sdebug_host_info *sdbg_host;
892 struct Scsi_Host *shost;
893 struct scsi_device *sdev;
894
895 spin_lock(&sdebug_host_list_lock);
896 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
897 shost = sdbg_host->shost;
898 shost_for_each_device(sdev, shost) {
899 config_cdb_len(sdev);
900 }
901 }
902 spin_unlock(&sdebug_host_list_lock);
903}
904
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500905static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
906{
907 struct sdebug_host_info *sdhp;
908 struct sdebug_dev_info *dp;
909
910 spin_lock(&sdebug_host_list_lock);
911 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
912 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
913 if ((devip->sdbg_host == dp->sdbg_host) &&
914 (devip->target == dp->target))
915 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
916 }
917 }
918 spin_unlock(&sdebug_host_list_lock);
919}
920
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400921static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400923 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400924
925 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
926 if (k != SDEBUG_NUM_UAS) {
927 const char *cp = NULL;
928
929 switch (k) {
930 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400931 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
932 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400933 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400934 cp = "power on reset";
935 break;
936 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400937 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
938 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400939 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400940 cp = "bus reset";
941 break;
942 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400943 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
944 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400945 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400946 cp = "mode parameters changed";
947 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500948 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400949 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
950 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400951 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500952 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500953 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500954 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400955 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400956 TARGET_CHANGED_ASC,
957 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400958 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500959 cp = "microcode has been changed";
960 break;
961 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400962 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500963 TARGET_CHANGED_ASC,
964 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400965 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500966 cp = "microcode has been changed without reset";
967 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500968 case SDEBUG_UA_LUNS_CHANGED:
969 /*
970 * SPC-3 behavior is to report a UNIT ATTENTION with
971 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
972 * on the target, until a REPORT LUNS command is
973 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400974 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500975 * values as struct scsi_device->scsi_level.
976 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400977 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500978 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400979 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500980 TARGET_CHANGED_ASC,
981 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400982 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500983 cp = "reported luns data has changed";
984 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400985 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400986 pr_warn("unexpected unit attention code=%d\n", k);
987 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400988 cp = "unknown";
989 break;
990 }
991 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400992 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400993 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400994 "%s reports: Unit attention: %s\n",
995 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 return check_condition_result;
997 }
998 return 0;
999}
1000
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001001/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001002static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003 int arr_len)
1004{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001005 int act_len;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001006 struct scsi_data_buffer *sdb = &scp->sdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001007
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001008 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001009 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001010 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbert773642d2016-04-25 12:16:28 -04001011 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001012
1013 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1014 arr, arr_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001015 scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017 return 0;
1018}
1019
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001020/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1021 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1022 * calls, not required to write in ascending offset order. Assumes resid
1023 * set to scsi_bufflen() prior to any calls.
1024 */
1025static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1026 int arr_len, unsigned int off_dst)
1027{
1028 int act_len, n;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001029 struct scsi_data_buffer *sdb = &scp->sdb;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001030 off_t skip = off_dst;
1031
1032 if (sdb->length <= off_dst)
1033 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001034 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001035 return DID_ERROR << 16;
1036
1037 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1038 arr, arr_len, skip);
1039 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
Bart Van Assche42d387b2019-02-08 13:25:00 -08001040 __func__, off_dst, scsi_bufflen(scp), act_len,
1041 scsi_get_resid(scp));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001042 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001043 scsi_set_resid(scp, min(scsi_get_resid(scp), n));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001044 return 0;
1045}
1046
1047/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1048 * 'arr' or -1 if error.
1049 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001050static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1051 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001052{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001053 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001055 if (scp->sc_data_direction != DMA_TO_DEVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001057
1058 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059}
1060
1061
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001062static char sdebug_inq_vendor_id[9] = "Linux ";
1063static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001064static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001065/* Use some locally assigned NAAs for SAS addresses. */
1066static const u64 naa3_comp_a = 0x3222222000000000ULL;
1067static const u64 naa3_comp_b = 0x3333333000000000ULL;
1068static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001069
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001070/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001071static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1072 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001073 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001074 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001075{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001076 int num, port_a;
1077 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001079 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 /* T10 vendor identifier field format (faked) */
1081 arr[0] = 0x2; /* ASCII */
1082 arr[1] = 0x1;
1083 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001084 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1085 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1087 num = 8 + 16 + dev_id_str_len;
1088 arr[3] = num;
1089 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001090 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001091 if (sdebug_uuid_ctl) {
1092 /* Locally assigned UUID */
1093 arr[num++] = 0x1; /* binary (not necessarily sas) */
1094 arr[num++] = 0xa; /* PIV=0, lu, naa */
1095 arr[num++] = 0x0;
1096 arr[num++] = 0x12;
1097 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1098 arr[num++] = 0x0;
1099 memcpy(arr + num, lu_name, 16);
1100 num += 16;
1101 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001102 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001103 arr[num++] = 0x1; /* binary (not necessarily sas) */
1104 arr[num++] = 0x3; /* PIV=0, lu, naa */
1105 arr[num++] = 0x0;
1106 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001107 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001108 num += 8;
1109 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001110 /* Target relative port number */
1111 arr[num++] = 0x61; /* proto=sas, binary */
1112 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1113 arr[num++] = 0x0; /* reserved */
1114 arr[num++] = 0x4; /* length */
1115 arr[num++] = 0x0; /* reserved */
1116 arr[num++] = 0x0; /* reserved */
1117 arr[num++] = 0x0;
1118 arr[num++] = 0x1; /* relative port A */
1119 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001120 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001121 arr[num++] = 0x61; /* proto=sas, binary */
1122 arr[num++] = 0x93; /* piv=1, target port, naa */
1123 arr[num++] = 0x0;
1124 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001125 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001126 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001127 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001128 arr[num++] = 0x61; /* proto=sas, binary */
1129 arr[num++] = 0x95; /* piv=1, target port group id */
1130 arr[num++] = 0x0;
1131 arr[num++] = 0x4;
1132 arr[num++] = 0;
1133 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001134 put_unaligned_be16(port_group_id, arr + num);
1135 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001136 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001137 arr[num++] = 0x61; /* proto=sas, binary */
1138 arr[num++] = 0xa3; /* piv=1, target device, naa */
1139 arr[num++] = 0x0;
1140 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001141 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001142 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001143 /* SCSI name string: Target device identifier */
1144 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1145 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1146 arr[num++] = 0x0;
1147 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001148 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001149 num += 12;
1150 snprintf(b, sizeof(b), "%08X", target_dev_id);
1151 memcpy(arr + num, b, 8);
1152 num += 8;
1153 memset(arr + num, 0, 4);
1154 num += 4;
1155 return num;
1156}
1157
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001158static unsigned char vpd84_data[] = {
1159/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1160 0x22,0x22,0x22,0x0,0xbb,0x1,
1161 0x22,0x22,0x22,0x0,0xbb,0x2,
1162};
1163
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001164/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001165static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001166{
1167 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1168 return sizeof(vpd84_data);
1169}
1170
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001171/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001172static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001173{
1174 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001175 const char *na1 = "https://www.kernel.org/config";
1176 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001177 int plen, olen;
1178
1179 arr[num++] = 0x1; /* lu, storage config */
1180 arr[num++] = 0x0; /* reserved */
1181 arr[num++] = 0x0;
1182 olen = strlen(na1);
1183 plen = olen + 1;
1184 if (plen % 4)
1185 plen = ((plen / 4) + 1) * 4;
1186 arr[num++] = plen; /* length, null termianted, padded */
1187 memcpy(arr + num, na1, olen);
1188 memset(arr + num + olen, 0, plen - olen);
1189 num += plen;
1190
1191 arr[num++] = 0x4; /* lu, logging */
1192 arr[num++] = 0x0; /* reserved */
1193 arr[num++] = 0x0;
1194 olen = strlen(na2);
1195 plen = olen + 1;
1196 if (plen % 4)
1197 plen = ((plen / 4) + 1) * 4;
1198 arr[num++] = plen; /* length, null terminated, padded */
1199 memcpy(arr + num, na2, olen);
1200 memset(arr + num + olen, 0, plen - olen);
1201 num += plen;
1202
1203 return num;
1204}
1205
1206/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001207static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001208{
1209 int num = 0;
1210 int port_a, port_b;
1211
1212 port_a = target_dev_id + 1;
1213 port_b = port_a + 1;
1214 arr[num++] = 0x0; /* reserved */
1215 arr[num++] = 0x0; /* reserved */
1216 arr[num++] = 0x0;
1217 arr[num++] = 0x1; /* relative port 1 (primary) */
1218 memset(arr + num, 0, 6);
1219 num += 6;
1220 arr[num++] = 0x0;
1221 arr[num++] = 12; /* length tp descriptor */
1222 /* naa-5 target port identifier (A) */
1223 arr[num++] = 0x61; /* proto=sas, binary */
1224 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1225 arr[num++] = 0x0; /* reserved */
1226 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001227 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001228 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001229 arr[num++] = 0x0; /* reserved */
1230 arr[num++] = 0x0; /* reserved */
1231 arr[num++] = 0x0;
1232 arr[num++] = 0x2; /* relative port 2 (secondary) */
1233 memset(arr + num, 0, 6);
1234 num += 6;
1235 arr[num++] = 0x0;
1236 arr[num++] = 12; /* length tp descriptor */
1237 /* naa-5 target port identifier (B) */
1238 arr[num++] = 0x61; /* proto=sas, binary */
1239 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1240 arr[num++] = 0x0; /* reserved */
1241 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001242 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001243 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001244
1245 return num;
1246}
1247
1248
1249static unsigned char vpd89_data[] = {
1250/* from 4th byte */ 0,0,0,0,
1251'l','i','n','u','x',' ',' ',' ',
1252'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1253'1','2','3','4',
12540x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12550xec,0,0,0,
12560x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12570,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12580x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12590x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12600x53,0x41,
12610x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12620x20,0x20,
12630x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12640x10,0x80,
12650,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12660x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12670x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12680,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12690x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12700x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12710,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12720,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12730,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12750x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12760,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12770xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12780,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,0,
12790,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12800,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12810,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12830,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12840,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12880,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12890,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12900,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1291};
1292
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001293/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001294static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001295{
1296 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1297 return sizeof(vpd89_data);
1298}
1299
1300
1301static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001302 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1303 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1304 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1305 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001306};
1307
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001308/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001309static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001310{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001311 unsigned int gran;
1312
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001313 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001314
1315 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001316 if (sdebug_opt_xferlen_exp != 0 &&
1317 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1318 gran = 1 << sdebug_opt_xferlen_exp;
1319 else
1320 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001321 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001322
1323 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001324 if (sdebug_store_sectors > 0x400)
1325 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001326
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001327 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001328 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001329
Douglas Gilbert773642d2016-04-25 12:16:28 -04001330 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001331 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001332 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001333
1334 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001335 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001336 }
1337
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001338 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001339 if (sdebug_unmap_alignment) {
1340 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001341 arr[28] |= 0x80; /* UGAVALID */
1342 }
1343
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001344 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001345 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001346
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001347 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001348 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001349
1350 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001351
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001352 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353}
1354
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001355/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001356static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001357{
1358 memset(arr, 0, 0x3c);
1359 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001360 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1361 arr[2] = 0;
1362 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001363
1364 return 0x3c;
1365}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001367/* Logical block provisioning VPD page (SBC-4) */
1368static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001369{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001370 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001371 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001372 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001373 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001374 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001375 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001376 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001377 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001378 if (sdebug_lbprz && scsi_debug_lbp())
1379 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1380 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1381 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1382 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001383 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001384}
1385
Linus Torvalds1da177e2005-04-16 15:20:36 -07001386#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001387#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001388
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001389static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390{
1391 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001392 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001393 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001394 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001395 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396
Douglas Gilbert773642d2016-04-25 12:16:28 -04001397 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001398 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1399 if (! arr)
1400 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001401 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001402 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001403 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001404 pq_pdt = TYPE_WLUN; /* present, wlun */
1405 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1406 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001407 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001408 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001409 arr[0] = pq_pdt;
1410 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001411 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001412 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001413 return check_condition_result;
1414 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001415 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001416 char lu_id_str[6];
1417 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001418
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001419 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1420 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001421 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001422 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001423 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001424 (devip->target * 1000) + devip->lun);
1425 target_dev_id = ((host_no + 1) * 2000) +
1426 (devip->target * 1000) - 3;
1427 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001428 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001429 arr[1] = cmd[2]; /*sanity */
1430 n = 4;
1431 arr[n++] = 0x0; /* this page */
1432 arr[n++] = 0x80; /* unit serial number */
1433 arr[n++] = 0x83; /* device identification */
1434 arr[n++] = 0x84; /* software interface ident. */
1435 arr[n++] = 0x85; /* management network addresses */
1436 arr[n++] = 0x86; /* extended inquiry */
1437 arr[n++] = 0x87; /* mode page policy */
1438 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001439 if (is_disk) { /* SBC only */
1440 arr[n++] = 0x89; /* ATA information */
1441 arr[n++] = 0xb0; /* Block limits */
1442 arr[n++] = 0xb1; /* Block characteristics */
1443 arr[n++] = 0xb2; /* Logical Block Prov */
1444 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001445 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001447 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001449 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001450 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001451 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001452 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1453 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001454 lu_id_str, len,
1455 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001456 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1457 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001458 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459 } else if (0x85 == cmd[2]) { /* Management network addresses */
1460 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001461 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 } else if (0x86 == cmd[2]) { /* extended inquiry */
1463 arr[1] = cmd[2]; /*sanity */
1464 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001465 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001466 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001467 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001468 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1469 else
1470 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001471 arr[5] = 0x7; /* head of q, ordered + simple q's */
1472 } else if (0x87 == cmd[2]) { /* mode page policy */
1473 arr[1] = cmd[2]; /*sanity */
1474 arr[3] = 0x8; /* number of following entries */
1475 arr[4] = 0x2; /* disconnect-reconnect mp */
1476 arr[6] = 0x80; /* mlus, shared */
1477 arr[8] = 0x18; /* protocol specific lu */
1478 arr[10] = 0x82; /* mlus, per initiator port */
1479 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1480 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001481 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1482 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001483 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001484 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001485 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001486 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001487 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001488 arr[3] = inquiry_vpd_b0(&arr[4]);
1489 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001490 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001491 arr[3] = inquiry_vpd_b1(&arr[4]);
1492 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001493 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001494 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001496 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001497 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 return check_condition_result;
1499 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001500 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001501 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001502 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001503 kfree(arr);
1504 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001505 }
1506 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001507 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1508 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001509 arr[3] = 2; /* response_data_format==2 */
1510 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001511 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001512 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001513 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001514 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001515 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001516 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001517 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1518 memcpy(&arr[16], sdebug_inq_product_id, 16);
1519 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001520 /* Use Vendor Specific area to place driver date in ASCII hex */
1521 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001523 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1524 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001525 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001526 if (is_disk) { /* SBC-4 no version claimed */
1527 put_unaligned_be16(0x600, arr + n);
1528 n += 2;
1529 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1530 put_unaligned_be16(0x525, arr + n);
1531 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001532 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001533 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001534 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001536 kfree(arr);
1537 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538}
1539
Douglas Gilbertfd321192016-04-25 12:16:33 -04001540static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1541 0, 0, 0x0, 0x0};
1542
John Pittman91d4c752018-02-09 21:12:43 -05001543static int resp_requests(struct scsi_cmnd *scp,
1544 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001545{
John Pittman91d4c752018-02-09 21:12:43 -05001546 unsigned char *sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001547 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001548 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001549 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550 int len = 18;
1551
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001552 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001553 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001554 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001555 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001556 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001557 arr[0] = 0x72;
1558 arr[1] = 0x0; /* NO_SENSE in sense_key */
1559 arr[2] = THRESHOLD_EXCEEDED;
1560 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001561 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001562 } else {
1563 arr[0] = 0x70;
1564 arr[2] = 0x0; /* NO_SENSE in sense_key */
1565 arr[7] = 0xa; /* 18 byte sense buffer */
1566 arr[12] = THRESHOLD_EXCEEDED;
1567 arr[13] = 0xff; /* TEST set and MRIE==6 */
1568 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001569 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001570 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001571 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001572 ; /* have sense and formats match */
1573 else if (arr[0] <= 0x70) {
1574 if (dsense) {
1575 memset(arr, 0, 8);
1576 arr[0] = 0x72;
1577 len = 8;
1578 } else {
1579 memset(arr, 0, 18);
1580 arr[0] = 0x70;
1581 arr[7] = 0xa;
1582 }
1583 } else if (dsense) {
1584 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001585 arr[0] = 0x72;
1586 arr[1] = sbuff[2]; /* sense key */
1587 arr[2] = sbuff[12]; /* asc */
1588 arr[3] = sbuff[13]; /* ascq */
1589 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001590 } else {
1591 memset(arr, 0, 18);
1592 arr[0] = 0x70;
1593 arr[2] = sbuff[1];
1594 arr[7] = 0xa;
1595 arr[12] = sbuff[1];
1596 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001597 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001598
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001599 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001600 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001601 return fill_from_dev_buffer(scp, arr, len);
1602}
1603
John Pittman91d4c752018-02-09 21:12:43 -05001604static int resp_start_stop(struct scsi_cmnd *scp,
1605 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001606{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001607 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001608 int power_cond, stop;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001609 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001610
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001611 power_cond = (cmd[4] & 0xf0) >> 4;
1612 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001613 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001614 return check_condition_result;
1615 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001616 stop = !(cmd[4] & 1);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001617 changing = atomic_read(&devip->stopped) == !stop;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001618 atomic_xchg(&devip->stopped, stop);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001619 if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */
1620 return SDEG_RES_IMMED_MASK;
1621 else
1622 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001623}
1624
FUJITA Tomonori28898872008-03-30 00:59:55 +09001625static sector_t get_sdebug_capacity(void)
1626{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001627 static const unsigned int gibibyte = 1073741824;
1628
1629 if (sdebug_virtual_gb > 0)
1630 return (sector_t)sdebug_virtual_gb *
1631 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001632 else
1633 return sdebug_store_sectors;
1634}
1635
Linus Torvalds1da177e2005-04-16 15:20:36 -07001636#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001637static int resp_readcap(struct scsi_cmnd *scp,
1638 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639{
1640 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001641 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001643 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001644 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001646 if (sdebug_capacity < 0xffffffff) {
1647 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001648 put_unaligned_be32(capac, arr + 0);
1649 } else
1650 put_unaligned_be32(0xffffffff, arr + 0);
1651 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001652 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1653}
1654
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001655#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001656static int resp_readcap16(struct scsi_cmnd *scp,
1657 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001658{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001659 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001660 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001661 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001662
Douglas Gilbert773642d2016-04-25 12:16:28 -04001663 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001664 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001665 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001666 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001667 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1668 put_unaligned_be32(sdebug_sector_size, arr + 8);
1669 arr[13] = sdebug_physblk_exp & 0xf;
1670 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001671
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001672 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001673 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001674 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1675 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1676 * in the wider field maps to 0 in this field.
1677 */
1678 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1679 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001680 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001681
Douglas Gilbert773642d2016-04-25 12:16:28 -04001682 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001683
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001684 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001685 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001686 arr[12] |= 1; /* PROT_EN */
1687 }
1688
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001689 return fill_from_dev_buffer(scp, arr,
1690 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1691}
1692
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001693#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1694
John Pittman91d4c752018-02-09 21:12:43 -05001695static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1696 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001697{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001698 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001699 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001700 int host_no = devip->sdbg_host->shost->host_no;
1701 int n, ret, alen, rlen;
1702 int port_group_a, port_group_b, port_a, port_b;
1703
Douglas Gilbert773642d2016-04-25 12:16:28 -04001704 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001705 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1706 if (! arr)
1707 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001708 /*
1709 * EVPD page 0x88 states we have two ports, one
1710 * real and a fake port with no device connected.
1711 * So we create two port groups with one port each
1712 * and set the group with port B to unavailable.
1713 */
1714 port_a = 0x1; /* relative port A */
1715 port_b = 0x2; /* relative port B */
1716 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001717 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001718 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001719 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001720
1721 /*
1722 * The asymmetric access state is cycled according to the host_id.
1723 */
1724 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001725 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001726 arr[n++] = host_no % 3; /* Asymm access state */
1727 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001728 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001729 arr[n++] = 0x0; /* Active/Optimized path */
1730 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001731 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001732 put_unaligned_be16(port_group_a, arr + n);
1733 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001734 arr[n++] = 0; /* Reserved */
1735 arr[n++] = 0; /* Status code */
1736 arr[n++] = 0; /* Vendor unique */
1737 arr[n++] = 0x1; /* One port per group */
1738 arr[n++] = 0; /* Reserved */
1739 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001740 put_unaligned_be16(port_a, arr + n);
1741 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001742 arr[n++] = 3; /* Port unavailable */
1743 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001744 put_unaligned_be16(port_group_b, arr + n);
1745 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001746 arr[n++] = 0; /* Reserved */
1747 arr[n++] = 0; /* Status code */
1748 arr[n++] = 0; /* Vendor unique */
1749 arr[n++] = 0x1; /* One port per group */
1750 arr[n++] = 0; /* Reserved */
1751 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001752 put_unaligned_be16(port_b, arr + n);
1753 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001754
1755 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001756 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001757
1758 /*
1759 * Return the smallest value of either
1760 * - The allocated length
1761 * - The constructed command length
1762 * - The maximum array size
1763 */
1764 rlen = min(alen,n);
1765 ret = fill_from_dev_buffer(scp, arr,
1766 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1767 kfree(arr);
1768 return ret;
1769}
1770
Douglas Gilbertfd321192016-04-25 12:16:33 -04001771static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1772 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001773{
1774 bool rctd;
1775 u8 reporting_opts, req_opcode, sdeb_i, supp;
1776 u16 req_sa, u;
1777 u32 alloc_len, a_len;
1778 int k, offset, len, errsts, count, bump, na;
1779 const struct opcode_info_t *oip;
1780 const struct opcode_info_t *r_oip;
1781 u8 *arr;
1782 u8 *cmd = scp->cmnd;
1783
1784 rctd = !!(cmd[2] & 0x80);
1785 reporting_opts = cmd[2] & 0x7;
1786 req_opcode = cmd[3];
1787 req_sa = get_unaligned_be16(cmd + 4);
1788 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001789 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001790 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1791 return check_condition_result;
1792 }
1793 if (alloc_len > 8192)
1794 a_len = 8192;
1795 else
1796 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001797 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001798 if (NULL == arr) {
1799 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1800 INSUFF_RES_ASCQ);
1801 return check_condition_result;
1802 }
1803 switch (reporting_opts) {
1804 case 0: /* all commands */
1805 /* count number of commands */
1806 for (count = 0, oip = opcode_info_arr;
1807 oip->num_attached != 0xff; ++oip) {
1808 if (F_INV_OP & oip->flags)
1809 continue;
1810 count += (oip->num_attached + 1);
1811 }
1812 bump = rctd ? 20 : 8;
1813 put_unaligned_be32(count * bump, arr);
1814 for (offset = 4, oip = opcode_info_arr;
1815 oip->num_attached != 0xff && offset < a_len; ++oip) {
1816 if (F_INV_OP & oip->flags)
1817 continue;
1818 na = oip->num_attached;
1819 arr[offset] = oip->opcode;
1820 put_unaligned_be16(oip->sa, arr + offset + 2);
1821 if (rctd)
1822 arr[offset + 5] |= 0x2;
1823 if (FF_SA & oip->flags)
1824 arr[offset + 5] |= 0x1;
1825 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1826 if (rctd)
1827 put_unaligned_be16(0xa, arr + offset + 8);
1828 r_oip = oip;
1829 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1830 if (F_INV_OP & oip->flags)
1831 continue;
1832 offset += bump;
1833 arr[offset] = oip->opcode;
1834 put_unaligned_be16(oip->sa, arr + offset + 2);
1835 if (rctd)
1836 arr[offset + 5] |= 0x2;
1837 if (FF_SA & oip->flags)
1838 arr[offset + 5] |= 0x1;
1839 put_unaligned_be16(oip->len_mask[0],
1840 arr + offset + 6);
1841 if (rctd)
1842 put_unaligned_be16(0xa,
1843 arr + offset + 8);
1844 }
1845 oip = r_oip;
1846 offset += bump;
1847 }
1848 break;
1849 case 1: /* one command: opcode only */
1850 case 2: /* one command: opcode plus service action */
1851 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1852 sdeb_i = opcode_ind_arr[req_opcode];
1853 oip = &opcode_info_arr[sdeb_i];
1854 if (F_INV_OP & oip->flags) {
1855 supp = 1;
1856 offset = 4;
1857 } else {
1858 if (1 == reporting_opts) {
1859 if (FF_SA & oip->flags) {
1860 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1861 2, 2);
1862 kfree(arr);
1863 return check_condition_result;
1864 }
1865 req_sa = 0;
1866 } else if (2 == reporting_opts &&
1867 0 == (FF_SA & oip->flags)) {
1868 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1869 kfree(arr); /* point at requested sa */
1870 return check_condition_result;
1871 }
1872 if (0 == (FF_SA & oip->flags) &&
1873 req_opcode == oip->opcode)
1874 supp = 3;
1875 else if (0 == (FF_SA & oip->flags)) {
1876 na = oip->num_attached;
1877 for (k = 0, oip = oip->arrp; k < na;
1878 ++k, ++oip) {
1879 if (req_opcode == oip->opcode)
1880 break;
1881 }
1882 supp = (k >= na) ? 1 : 3;
1883 } else if (req_sa != oip->sa) {
1884 na = oip->num_attached;
1885 for (k = 0, oip = oip->arrp; k < na;
1886 ++k, ++oip) {
1887 if (req_sa == oip->sa)
1888 break;
1889 }
1890 supp = (k >= na) ? 1 : 3;
1891 } else
1892 supp = 3;
1893 if (3 == supp) {
1894 u = oip->len_mask[0];
1895 put_unaligned_be16(u, arr + 2);
1896 arr[4] = oip->opcode;
1897 for (k = 1; k < u; ++k)
1898 arr[4 + k] = (k < 16) ?
1899 oip->len_mask[k] : 0xff;
1900 offset = 4 + u;
1901 } else
1902 offset = 4;
1903 }
1904 arr[1] = (rctd ? 0x80 : 0) | supp;
1905 if (rctd) {
1906 put_unaligned_be16(0xa, arr + offset);
1907 offset += 12;
1908 }
1909 break;
1910 default:
1911 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1912 kfree(arr);
1913 return check_condition_result;
1914 }
1915 offset = (offset < a_len) ? offset : a_len;
1916 len = (offset < alloc_len) ? offset : alloc_len;
1917 errsts = fill_from_dev_buffer(scp, arr, len);
1918 kfree(arr);
1919 return errsts;
1920}
1921
Douglas Gilbertfd321192016-04-25 12:16:33 -04001922static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1923 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001924{
1925 bool repd;
1926 u32 alloc_len, len;
1927 u8 arr[16];
1928 u8 *cmd = scp->cmnd;
1929
1930 memset(arr, 0, sizeof(arr));
1931 repd = !!(cmd[2] & 0x80);
1932 alloc_len = get_unaligned_be32(cmd + 6);
1933 if (alloc_len < 4) {
1934 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1935 return check_condition_result;
1936 }
1937 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1938 arr[1] = 0x1; /* ITNRS */
1939 if (repd) {
1940 arr[3] = 0xc;
1941 len = 16;
1942 } else
1943 len = 4;
1944
1945 len = (len < alloc_len) ? len : alloc_len;
1946 return fill_from_dev_buffer(scp, arr, len);
1947}
1948
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949/* <<Following mode page info copied from ST318451LW>> */
1950
John Pittman91d4c752018-02-09 21:12:43 -05001951static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952{ /* Read-Write Error Recovery page for mode_sense */
1953 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1954 5, 0, 0xff, 0xff};
1955
1956 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1957 if (1 == pcontrol)
1958 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1959 return sizeof(err_recov_pg);
1960}
1961
John Pittman91d4c752018-02-09 21:12:43 -05001962static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963{ /* Disconnect-Reconnect page for mode_sense */
1964 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1965 0, 0, 0, 0, 0, 0, 0, 0};
1966
1967 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1968 if (1 == pcontrol)
1969 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1970 return sizeof(disconnect_pg);
1971}
1972
John Pittman91d4c752018-02-09 21:12:43 -05001973static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001974{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001975 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1976 0, 0, 0, 0, 0, 0, 0, 0,
1977 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001979 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001980 put_unaligned_be16(sdebug_sectors_per, p + 10);
1981 put_unaligned_be16(sdebug_sector_size, p + 12);
1982 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001983 p[20] |= 0x20; /* should agree with INQUIRY */
1984 if (1 == pcontrol)
1985 memset(p + 2, 0, sizeof(format_pg) - 2);
1986 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001987}
1988
Douglas Gilbertfd321192016-04-25 12:16:33 -04001989static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1990 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1991 0, 0, 0, 0};
1992
John Pittman91d4c752018-02-09 21:12:43 -05001993static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001995 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1996 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
1997 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
1999
Douglas Gilbert773642d2016-04-25 12:16:28 -04002000 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002001 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002002 memcpy(p, caching_pg, sizeof(caching_pg));
2003 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002004 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2005 else if (2 == pcontrol)
2006 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 return sizeof(caching_pg);
2008}
2009
Douglas Gilbertfd321192016-04-25 12:16:33 -04002010static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2011 0, 0, 0x2, 0x4b};
2012
John Pittman91d4c752018-02-09 21:12:43 -05002013static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002015 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002016 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002017 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002018 0, 0, 0x2, 0x4b};
2019
Douglas Gilbert773642d2016-04-25 12:16:28 -04002020 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002022 else
2023 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002024
Douglas Gilbert773642d2016-04-25 12:16:28 -04002025 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002026 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2027
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2029 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002030 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2031 else if (2 == pcontrol)
2032 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033 return sizeof(ctrl_m_pg);
2034}
2035
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002036
John Pittman91d4c752018-02-09 21:12:43 -05002037static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002038{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002039 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2040 0, 0, 0x0, 0x0};
2041 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2042 0, 0, 0x0, 0x0};
2043
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2045 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002046 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2047 else if (2 == pcontrol)
2048 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002049 return sizeof(iec_m_pg);
2050}
2051
John Pittman91d4c752018-02-09 21:12:43 -05002052static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002053{ /* SAS SSP mode page - short format for mode_sense */
2054 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2055 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2056
2057 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2058 if (1 == pcontrol)
2059 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2060 return sizeof(sas_sf_m_pg);
2061}
2062
2063
John Pittman91d4c752018-02-09 21:12:43 -05002064static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002065 int target_dev_id)
2066{ /* SAS phy control and discover mode page for mode_sense */
2067 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2068 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002069 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2070 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002071 0x2, 0, 0, 0, 0, 0, 0, 0,
2072 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2073 0, 0, 0, 0, 0, 0, 0, 0,
2074 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002075 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2076 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002077 0x3, 0, 0, 0, 0, 0, 0, 0,
2078 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2079 0, 0, 0, 0, 0, 0, 0, 0,
2080 };
2081 int port_a, port_b;
2082
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002083 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2084 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2085 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2086 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002087 port_a = target_dev_id + 1;
2088 port_b = port_a + 1;
2089 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002090 put_unaligned_be32(port_a, p + 20);
2091 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002092 if (1 == pcontrol)
2093 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2094 return sizeof(sas_pcd_m_pg);
2095}
2096
John Pittman91d4c752018-02-09 21:12:43 -05002097static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002098{ /* SAS SSP shared protocol specific port mode subpage */
2099 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2100 0, 0, 0, 0, 0, 0, 0, 0,
2101 };
2102
2103 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2104 if (1 == pcontrol)
2105 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2106 return sizeof(sas_sha_m_pg);
2107}
2108
Linus Torvalds1da177e2005-04-16 15:20:36 -07002109#define SDEBUG_MAX_MSENSE_SZ 256
2110
Douglas Gilbertfd321192016-04-25 12:16:33 -04002111static int resp_mode_sense(struct scsi_cmnd *scp,
2112 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113{
Douglas Gilbert23183912006-09-16 20:30:47 -04002114 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002116 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002117 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002118 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002120 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002121 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002123 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002124 pcontrol = (cmd[2] & 0xc0) >> 6;
2125 pcode = cmd[2] & 0x3f;
2126 subpcode = cmd[3];
2127 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002128 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2129 is_disk = (sdebug_ptype == TYPE_DISK);
2130 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002131 bd_len = llbaa ? 16 : 8;
2132 else
2133 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002134 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002135 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2136 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002137 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 return check_condition_result;
2139 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002140 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2141 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002142 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002143 if (is_disk) {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002144 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002145 if (sdebug_wp)
2146 dev_spec |= 0x80;
2147 } else
Douglas Gilbert23183912006-09-16 20:30:47 -04002148 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002149 if (msense_6) {
2150 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002151 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002152 offset = 4;
2153 } else {
2154 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002155 if (16 == bd_len)
2156 arr[4] = 0x1; /* set LONGLBA bit */
2157 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158 offset = 8;
2159 }
2160 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002161 if ((bd_len > 0) && (!sdebug_capacity))
2162 sdebug_capacity = get_sdebug_capacity();
2163
Douglas Gilbert23183912006-09-16 20:30:47 -04002164 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002165 if (sdebug_capacity > 0xfffffffe)
2166 put_unaligned_be32(0xffffffff, ap + 0);
2167 else
2168 put_unaligned_be32(sdebug_capacity, ap + 0);
2169 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002170 offset += bd_len;
2171 ap = arr + offset;
2172 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002173 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2174 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002175 offset += bd_len;
2176 ap = arr + offset;
2177 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002178
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002179 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2180 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002181 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002182 return check_condition_result;
2183 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002184 bad_pcode = false;
2185
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 switch (pcode) {
2187 case 0x1: /* Read-Write error recovery page, direct access */
2188 len = resp_err_recov_pg(ap, pcontrol, target);
2189 offset += len;
2190 break;
2191 case 0x2: /* Disconnect-Reconnect page, all devices */
2192 len = resp_disconnect_pg(ap, pcontrol, target);
2193 offset += len;
2194 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002195 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002196 if (is_disk) {
2197 len = resp_format_pg(ap, pcontrol, target);
2198 offset += len;
2199 } else
2200 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002201 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002202 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002203 if (is_disk) {
2204 len = resp_caching_pg(ap, pcontrol, target);
2205 offset += len;
2206 } else
2207 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002208 break;
2209 case 0xa: /* Control Mode page, all devices */
2210 len = resp_ctrl_m_pg(ap, pcontrol, target);
2211 offset += len;
2212 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002213 case 0x19: /* if spc==1 then sas phy, control+discover */
2214 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002215 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002216 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002217 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002218 len = 0;
2219 if ((0x0 == subpcode) || (0xff == subpcode))
2220 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2221 if ((0x1 == subpcode) || (0xff == subpcode))
2222 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2223 target_dev_id);
2224 if ((0x2 == subpcode) || (0xff == subpcode))
2225 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2226 offset += len;
2227 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002228 case 0x1c: /* Informational Exceptions Mode page, all devices */
2229 len = resp_iec_m_pg(ap, pcontrol, target);
2230 offset += len;
2231 break;
2232 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002233 if ((0 == subpcode) || (0xff == subpcode)) {
2234 len = resp_err_recov_pg(ap, pcontrol, target);
2235 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002236 if (is_disk) {
2237 len += resp_format_pg(ap + len, pcontrol,
2238 target);
2239 len += resp_caching_pg(ap + len, pcontrol,
2240 target);
2241 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002242 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2243 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2244 if (0xff == subpcode) {
2245 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2246 target, target_dev_id);
2247 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2248 }
2249 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002250 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002251 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002252 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002253 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002254 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002255 break;
2256 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002257 bad_pcode = true;
2258 break;
2259 }
2260 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002261 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002262 return check_condition_result;
2263 }
2264 if (msense_6)
2265 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002266 else
2267 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002268 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2269}
2270
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002271#define SDEBUG_MAX_MSELECT_SZ 512
2272
Douglas Gilbertfd321192016-04-25 12:16:33 -04002273static int resp_mode_select(struct scsi_cmnd *scp,
2274 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002275{
2276 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002277 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002278 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002279 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002280 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002281
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002282 memset(arr, 0, sizeof(arr));
2283 pf = cmd[1] & 0x10;
2284 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002285 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002286 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002287 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002288 return check_condition_result;
2289 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002290 res = fetch_to_dev_buffer(scp, arr, param_len);
2291 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002292 return DID_ERROR << 16;
2293 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002294 sdev_printk(KERN_INFO, scp->device,
2295 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2296 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002297 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2298 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002299 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002300 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002301 return check_condition_result;
2302 }
2303 off = bd_len + (mselect6 ? 4 : 8);
2304 mpage = arr[off] & 0x3f;
2305 ps = !!(arr[off] & 0x80);
2306 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002307 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002308 return check_condition_result;
2309 }
2310 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002311 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002312 (arr[off + 1] + 2);
2313 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002314 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002315 PARAMETER_LIST_LENGTH_ERR, 0);
2316 return check_condition_result;
2317 }
2318 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002319 case 0x8: /* Caching Mode page */
2320 if (caching_pg[1] == arr[off + 1]) {
2321 memcpy(caching_pg + 2, arr + off + 2,
2322 sizeof(caching_pg) - 2);
2323 goto set_mode_changed_ua;
2324 }
2325 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002326 case 0xa: /* Control Mode page */
2327 if (ctrl_m_pg[1] == arr[off + 1]) {
2328 memcpy(ctrl_m_pg + 2, arr + off + 2,
2329 sizeof(ctrl_m_pg) - 2);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002330 if (ctrl_m_pg[4] & 0x8)
2331 sdebug_wp = true;
2332 else
2333 sdebug_wp = false;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002334 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002335 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002336 }
2337 break;
2338 case 0x1c: /* Informational Exceptions Mode page */
2339 if (iec_m_pg[1] == arr[off + 1]) {
2340 memcpy(iec_m_pg + 2, arr + off + 2,
2341 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002342 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002343 }
2344 break;
2345 default:
2346 break;
2347 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002348 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002349 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002350set_mode_changed_ua:
2351 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2352 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002353}
2354
John Pittman91d4c752018-02-09 21:12:43 -05002355static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002356{
2357 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2358 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2359 };
2360
Douglas Gilbert9a051012017-12-23 12:48:10 -05002361 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2362 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363}
2364
John Pittman91d4c752018-02-09 21:12:43 -05002365static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002366{
2367 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2368 };
2369
Douglas Gilbert9a051012017-12-23 12:48:10 -05002370 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002371 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2372 arr[4] = THRESHOLD_EXCEEDED;
2373 arr[5] = 0xff;
2374 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002375 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002376}
2377
2378#define SDEBUG_MAX_LSENSE_SZ 512
2379
Douglas Gilbert9a051012017-12-23 12:48:10 -05002380static int resp_log_sense(struct scsi_cmnd *scp,
2381 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002382{
Bart Van Asscheab172412017-08-25 13:46:42 -07002383 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002385 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002386
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002387 memset(arr, 0, sizeof(arr));
2388 ppc = cmd[1] & 0x2;
2389 sp = cmd[1] & 0x1;
2390 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002391 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002392 return check_condition_result;
2393 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002394 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002395 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002396 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002397 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002398 if (0 == subpcode) {
2399 switch (pcode) {
2400 case 0x0: /* Supported log pages log page */
2401 n = 4;
2402 arr[n++] = 0x0; /* this page */
2403 arr[n++] = 0xd; /* Temperature */
2404 arr[n++] = 0x2f; /* Informational exceptions */
2405 arr[3] = n - 4;
2406 break;
2407 case 0xd: /* Temperature log page */
2408 arr[3] = resp_temp_l_pg(arr + 4);
2409 break;
2410 case 0x2f: /* Informational exceptions log page */
2411 arr[3] = resp_ie_l_pg(arr + 4);
2412 break;
2413 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002414 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002415 return check_condition_result;
2416 }
2417 } else if (0xff == subpcode) {
2418 arr[0] |= 0x40;
2419 arr[1] = subpcode;
2420 switch (pcode) {
2421 case 0x0: /* Supported log pages and subpages log page */
2422 n = 4;
2423 arr[n++] = 0x0;
2424 arr[n++] = 0x0; /* 0,0 page */
2425 arr[n++] = 0x0;
2426 arr[n++] = 0xff; /* this page */
2427 arr[n++] = 0xd;
2428 arr[n++] = 0x0; /* Temperature */
2429 arr[n++] = 0x2f;
2430 arr[n++] = 0x0; /* Informational exceptions */
2431 arr[3] = n - 4;
2432 break;
2433 case 0xd: /* Temperature subpages */
2434 n = 4;
2435 arr[n++] = 0xd;
2436 arr[n++] = 0x0; /* Temperature */
2437 arr[3] = n - 4;
2438 break;
2439 case 0x2f: /* Informational exceptions subpages */
2440 n = 4;
2441 arr[n++] = 0x2f;
2442 arr[n++] = 0x0; /* Informational exceptions */
2443 arr[3] = n - 4;
2444 break;
2445 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002446 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002447 return check_condition_result;
2448 }
2449 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002450 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002451 return check_condition_result;
2452 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002453 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002454 return fill_from_dev_buffer(scp, arr,
2455 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2456}
2457
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002458static inline int check_device_access_params(struct scsi_cmnd *scp,
2459 unsigned long long lba, unsigned int num, bool write)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002461 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002462 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002463 return check_condition_result;
2464 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002465 /* transfer length excessive (tie in to block limits VPD page) */
2466 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002467 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002468 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002469 return check_condition_result;
2470 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002471 if (write && unlikely(sdebug_wp)) {
2472 mk_sense_buffer(scp, DATA_PROTECT, WRITE_PROTECTED, 0x2);
2473 return check_condition_result;
2474 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002475 return 0;
2476}
2477
Akinobu Mitaa4517512013-07-08 16:01:57 -07002478/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002479static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2480 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002481{
2482 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002483 u64 block, rest = 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01002484 struct scsi_data_buffer *sdb = &scmd->sdb;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002485 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002486
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002487 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002488 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002489 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002490 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002491 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002492 }
2493
2494 if (!sdb->length)
2495 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01002496 if (scmd->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002497 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002498
2499 block = do_div(lba, sdebug_store_sectors);
2500 if (block + num > sdebug_store_sectors)
2501 rest = block + num - sdebug_store_sectors;
2502
Dave Gordon386ecb12015-06-30 14:58:57 -07002503 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002504 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002505 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002506 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002507 return ret;
2508
2509 if (rest) {
Dave Gordon386ecb12015-06-30 14:58:57 -07002510 ret += sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002511 fake_storep, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002512 sg_skip + ((num - rest) * sdebug_sector_size),
2513 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002514 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002515
2516 return ret;
2517}
2518
Douglas Gilbert40d07b52019-01-25 12:46:09 -05002519/* If lba2fake_store(lba,num) compares equal to arr(num), then copy top half of
2520 * arr into lba2fake_store(lba,num) and return true. If comparison fails then
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002521 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002522static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002523{
2524 bool res;
2525 u64 block, rest = 0;
2526 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002527 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002528
2529 block = do_div(lba, store_blks);
2530 if (block + num > store_blks)
2531 rest = block + num - store_blks;
2532
2533 res = !memcmp(fake_storep + (block * lb_size), arr,
2534 (num - rest) * lb_size);
2535 if (!res)
2536 return res;
2537 if (rest)
2538 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2539 rest * lb_size);
2540 if (!res)
2541 return res;
2542 arr += num * lb_size;
2543 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2544 if (rest)
2545 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2546 rest * lb_size);
2547 return res;
2548}
2549
Akinobu Mita51d648a2013-09-18 21:27:28 +09002550static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002551{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002552 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002553
Douglas Gilbert773642d2016-04-25 12:16:28 -04002554 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002555 csum = (__force __be16)ip_compute_csum(buf, len);
2556 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002557 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002558
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002559 return csum;
2560}
2561
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002562static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002563 sector_t sector, u32 ei_lba)
2564{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002565 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002566
2567 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002568 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002569 (unsigned long)sector,
2570 be16_to_cpu(sdt->guard_tag),
2571 be16_to_cpu(csum));
2572 return 0x01;
2573 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002574 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002575 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002576 pr_err("REF check failed on sector %lu\n",
2577 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002578 return 0x03;
2579 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002580 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002581 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002582 pr_err("REF check failed on sector %lu\n",
2583 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002584 return 0x03;
2585 }
2586 return 0;
2587}
2588
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002589static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002590 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002591{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002592 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002593 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002594 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002595 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002596
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002597 /* Bytes of protection data to copy into sgl */
2598 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002599
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002600 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2601 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2602 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2603
2604 while (sg_miter_next(&miter) && resid > 0) {
2605 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002606 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002607 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002608
2609 if (dif_store_end < start + len)
2610 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002611
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002612 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002613
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002614 if (read)
2615 memcpy(paddr, start, len - rest);
2616 else
2617 memcpy(start, paddr, len - rest);
2618
2619 if (rest) {
2620 if (read)
2621 memcpy(paddr + len - rest, dif_storep, rest);
2622 else
2623 memcpy(dif_storep, paddr + len - rest, rest);
2624 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002625
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002626 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002627 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002628 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002629 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002630}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002631
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002632static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2633 unsigned int sectors, u32 ei_lba)
2634{
2635 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002636 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002637 sector_t sector;
2638
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002639 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002640 int ret;
2641
2642 sector = start_sec + i;
2643 sdt = dif_store(sector);
2644
Akinobu Mita51d648a2013-09-18 21:27:28 +09002645 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002646 continue;
2647
Douglas Gilbert40d07b52019-01-25 12:46:09 -05002648 ret = dif_verify(sdt, lba2fake_store(sector), sector, ei_lba);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002649 if (ret) {
2650 dif_errors++;
2651 return ret;
2652 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002653 }
2654
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002655 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002656 dix_reads++;
2657
2658 return 0;
2659}
2660
Douglas Gilbertfd321192016-04-25 12:16:33 -04002661static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002662{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002663 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002664 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002665 u64 lba;
2666 u32 num;
2667 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002668 unsigned long iflags;
2669 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002670 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002671
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002672 switch (cmd[0]) {
2673 case READ_16:
2674 ei_lba = 0;
2675 lba = get_unaligned_be64(cmd + 2);
2676 num = get_unaligned_be32(cmd + 10);
2677 check_prot = true;
2678 break;
2679 case READ_10:
2680 ei_lba = 0;
2681 lba = get_unaligned_be32(cmd + 2);
2682 num = get_unaligned_be16(cmd + 7);
2683 check_prot = true;
2684 break;
2685 case READ_6:
2686 ei_lba = 0;
2687 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2688 (u32)(cmd[1] & 0x1f) << 16;
2689 num = (0 == cmd[4]) ? 256 : cmd[4];
2690 check_prot = true;
2691 break;
2692 case READ_12:
2693 ei_lba = 0;
2694 lba = get_unaligned_be32(cmd + 2);
2695 num = get_unaligned_be32(cmd + 6);
2696 check_prot = true;
2697 break;
2698 case XDWRITEREAD_10:
2699 ei_lba = 0;
2700 lba = get_unaligned_be32(cmd + 2);
2701 num = get_unaligned_be16(cmd + 7);
2702 check_prot = false;
2703 break;
2704 default: /* assume READ(32) */
2705 lba = get_unaligned_be64(cmd + 12);
2706 ei_lba = get_unaligned_be32(cmd + 20);
2707 num = get_unaligned_be32(cmd + 28);
2708 check_prot = false;
2709 break;
2710 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002711 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002712 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002713 (cmd[1] & 0xe0)) {
2714 mk_sense_invalid_opcode(scp);
2715 return check_condition_result;
2716 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002717 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2718 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002719 (cmd[1] & 0xe0) == 0)
2720 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2721 "to DIF device\n");
2722 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002723 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002724 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002725
Douglas Gilbertc4837392016-05-06 00:40:26 -04002726 if (sqcp) {
2727 if (sqcp->inj_short)
2728 num /= 2;
2729 }
2730 } else
2731 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002732
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05002733 ret = check_device_access_params(scp, lba, num, false);
2734 if (ret)
2735 return ret;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002736 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05002737 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2738 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002739 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002740 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002741 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002742 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2743 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002744 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2745 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002746 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002747 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002748 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002749 return check_condition_result;
2750 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002751
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002752 read_lock_irqsave(&atomic_rw, iflags);
2753
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002754 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002755 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002756 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002757
2758 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002759 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002760 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002761 return illegal_condition_result;
2762 }
2763 }
2764
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002765 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002766 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002767 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002768 return DID_ERROR << 16;
2769
Bart Van Assche42d387b2019-02-08 13:25:00 -08002770 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002771
Douglas Gilbertc4837392016-05-06 00:40:26 -04002772 if (unlikely(sqcp)) {
2773 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002774 mk_sense_buffer(scp, RECOVERED_ERROR,
2775 THRESHOLD_EXCEEDED, 0);
2776 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002777 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002778 mk_sense_buffer(scp, ABORTED_COMMAND,
2779 TRANSPORT_PROBLEM, ACK_NAK_TO);
2780 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002781 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002782 /* Logical block guard check failed */
2783 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2784 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002785 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002786 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2787 return illegal_condition_result;
2788 }
2789 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002790 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002791}
2792
Tomas Winkler58a86352015-07-28 16:54:23 +03002793static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002794{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002795 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002796
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002797 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002798 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002799 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002800
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002801 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002802 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002803
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002804 if (c >= 0x20 && c < 0x7e)
2805 n += scnprintf(b + n, sizeof(b) - n,
2806 " %c ", buf[i+j]);
2807 else
2808 n += scnprintf(b + n, sizeof(b) - n,
2809 "%02x ", buf[i+j]);
2810 }
2811 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002812 }
2813}
2814
2815static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002816 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002817{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002818 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002819 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002820 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002821 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002822 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002823 int dpage_offset;
2824 struct sg_mapping_iter diter;
2825 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002826
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002827 BUG_ON(scsi_sg_count(SCpnt) == 0);
2828 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2829
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002830 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2831 scsi_prot_sg_count(SCpnt),
2832 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2833 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2834 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002835
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002836 /* For each protection page */
2837 while (sg_miter_next(&piter)) {
2838 dpage_offset = 0;
2839 if (WARN_ON(!sg_miter_next(&diter))) {
2840 ret = 0x01;
2841 goto out;
2842 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002843
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002844 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002845 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002846 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002847 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002848 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002849 if (dpage_offset >= diter.length) {
2850 if (WARN_ON(!sg_miter_next(&diter))) {
2851 ret = 0x01;
2852 goto out;
2853 }
2854 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002855 }
2856
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002857 sdt = piter.addr + ppage_offset;
2858 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002859
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002860 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002861 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002862 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002863 goto out;
2864 }
2865
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002866 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002867 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002868 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002869 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002870 diter.consumed = dpage_offset;
2871 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002872 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002873 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002874
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002875 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002876 dix_writes++;
2877
2878 return 0;
2879
2880out:
2881 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002882 sg_miter_stop(&diter);
2883 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002884 return ret;
2885}
2886
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002887static unsigned long lba_to_map_index(sector_t lba)
2888{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002889 if (sdebug_unmap_alignment)
2890 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2891 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002892 return lba;
2893}
2894
2895static sector_t map_index_to_lba(unsigned long index)
2896{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002897 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002898
Douglas Gilbert773642d2016-04-25 12:16:28 -04002899 if (sdebug_unmap_alignment)
2900 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002901 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002902}
2903
Martin K. Petersen44d92692009-10-15 14:45:27 -04002904static unsigned int map_state(sector_t lba, unsigned int *num)
2905{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002906 sector_t end;
2907 unsigned int mapped;
2908 unsigned long index;
2909 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002910
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002911 index = lba_to_map_index(lba);
2912 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002913
2914 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002915 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002916 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002917 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002918
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002919 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002920 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002921 return mapped;
2922}
2923
2924static void map_region(sector_t lba, unsigned int len)
2925{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002926 sector_t end = lba + len;
2927
Martin K. Petersen44d92692009-10-15 14:45:27 -04002928 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002929 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002930
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002931 if (index < map_size)
2932 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002933
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002934 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002935 }
2936}
2937
2938static void unmap_region(sector_t lba, unsigned int len)
2939{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002940 sector_t end = lba + len;
2941
Martin K. Petersen44d92692009-10-15 14:45:27 -04002942 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002943 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002944
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002945 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002946 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002947 index < map_size) {
2948 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002949 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002950 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002951 lba * sdebug_sector_size,
2952 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002953 sdebug_sector_size *
2954 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002955 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002956 if (dif_storep) {
2957 memset(dif_storep + lba, 0xff,
2958 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002959 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002960 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002961 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002962 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002963 }
2964}
2965
Douglas Gilbertfd321192016-04-25 12:16:33 -04002966static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002967{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002968 u8 *cmd = scp->cmnd;
2969 u64 lba;
2970 u32 num;
2971 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002972 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002973 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002974 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002975
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002976 switch (cmd[0]) {
2977 case WRITE_16:
2978 ei_lba = 0;
2979 lba = get_unaligned_be64(cmd + 2);
2980 num = get_unaligned_be32(cmd + 10);
2981 check_prot = true;
2982 break;
2983 case WRITE_10:
2984 ei_lba = 0;
2985 lba = get_unaligned_be32(cmd + 2);
2986 num = get_unaligned_be16(cmd + 7);
2987 check_prot = true;
2988 break;
2989 case WRITE_6:
2990 ei_lba = 0;
2991 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2992 (u32)(cmd[1] & 0x1f) << 16;
2993 num = (0 == cmd[4]) ? 256 : cmd[4];
2994 check_prot = true;
2995 break;
2996 case WRITE_12:
2997 ei_lba = 0;
2998 lba = get_unaligned_be32(cmd + 2);
2999 num = get_unaligned_be32(cmd + 6);
3000 check_prot = true;
3001 break;
3002 case 0x53: /* XDWRITEREAD(10) */
3003 ei_lba = 0;
3004 lba = get_unaligned_be32(cmd + 2);
3005 num = get_unaligned_be16(cmd + 7);
3006 check_prot = false;
3007 break;
3008 default: /* assume WRITE(32) */
3009 lba = get_unaligned_be64(cmd + 12);
3010 ei_lba = get_unaligned_be32(cmd + 20);
3011 num = get_unaligned_be32(cmd + 28);
3012 check_prot = false;
3013 break;
3014 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003015 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003016 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003017 (cmd[1] & 0xe0)) {
3018 mk_sense_invalid_opcode(scp);
3019 return check_condition_result;
3020 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003021 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3022 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003023 (cmd[1] & 0xe0) == 0)
3024 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3025 "to DIF device\n");
3026 }
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003027 ret = check_device_access_params(scp, lba, num, true);
3028 if (ret)
3029 return ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003030 write_lock_irqsave(&atomic_rw, iflags);
3031
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003032 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003033 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003034 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003035
3036 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003037 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003038 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003039 return illegal_condition_result;
3040 }
3041 }
3042
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003043 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003044 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003045 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003046 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003047 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003048 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003049 else if (unlikely(sdebug_verbose &&
3050 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003051 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003052 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003053 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003054
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003055 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003056 struct sdebug_queued_cmd *sqcp =
3057 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003058
Douglas Gilbertc4837392016-05-06 00:40:26 -04003059 if (sqcp) {
3060 if (sqcp->inj_recovered) {
3061 mk_sense_buffer(scp, RECOVERED_ERROR,
3062 THRESHOLD_EXCEEDED, 0);
3063 return check_condition_result;
3064 } else if (sqcp->inj_dif) {
3065 /* Logical block guard check failed */
3066 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3067 return illegal_condition_result;
3068 } else if (sqcp->inj_dix) {
3069 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3070 return illegal_condition_result;
3071 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003072 }
3073 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003074 return 0;
3075}
3076
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003077/*
3078 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3079 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3080 */
3081static int resp_write_scat(struct scsi_cmnd *scp,
3082 struct sdebug_dev_info *devip)
3083{
3084 u8 *cmd = scp->cmnd;
3085 u8 *lrdp = NULL;
3086 u8 *up;
3087 u8 wrprotect;
3088 u16 lbdof, num_lrd, k;
3089 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3090 u32 lb_size = sdebug_sector_size;
3091 u32 ei_lba;
3092 u64 lba;
3093 unsigned long iflags;
3094 int ret, res;
3095 bool is_16;
3096 static const u32 lrd_size = 32; /* + parameter list header size */
3097
3098 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3099 is_16 = false;
3100 wrprotect = (cmd[10] >> 5) & 0x7;
3101 lbdof = get_unaligned_be16(cmd + 12);
3102 num_lrd = get_unaligned_be16(cmd + 16);
3103 bt_len = get_unaligned_be32(cmd + 28);
3104 } else { /* that leaves WRITE SCATTERED(16) */
3105 is_16 = true;
3106 wrprotect = (cmd[2] >> 5) & 0x7;
3107 lbdof = get_unaligned_be16(cmd + 4);
3108 num_lrd = get_unaligned_be16(cmd + 8);
3109 bt_len = get_unaligned_be32(cmd + 10);
3110 if (unlikely(have_dif_prot)) {
3111 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3112 wrprotect) {
3113 mk_sense_invalid_opcode(scp);
3114 return illegal_condition_result;
3115 }
3116 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3117 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3118 wrprotect == 0)
3119 sdev_printk(KERN_ERR, scp->device,
3120 "Unprotected WR to DIF device\n");
3121 }
3122 }
3123 if ((num_lrd == 0) || (bt_len == 0))
3124 return 0; /* T10 says these do-nothings are not errors */
3125 if (lbdof == 0) {
3126 if (sdebug_verbose)
3127 sdev_printk(KERN_INFO, scp->device,
3128 "%s: %s: LB Data Offset field bad\n",
3129 my_name, __func__);
3130 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3131 return illegal_condition_result;
3132 }
3133 lbdof_blen = lbdof * lb_size;
3134 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3135 if (sdebug_verbose)
3136 sdev_printk(KERN_INFO, scp->device,
3137 "%s: %s: LBA range descriptors don't fit\n",
3138 my_name, __func__);
3139 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3140 return illegal_condition_result;
3141 }
3142 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3143 if (lrdp == NULL)
3144 return SCSI_MLQUEUE_HOST_BUSY;
3145 if (sdebug_verbose)
3146 sdev_printk(KERN_INFO, scp->device,
3147 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3148 my_name, __func__, lbdof_blen);
3149 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3150 if (res == -1) {
3151 ret = DID_ERROR << 16;
3152 goto err_out;
3153 }
3154
3155 write_lock_irqsave(&atomic_rw, iflags);
3156 sg_off = lbdof_blen;
3157 /* Spec says Buffer xfer Length field in number of LBs in dout */
3158 cum_lb = 0;
3159 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3160 lba = get_unaligned_be64(up + 0);
3161 num = get_unaligned_be32(up + 8);
3162 if (sdebug_verbose)
3163 sdev_printk(KERN_INFO, scp->device,
3164 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3165 my_name, __func__, k, lba, num, sg_off);
3166 if (num == 0)
3167 continue;
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003168 ret = check_device_access_params(scp, lba, num, true);
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003169 if (ret)
3170 goto err_out_unlock;
3171 num_by = num * lb_size;
3172 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3173
3174 if ((cum_lb + num) > bt_len) {
3175 if (sdebug_verbose)
3176 sdev_printk(KERN_INFO, scp->device,
3177 "%s: %s: sum of blocks > data provided\n",
3178 my_name, __func__);
3179 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3180 0);
3181 ret = illegal_condition_result;
3182 goto err_out_unlock;
3183 }
3184
3185 /* DIX + T10 DIF */
3186 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3187 int prot_ret = prot_verify_write(scp, lba, num,
3188 ei_lba);
3189
3190 if (prot_ret) {
3191 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3192 prot_ret);
3193 ret = illegal_condition_result;
3194 goto err_out_unlock;
3195 }
3196 }
3197
3198 ret = do_device_access(scp, sg_off, lba, num, true);
3199 if (unlikely(scsi_debug_lbp()))
3200 map_region(lba, num);
3201 if (unlikely(-1 == ret)) {
3202 ret = DID_ERROR << 16;
3203 goto err_out_unlock;
3204 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3205 sdev_printk(KERN_INFO, scp->device,
3206 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3207 my_name, num_by, ret);
3208
3209 if (unlikely(sdebug_any_injecting_opt)) {
3210 struct sdebug_queued_cmd *sqcp =
3211 (struct sdebug_queued_cmd *)scp->host_scribble;
3212
3213 if (sqcp) {
3214 if (sqcp->inj_recovered) {
3215 mk_sense_buffer(scp, RECOVERED_ERROR,
3216 THRESHOLD_EXCEEDED, 0);
3217 ret = illegal_condition_result;
3218 goto err_out_unlock;
3219 } else if (sqcp->inj_dif) {
3220 /* Logical block guard check failed */
3221 mk_sense_buffer(scp, ABORTED_COMMAND,
3222 0x10, 1);
3223 ret = illegal_condition_result;
3224 goto err_out_unlock;
3225 } else if (sqcp->inj_dix) {
3226 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3227 0x10, 1);
3228 ret = illegal_condition_result;
3229 goto err_out_unlock;
3230 }
3231 }
3232 }
3233 sg_off += num_by;
3234 cum_lb += num;
3235 }
3236 ret = 0;
3237err_out_unlock:
3238 write_unlock_irqrestore(&atomic_rw, iflags);
3239err_out:
3240 kfree(lrdp);
3241 return ret;
3242}
3243
Douglas Gilbertfd321192016-04-25 12:16:33 -04003244static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3245 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003246{
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003247 int ret;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003248 unsigned long iflags;
3249 unsigned long long i;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003250 u32 lb_size = sdebug_sector_size;
3251 u64 block, lbaa;
3252 u8 *fs1p;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003253
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003254 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003255 if (ret)
3256 return ret;
3257
3258 write_lock_irqsave(&atomic_rw, iflags);
3259
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003260 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003261 unmap_region(lba, num);
3262 goto out;
3263 }
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003264 lbaa = lba;
3265 block = do_div(lbaa, sdebug_store_sectors);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003266 /* if ndob then zero 1 logical block, else fetch 1 logical block */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003267 fs1p = fake_storep + (block * lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003268 if (ndob) {
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003269 memset(fs1p, 0, lb_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003270 ret = 0;
3271 } else
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003272 ret = fetch_to_dev_buffer(scp, fs1p, lb_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003273
3274 if (-1 == ret) {
3275 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003276 return DID_ERROR << 16;
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003277 } else if (sdebug_verbose && !ndob && (ret < lb_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003278 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003279 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003280 my_name, "write same", lb_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003281
3282 /* Copy first sector to remaining blocks */
Douglas Gilbert40d07b52019-01-25 12:46:09 -05003283 for (i = 1 ; i < num ; i++) {
3284 lbaa = lba + i;
3285 block = do_div(lbaa, sdebug_store_sectors);
3286 memmove(fake_storep + (block * lb_size), fs1p, lb_size);
3287 }
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003288 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003289 map_region(lba, num);
3290out:
3291 write_unlock_irqrestore(&atomic_rw, iflags);
3292
3293 return 0;
3294}
3295
Douglas Gilbertfd321192016-04-25 12:16:33 -04003296static int resp_write_same_10(struct scsi_cmnd *scp,
3297 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003298{
3299 u8 *cmd = scp->cmnd;
3300 u32 lba;
3301 u16 num;
3302 u32 ei_lba = 0;
3303 bool unmap = false;
3304
3305 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003306 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003307 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3308 return check_condition_result;
3309 } else
3310 unmap = true;
3311 }
3312 lba = get_unaligned_be32(cmd + 2);
3313 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003314 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003315 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3316 return check_condition_result;
3317 }
3318 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3319}
3320
Douglas Gilbertfd321192016-04-25 12:16:33 -04003321static int resp_write_same_16(struct scsi_cmnd *scp,
3322 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003323{
3324 u8 *cmd = scp->cmnd;
3325 u64 lba;
3326 u32 num;
3327 u32 ei_lba = 0;
3328 bool unmap = false;
3329 bool ndob = false;
3330
3331 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003332 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003333 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3334 return check_condition_result;
3335 } else
3336 unmap = true;
3337 }
3338 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3339 ndob = true;
3340 lba = get_unaligned_be64(cmd + 2);
3341 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003342 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003343 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3344 return check_condition_result;
3345 }
3346 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3347}
3348
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003349/* Note the mode field is in the same position as the (lower) service action
3350 * field. For the Report supported operation codes command, SPC-4 suggests
3351 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003352static int resp_write_buffer(struct scsi_cmnd *scp,
3353 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003354{
3355 u8 *cmd = scp->cmnd;
3356 struct scsi_device *sdp = scp->device;
3357 struct sdebug_dev_info *dp;
3358 u8 mode;
3359
3360 mode = cmd[1] & 0x1f;
3361 switch (mode) {
3362 case 0x4: /* download microcode (MC) and activate (ACT) */
3363 /* set UAs on this device only */
3364 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3365 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3366 break;
3367 case 0x5: /* download MC, save and ACT */
3368 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3369 break;
3370 case 0x6: /* download MC with offsets and ACT */
3371 /* set UAs on most devices (LUs) in this target */
3372 list_for_each_entry(dp,
3373 &devip->sdbg_host->dev_info_list,
3374 dev_list)
3375 if (dp->target == sdp->id) {
3376 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3377 if (devip != dp)
3378 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3379 dp->uas_bm);
3380 }
3381 break;
3382 case 0x7: /* download MC with offsets, save, and ACT */
3383 /* set UA on all devices (LUs) in this target */
3384 list_for_each_entry(dp,
3385 &devip->sdbg_host->dev_info_list,
3386 dev_list)
3387 if (dp->target == sdp->id)
3388 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3389 dp->uas_bm);
3390 break;
3391 default:
3392 /* do nothing for this command for other mode values */
3393 break;
3394 }
3395 return 0;
3396}
3397
Douglas Gilbertfd321192016-04-25 12:16:33 -04003398static int resp_comp_write(struct scsi_cmnd *scp,
3399 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003400{
3401 u8 *cmd = scp->cmnd;
3402 u8 *arr;
3403 u8 *fake_storep_hold;
3404 u64 lba;
3405 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003406 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003407 u8 num;
3408 unsigned long iflags;
3409 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003410 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003411
Douglas Gilbertd467d312014-11-26 12:33:48 -05003412 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003413 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3414 if (0 == num)
3415 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003416 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003417 (cmd[1] & 0xe0)) {
3418 mk_sense_invalid_opcode(scp);
3419 return check_condition_result;
3420 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003421 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3422 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003423 (cmd[1] & 0xe0) == 0)
3424 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3425 "to DIF device\n");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003426 ret = check_device_access_params(scp, lba, num, false);
3427 if (ret)
3428 return ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003429 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003430 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003431 if (NULL == arr) {
3432 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3433 INSUFF_RES_ASCQ);
3434 return check_condition_result;
3435 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003436
3437 write_lock_irqsave(&atomic_rw, iflags);
3438
3439 /* trick do_device_access() to fetch both compare and write buffers
3440 * from data-in into arr. Safe (atomic) since write_lock held. */
3441 fake_storep_hold = fake_storep;
3442 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003443 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003444 fake_storep = fake_storep_hold;
3445 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003446 retval = DID_ERROR << 16;
3447 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003448 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003449 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3450 "indicated=%u, IO sent=%d bytes\n", my_name,
3451 dnum * lb_size, ret);
3452 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003453 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003454 retval = check_condition_result;
3455 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003456 }
3457 if (scsi_debug_lbp())
3458 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003459cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003460 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003461 kfree(arr);
3462 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003463}
3464
Martin K. Petersen44d92692009-10-15 14:45:27 -04003465struct unmap_block_desc {
3466 __be64 lba;
3467 __be32 blocks;
3468 __be32 __reserved;
3469};
3470
Douglas Gilbertfd321192016-04-25 12:16:33 -04003471static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003472{
3473 unsigned char *buf;
3474 struct unmap_block_desc *desc;
3475 unsigned int i, payload_len, descriptors;
3476 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003477 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003478
Martin K. Petersen44d92692009-10-15 14:45:27 -04003479
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003480 if (!scsi_debug_lbp())
3481 return 0; /* fib and say its done */
3482 payload_len = get_unaligned_be16(scp->cmnd + 7);
3483 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003484
3485 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003486 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003487 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003488 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003489 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003490
Douglas Gilbertb333a812016-04-25 12:16:30 -04003491 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003492 if (!buf) {
3493 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3494 INSUFF_RES_ASCQ);
3495 return check_condition_result;
3496 }
3497
3498 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003499
3500 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3501 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3502
3503 desc = (void *)&buf[8];
3504
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003505 write_lock_irqsave(&atomic_rw, iflags);
3506
Martin K. Petersen44d92692009-10-15 14:45:27 -04003507 for (i = 0 ; i < descriptors ; i++) {
3508 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3509 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3510
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003511 ret = check_device_access_params(scp, lba, num, true);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003512 if (ret)
3513 goto out;
3514
3515 unmap_region(lba, num);
3516 }
3517
3518 ret = 0;
3519
3520out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003521 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003522 kfree(buf);
3523
3524 return ret;
3525}
3526
3527#define SDEBUG_GET_LBA_STATUS_LEN 32
3528
Douglas Gilbertfd321192016-04-25 12:16:33 -04003529static int resp_get_lba_status(struct scsi_cmnd *scp,
3530 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003531{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003532 u8 *cmd = scp->cmnd;
3533 u64 lba;
3534 u32 alloc_len, mapped, num;
3535 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003536 int ret;
3537
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003538 lba = get_unaligned_be64(cmd + 2);
3539 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003540
3541 if (alloc_len < 24)
3542 return 0;
3543
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05003544 ret = check_device_access_params(scp, lba, 1, false);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003545 if (ret)
3546 return ret;
3547
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003548 if (scsi_debug_lbp())
3549 mapped = map_state(lba, &num);
3550 else {
3551 mapped = 1;
3552 /* following just in case virtual_gb changed */
3553 sdebug_capacity = get_sdebug_capacity();
3554 if (sdebug_capacity - lba <= 0xffffffff)
3555 num = sdebug_capacity - lba;
3556 else
3557 num = 0xffffffff;
3558 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003559
3560 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003561 put_unaligned_be32(20, arr); /* Parameter Data Length */
3562 put_unaligned_be64(lba, arr + 8); /* LBA */
3563 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3564 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003565
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003566 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003567}
3568
Douglas Gilbert80c49562018-02-09 21:36:39 -05003569static int resp_sync_cache(struct scsi_cmnd *scp,
3570 struct sdebug_dev_info *devip)
3571{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003572 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003573 u64 lba;
3574 u32 num_blocks;
3575 u8 *cmd = scp->cmnd;
3576
3577 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
3578 lba = get_unaligned_be32(cmd + 2);
3579 num_blocks = get_unaligned_be16(cmd + 7);
3580 } else { /* SYNCHRONIZE_CACHE(16) */
3581 lba = get_unaligned_be64(cmd + 2);
3582 num_blocks = get_unaligned_be32(cmd + 10);
3583 }
3584 if (lba + num_blocks > sdebug_capacity) {
3585 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3586 return check_condition_result;
3587 }
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003588 if (!write_since_sync || cmd[1] & 0x2)
3589 res = SDEG_RES_IMMED_MASK;
3590 else /* delay if write_since_sync and IMMED clear */
3591 write_since_sync = false;
3592 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003593}
3594
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003595#define RL_BUCKET_ELEMS 8
3596
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003597/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3598 * (W-LUN), the normal Linux scanning logic does not associate it with a
3599 * device (e.g. /dev/sg7). The following magic will make that association:
3600 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3601 * where <n> is a host number. If there are multiple targets in a host then
3602 * the above will associate a W-LUN to each target. To only get a W-LUN
3603 * for target 2, then use "echo '- 2 49409' > scan" .
3604 */
3605static int resp_report_luns(struct scsi_cmnd *scp,
3606 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003607{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003608 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003609 unsigned int alloc_len;
3610 unsigned char select_report;
3611 u64 lun;
3612 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003613 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003614 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3615 unsigned int wlun_cnt; /* report luns W-LUN count */
3616 unsigned int tlun_cnt; /* total LUN count */
3617 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003618 int k, j, n, res;
3619 unsigned int off_rsp = 0;
3620 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003621
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003622 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003623
3624 select_report = cmd[2];
3625 alloc_len = get_unaligned_be32(cmd + 6);
3626
3627 if (alloc_len < 4) {
3628 pr_err("alloc len too small %d\n", alloc_len);
3629 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003630 return check_condition_result;
3631 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003632
3633 switch (select_report) {
3634 case 0: /* all LUNs apart from W-LUNs */
3635 lun_cnt = sdebug_max_luns;
3636 wlun_cnt = 0;
3637 break;
3638 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003639 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003640 wlun_cnt = 1;
3641 break;
3642 case 2: /* all LUNs */
3643 lun_cnt = sdebug_max_luns;
3644 wlun_cnt = 1;
3645 break;
3646 case 0x10: /* only administrative LUs */
3647 case 0x11: /* see SPC-5 */
3648 case 0x12: /* only subsiduary LUs owned by referenced LU */
3649 default:
3650 pr_debug("select report invalid %d\n", select_report);
3651 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3652 return check_condition_result;
3653 }
3654
3655 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003656 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003657
3658 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003659 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3660 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003661 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3662 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3663
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003664 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003665 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003666 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3667 memset(arr, 0, sizeof(arr));
3668 lun_p = (struct scsi_lun *)&arr[0];
3669 if (k == 0) {
3670 put_unaligned_be32(rlen, &arr[0]);
3671 ++lun_p;
3672 j = 1;
3673 }
3674 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3675 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3676 break;
3677 int_to_scsilun(lun++, lun_p);
3678 }
3679 if (j < RL_BUCKET_ELEMS)
3680 break;
3681 n = j * sz_lun;
3682 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3683 if (res)
3684 return res;
3685 off_rsp += n;
3686 }
3687 if (wlun_cnt) {
3688 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3689 ++j;
3690 }
3691 if (j > 0)
3692 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003693 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003694}
3695
Douglas Gilbertc4837392016-05-06 00:40:26 -04003696static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3697{
Bart Van Assche458df782018-01-26 08:52:19 -08003698 u32 tag = blk_mq_unique_tag(cmnd->request);
3699 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003700
Bart Van Assche458df782018-01-26 08:52:19 -08003701 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3702 if (WARN_ON_ONCE(hwq >= submit_queues))
3703 hwq = 0;
3704 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003705}
3706
3707/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003708static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003709{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003710 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003711 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003712 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003713 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003714 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003715 struct sdebug_queued_cmd *sqcp;
3716 struct scsi_cmnd *scp;
3717 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003718
Douglas Gilbert10bde982018-01-10 16:57:31 -05003719 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003720 if (unlikely(aborted))
3721 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003722 qc_idx = sd_dp->qc_idx;
3723 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3724 if (sdebug_statistics) {
3725 atomic_inc(&sdebug_completions);
3726 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3727 atomic_inc(&sdebug_miss_cpus);
3728 }
3729 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3730 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003731 return;
3732 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003733 spin_lock_irqsave(&sqp->qc_lock, iflags);
3734 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003735 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003736 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003737 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3738 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3739 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003740 return;
3741 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003742 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003743 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003744 atomic_dec(&devip->num_in_q);
3745 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003746 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003747 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003748 retiring = 1;
3749
3750 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003751 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3752 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003753 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003754 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003755 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003756
3757 if (unlikely(retiring)) { /* user has reduced max_queue */
3758 int k, retval;
3759
3760 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003761 if (qc_idx >= retval) {
3762 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003763 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003764 return;
3765 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003766 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003767 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003768 atomic_set(&retired_max_queue, 0);
3769 else
3770 atomic_set(&retired_max_queue, k + 1);
3771 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003772 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003773 if (unlikely(aborted)) {
3774 if (sdebug_verbose)
3775 pr_info("bypassing scsi_done() due to aborted cmd\n");
3776 return;
3777 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003778 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003779}
3780
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003781/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003782static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003783{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003784 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3785 hrt);
3786 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003787 return HRTIMER_NORESTART;
3788}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003789
Douglas Gilberta10bc122016-04-25 12:16:32 -04003790/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003791static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003792{
3793 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3794 ew.work);
3795 sdebug_q_cmd_complete(sd_dp);
3796}
3797
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003798static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003799static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003800
Douglas Gilbertfd321192016-04-25 12:16:33 -04003801static struct sdebug_dev_info *sdebug_device_create(
3802 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003803{
3804 struct sdebug_dev_info *devip;
3805
3806 devip = kzalloc(sizeof(*devip), flags);
3807 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003808 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003809 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003810 else if (sdebug_uuid_ctl == 2) {
3811 if (got_shared_uuid)
3812 devip->lu_name = shared_uuid;
3813 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003814 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003815 got_shared_uuid = true;
3816 devip->lu_name = shared_uuid;
3817 }
3818 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003819 devip->sdbg_host = sdbg_host;
3820 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3821 }
3822 return devip;
3823}
3824
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003825static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003826{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003827 struct sdebug_host_info *sdbg_host;
3828 struct sdebug_dev_info *open_devip = NULL;
3829 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003830
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003831 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3832 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003833 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003834 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003835 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003836 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3837 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003838 (devip->target == sdev->id) &&
3839 (devip->lun == sdev->lun))
3840 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003841 else {
3842 if ((!devip->used) && (!open_devip))
3843 open_devip = devip;
3844 }
3845 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003846 if (!open_devip) { /* try and make a new one */
3847 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3848 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003849 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850 return NULL;
3851 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003852 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003853
3854 open_devip->channel = sdev->channel;
3855 open_devip->target = sdev->id;
3856 open_devip->lun = sdev->lun;
3857 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003858 atomic_set(&open_devip->num_in_q, 0);
3859 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003860 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003861 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003862}
3863
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003864static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003865{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003866 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003867 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003868 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003869 return 0;
3870}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003871
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003872static int scsi_debug_slave_configure(struct scsi_device *sdp)
3873{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003874 struct sdebug_dev_info *devip =
3875 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003876
Douglas Gilbert773642d2016-04-25 12:16:28 -04003877 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003878 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003879 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003880 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3881 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3882 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003883 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003884 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003885 return 1; /* no resources, will be marked offline */
3886 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003887 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003888 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003889 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003890 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003891 return 0;
3892}
3893
3894static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3895{
3896 struct sdebug_dev_info *devip =
3897 (struct sdebug_dev_info *)sdp->hostdata;
3898
Douglas Gilbert773642d2016-04-25 12:16:28 -04003899 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003900 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003901 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3902 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003903 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003904 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003905 sdp->hostdata = NULL;
3906 }
3907}
3908
Douglas Gilbert10bde982018-01-10 16:57:31 -05003909static void stop_qc_helper(struct sdebug_defer *sd_dp,
3910 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003911{
3912 if (!sd_dp)
3913 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003914 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003915 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003916 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003917 cancel_work_sync(&sd_dp->ew.work);
3918}
3919
Douglas Gilberta10bc122016-04-25 12:16:32 -04003920/* If @cmnd found deletes its timer or work queue and returns true; else
3921 returns false */
3922static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003923{
3924 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003925 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003926 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003927 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003928 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003929 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003930 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003931
Douglas Gilbertc4837392016-05-06 00:40:26 -04003932 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3933 spin_lock_irqsave(&sqp->qc_lock, iflags);
3934 qmax = sdebug_max_queue;
3935 r_qmax = atomic_read(&retired_max_queue);
3936 if (r_qmax > qmax)
3937 qmax = r_qmax;
3938 for (k = 0; k < qmax; ++k) {
3939 if (test_bit(k, sqp->in_use_bm)) {
3940 sqcp = &sqp->qc_arr[k];
3941 if (cmnd != sqcp->a_cmnd)
3942 continue;
3943 /* found */
3944 devip = (struct sdebug_dev_info *)
3945 cmnd->device->hostdata;
3946 if (devip)
3947 atomic_dec(&devip->num_in_q);
3948 sqcp->a_cmnd = NULL;
3949 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003950 if (sd_dp) {
3951 l_defer_t = sd_dp->defer_t;
3952 sd_dp->defer_t = SDEB_DEFER_NONE;
3953 } else
3954 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003955 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003956 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003957 clear_bit(k, sqp->in_use_bm);
3958 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003959 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003960 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003961 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003962 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003963 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003964}
3965
Douglas Gilberta10bc122016-04-25 12:16:32 -04003966/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003967static void stop_all_queued(void)
3968{
3969 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003970 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003971 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003972 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003973 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003974 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003975 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003976
Douglas Gilbertc4837392016-05-06 00:40:26 -04003977 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3978 spin_lock_irqsave(&sqp->qc_lock, iflags);
3979 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
3980 if (test_bit(k, sqp->in_use_bm)) {
3981 sqcp = &sqp->qc_arr[k];
3982 if (sqcp->a_cmnd == NULL)
3983 continue;
3984 devip = (struct sdebug_dev_info *)
3985 sqcp->a_cmnd->device->hostdata;
3986 if (devip)
3987 atomic_dec(&devip->num_in_q);
3988 sqcp->a_cmnd = NULL;
3989 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003990 if (sd_dp) {
3991 l_defer_t = sd_dp->defer_t;
3992 sd_dp->defer_t = SDEB_DEFER_NONE;
3993 } else
3994 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003995 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003996 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 clear_bit(k, sqp->in_use_bm);
3998 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003999 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004000 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004001 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004002 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004003}
4004
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004005/* Free queued command memory on heap */
4006static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004007{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004008 int j, k;
4009 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004010 struct sdebug_queued_cmd *sqcp;
4011
Douglas Gilbertc4837392016-05-06 00:40:26 -04004012 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4013 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4014 sqcp = &sqp->qc_arr[k];
4015 kfree(sqcp->sd_dp);
4016 sqcp->sd_dp = NULL;
4017 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004018 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004019}
4020
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004021static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004022{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004023 bool ok;
4024
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004025 ++num_aborts;
4026 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004027 ok = stop_queued_cmnd(SCpnt);
4028 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4029 sdev_printk(KERN_INFO, SCpnt->device,
4030 "%s: command%s found\n", __func__,
4031 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004032 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004033 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004034}
4035
John Pittman91d4c752018-02-09 21:12:43 -05004036static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004037{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004038 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004039 if (SCpnt && SCpnt->device) {
4040 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004041 struct sdebug_dev_info *devip =
4042 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004043
Douglas Gilbert773642d2016-04-25 12:16:28 -04004044 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004045 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004046 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004047 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004048 }
4049 return SUCCESS;
4050}
4051
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004052static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4053{
4054 struct sdebug_host_info *sdbg_host;
4055 struct sdebug_dev_info *devip;
4056 struct scsi_device *sdp;
4057 struct Scsi_Host *hp;
4058 int k = 0;
4059
4060 ++num_target_resets;
4061 if (!SCpnt)
4062 goto lie;
4063 sdp = SCpnt->device;
4064 if (!sdp)
4065 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004066 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004067 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4068 hp = sdp->host;
4069 if (!hp)
4070 goto lie;
4071 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4072 if (sdbg_host) {
4073 list_for_each_entry(devip,
4074 &sdbg_host->dev_info_list,
4075 dev_list)
4076 if (devip->target == sdp->id) {
4077 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4078 ++k;
4079 }
4080 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004081 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004082 sdev_printk(KERN_INFO, sdp,
4083 "%s: %d device(s) found in target\n", __func__, k);
4084lie:
4085 return SUCCESS;
4086}
4087
John Pittman91d4c752018-02-09 21:12:43 -05004088static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004089{
4090 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004091 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004092 struct scsi_device *sdp;
4093 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004094 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004095
Linus Torvalds1da177e2005-04-16 15:20:36 -07004096 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004097 if (!(SCpnt && SCpnt->device))
4098 goto lie;
4099 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004100 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004101 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4102 hp = sdp->host;
4103 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004104 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004105 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004106 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004107 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004108 dev_list) {
4109 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4110 ++k;
4111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004112 }
4113 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004114 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004115 sdev_printk(KERN_INFO, sdp,
4116 "%s: %d device(s) found in host\n", __func__, k);
4117lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004118 return SUCCESS;
4119}
4120
John Pittman91d4c752018-02-09 21:12:43 -05004121static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004122{
John Pittman91d4c752018-02-09 21:12:43 -05004123 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004124 struct sdebug_dev_info *devip;
4125 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004126
Linus Torvalds1da177e2005-04-16 15:20:36 -07004127 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004128 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004129 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004130 spin_lock(&sdebug_host_list_lock);
4131 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004132 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4133 dev_list) {
4134 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4135 ++k;
4136 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004137 }
4138 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004139 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004140 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004141 sdev_printk(KERN_INFO, SCpnt->device,
4142 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004143 return SUCCESS;
4144}
4145
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004146static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004147 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004148{
John Pittman91d4c752018-02-09 21:12:43 -05004149 struct partition *pp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004150 int starts[SDEBUG_MAX_PARTS + 2];
4151 int sectors_per_part, num_sectors, k;
4152 int heads_by_sects, start_sec, end_sec;
4153
4154 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004155 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004156 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004157 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4158 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004159 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004160 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004161 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004162 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004163 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004164 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004165 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004166 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004167 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4168 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004169 starts[sdebug_num_parts] = num_sectors;
4170 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004171
4172 ramp[510] = 0x55; /* magic partition markings */
4173 ramp[511] = 0xAA;
4174 pp = (struct partition *)(ramp + 0x1be);
4175 for (k = 0; starts[k + 1]; ++k, ++pp) {
4176 start_sec = starts[k];
4177 end_sec = starts[k + 1] - 1;
4178 pp->boot_ind = 0;
4179
4180 pp->cyl = start_sec / heads_by_sects;
4181 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4182 / sdebug_sectors_per;
4183 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4184
4185 pp->end_cyl = end_sec / heads_by_sects;
4186 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4187 / sdebug_sectors_per;
4188 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4189
Akinobu Mita150c3542013-08-26 22:08:40 +09004190 pp->start_sect = cpu_to_le32(start_sec);
4191 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004192 pp->sys_ind = 0x83; /* plain Linux partition */
4193 }
4194}
4195
Douglas Gilbertc4837392016-05-06 00:40:26 -04004196static void block_unblock_all_queues(bool block)
4197{
4198 int j;
4199 struct sdebug_queue *sqp;
4200
4201 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4202 atomic_set(&sqp->blocked, (int)block);
4203}
4204
4205/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4206 * commands will be processed normally before triggers occur.
4207 */
4208static void tweak_cmnd_count(void)
4209{
4210 int count, modulo;
4211
4212 modulo = abs(sdebug_every_nth);
4213 if (modulo < 2)
4214 return;
4215 block_unblock_all_queues(true);
4216 count = atomic_read(&sdebug_cmnd_count);
4217 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4218 block_unblock_all_queues(false);
4219}
4220
4221static void clear_queue_stats(void)
4222{
4223 atomic_set(&sdebug_cmnd_count, 0);
4224 atomic_set(&sdebug_completions, 0);
4225 atomic_set(&sdebug_miss_cpus, 0);
4226 atomic_set(&sdebug_a_tsf, 0);
4227}
4228
4229static void setup_inject(struct sdebug_queue *sqp,
4230 struct sdebug_queued_cmd *sqcp)
4231{
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004232 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4233 if (sdebug_every_nth > 0)
4234 sqcp->inj_recovered = sqcp->inj_transport
4235 = sqcp->inj_dif
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004236 = sqcp->inj_dix = sqcp->inj_short
4237 = sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004238 return;
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004239 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004240 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4241 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4242 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4243 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4244 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004245 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004246 sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004247}
4248
4249/* Complete the processing of the thread that queued a SCSI command to this
4250 * driver. It either completes the command by calling cmnd_done() or
4251 * schedules a hr timer or work queue then returns 0. Returns
4252 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4253 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004254static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01004255 int scsi_result,
4256 int (*pfp)(struct scsi_cmnd *,
4257 struct sdebug_dev_info *),
4258 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004259{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004260 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004261 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004262 struct sdebug_queue *sqp;
4263 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004264 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004265 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004266
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004267 if (unlikely(devip == NULL)) {
4268 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004269 scsi_result = DID_NO_CONNECT << 16;
4270 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004271 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004272 sdp = cmnd->device;
4273
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004274 if (delta_jiff == 0)
4275 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004276
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004277 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004278 sqp = get_queue(cmnd);
4279 spin_lock_irqsave(&sqp->qc_lock, iflags);
4280 if (unlikely(atomic_read(&sqp->blocked))) {
4281 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4282 return SCSI_MLQUEUE_HOST_BUSY;
4283 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004284 num_in_q = atomic_read(&devip->num_in_q);
4285 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004286 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004287 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004288 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004289 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004290 goto respond_in_thread;
4291 } else
4292 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004293 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004294 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4295 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004296 if ((num_in_q == (qdepth - 1)) &&
4297 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004298 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004299 atomic_set(&sdebug_a_tsf, 0);
4300 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004301 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004302 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004303 }
4304
Douglas Gilbertc4837392016-05-06 00:40:26 -04004305 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004306 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004307 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004308 if (scsi_result)
4309 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004310 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004311 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004312 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004313 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004314 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004315 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004316 (scsi_result ? "status: TASK SET FULL" :
4317 "report: host busy"));
4318 if (scsi_result)
4319 goto respond_in_thread;
4320 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004321 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004323 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004324 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004325 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004326 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004327 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004328 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004329 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4330 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4331 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004332 if (sd_dp == NULL) {
4333 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4334 if (sd_dp == NULL)
4335 return SCSI_MLQUEUE_HOST_BUSY;
4336 }
Martin Wilckf66b8512018-02-14 11:05:57 +01004337
4338 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4339 if (cmnd->result & SDEG_RES_IMMED_MASK) {
4340 /*
4341 * This is the F_DELAY_OVERR case. No delay.
4342 */
4343 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4344 delta_jiff = ndelay = 0;
4345 }
4346 if (cmnd->result == 0 && scsi_result != 0)
4347 cmnd->result = scsi_result;
4348
4349 if (unlikely(sdebug_verbose && cmnd->result))
4350 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4351 __func__, cmnd->result);
4352
Douglas Gilbert10bde982018-01-10 16:57:31 -05004353 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004354 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004355
Douglas Gilbertb333a812016-04-25 12:16:30 -04004356 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004357 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004358 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004359 kt = ndelay;
4360 if (!sd_dp->init_hrt) {
4361 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004362 sqcp->sd_dp = sd_dp;
4363 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004364 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004365 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004366 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4367 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004368 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004369 if (sdebug_statistics)
4370 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004371 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004372 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4373 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004374 if (!sd_dp->init_wq) {
4375 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004376 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004377 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4378 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004379 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004380 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004381 if (sdebug_statistics)
4382 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004383 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004384 if (unlikely(sqcp->inj_cmd_abort))
4385 sd_dp->aborted = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004386 schedule_work(&sd_dp->ew.work);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004387 if (unlikely(sqcp->inj_cmd_abort)) {
4388 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
4389 cmnd->request->tag);
4390 blk_abort_request(cmnd->request);
4391 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004392 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004393 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4394 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004395 sdev_printk(KERN_INFO, sdp,
4396 "%s: num_in_q=%d +1, %s%s\n", __func__,
4397 num_in_q, (inject ? "<inject> " : ""),
4398 "status: TASK SET FULL");
4399 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004400
4401respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01004402 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4403 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4404 if (cmnd->result == 0 && scsi_result != 0)
4405 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004406 cmnd->scsi_done(cmnd);
4407 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004408}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004409
Douglas Gilbert23183912006-09-16 20:30:47 -04004410/* Note: The following macros create attribute files in the
4411 /sys/module/scsi_debug/parameters directory. Unfortunately this
4412 driver is unaware of a change and cannot trigger auxiliary actions
4413 as it can when the corresponding attribute in the
4414 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4415 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004416module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4417module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004418module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004419module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004420module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004421module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4422module_param_named(dif, sdebug_dif, int, S_IRUGO);
4423module_param_named(dix, sdebug_dix, int, S_IRUGO);
4424module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4425module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4426module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4427module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4428module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004429module_param_string(inq_vendor, sdebug_inq_vendor_id,
4430 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4431module_param_string(inq_product, sdebug_inq_product_id,
4432 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4433module_param_string(inq_rev, sdebug_inq_product_rev,
4434 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004435module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4436module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4437module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4438module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4439module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4440module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4441module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Laurence Obermand9da8912018-02-03 13:38:35 -05004442module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4443module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004444module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4445module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4446module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4447module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4448module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4449module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4450module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4451module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004452module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004453module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4454module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4455module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4456module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004457module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004458module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004459module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004460module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4461module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4462module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4463module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4464module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004465module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004466module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004467 S_IRUGO | S_IWUSR);
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05004468module_param_named(wp, sdebug_wp, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004469module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004470 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004471
4472MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4473MODULE_DESCRIPTION("SCSI debug adapter driver");
4474MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004475MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004476
4477MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004478MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004479MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004480MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004481MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004482MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004483MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4484MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004485MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004486MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004487MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004488MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004489MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004490MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4491MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004492MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4493 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004494MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4495MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4496MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004497MODULE_PARM_DESC(lbprz,
4498 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004499MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004500MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004501MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05004502MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4503MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004504MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004505MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004506MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004507MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004508MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004509MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004510MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004511MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004512MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004513MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004514MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004515MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004516MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004517MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004518MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004519MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004520MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4521MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004522MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4523MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004524MODULE_PARM_DESC(uuid_ctl,
4525 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004526MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004527MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
Martin K. Petersen9447b6c2019-02-08 18:37:25 -05004528MODULE_PARM_DESC(wp, "Write Protect (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004529MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004530
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004531#define SDEBUG_INFO_LEN 256
4532static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004533
John Pittman91d4c752018-02-09 21:12:43 -05004534static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004535{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004536 int k;
4537
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004538 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4539 my_name, SDEBUG_VERSION, sdebug_version_date);
4540 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004541 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004542 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4543 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4544 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4545 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004546 return sdebug_info;
4547}
4548
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004549/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004550static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4551 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004552{
Al Viroc8ed5552013-03-31 01:46:06 -04004553 char arr[16];
4554 int opts;
4555 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004556
Al Viroc8ed5552013-03-31 01:46:06 -04004557 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4558 return -EACCES;
4559 memcpy(arr, buffer, minLen);
4560 arr[minLen] = '\0';
4561 if (1 != sscanf(arr, "%d", &opts))
4562 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004563 sdebug_opts = opts;
4564 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4565 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4566 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004567 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004568 return length;
4569}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004571/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4572 * same for each scsi_debug host (if more than one). Some of the counters
4573 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004574static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4575{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004576 int f, j, l;
4577 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004578
Douglas Gilbertc4837392016-05-06 00:40:26 -04004579 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4580 SDEBUG_VERSION, sdebug_version_date);
4581 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4582 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4583 sdebug_opts, sdebug_every_nth);
4584 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4585 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4586 sdebug_sector_size, "bytes");
4587 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4588 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4589 num_aborts);
4590 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4591 num_dev_resets, num_target_resets, num_bus_resets,
4592 num_host_resets);
4593 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4594 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004595 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4596 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004597 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4598 atomic_read(&sdebug_cmnd_count),
4599 atomic_read(&sdebug_completions),
4600 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4601 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004602
Douglas Gilbertc4837392016-05-06 00:40:26 -04004603 seq_printf(m, "submit_queues=%d\n", submit_queues);
4604 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4605 seq_printf(m, " queue %d:\n", j);
4606 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4607 if (f != sdebug_max_queue) {
4608 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4609 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4610 "first,last bits", f, l);
4611 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004612 }
Al Viroc8ed5552013-03-31 01:46:06 -04004613 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004614}
4615
Akinobu Mita82069372013-10-14 22:48:04 +09004616static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004617{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004618 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004619}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004620/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4621 * of delay is jiffies.
4622 */
Akinobu Mita82069372013-10-14 22:48:04 +09004623static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4624 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004625{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004626 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004627
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004628 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004629 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004630 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004631 int j, k;
4632 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004633
Douglas Gilbertc4837392016-05-06 00:40:26 -04004634 block_unblock_all_queues(true);
4635 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4636 ++j, ++sqp) {
4637 k = find_first_bit(sqp->in_use_bm,
4638 sdebug_max_queue);
4639 if (k != sdebug_max_queue) {
4640 res = -EBUSY; /* queued commands */
4641 break;
4642 }
4643 }
4644 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004645 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004646 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004647 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004648 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004649 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004650 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004651 }
4652 return -EINVAL;
4653}
Akinobu Mita82069372013-10-14 22:48:04 +09004654static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004655
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004656static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4657{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004658 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004659}
4660/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004661/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004662static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004663 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004664{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004665 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004666
4667 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004668 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004669 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004670 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004671 int j, k;
4672 struct sdebug_queue *sqp;
4673
4674 block_unblock_all_queues(true);
4675 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4676 ++j, ++sqp) {
4677 k = find_first_bit(sqp->in_use_bm,
4678 sdebug_max_queue);
4679 if (k != sdebug_max_queue) {
4680 res = -EBUSY; /* queued commands */
4681 break;
4682 }
4683 }
4684 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004685 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004686 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4687 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004688 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004689 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004690 }
4691 return res;
4692 }
4693 return -EINVAL;
4694}
4695static DRIVER_ATTR_RW(ndelay);
4696
Akinobu Mita82069372013-10-14 22:48:04 +09004697static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004698{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004699 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004700}
4701
Akinobu Mita82069372013-10-14 22:48:04 +09004702static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4703 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004704{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004705 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004706 char work[20];
4707
Douglas Gilbert9a051012017-12-23 12:48:10 -05004708 if (sscanf(buf, "%10s", work) == 1) {
4709 if (strncasecmp(work, "0x", 2) == 0) {
4710 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004711 goto opts_done;
4712 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004713 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004714 goto opts_done;
4715 }
4716 }
4717 return -EINVAL;
4718opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004719 sdebug_opts = opts;
4720 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4721 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004722 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004723 return count;
4724}
Akinobu Mita82069372013-10-14 22:48:04 +09004725static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004726
Akinobu Mita82069372013-10-14 22:48:04 +09004727static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004728{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004729 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004730}
Akinobu Mita82069372013-10-14 22:48:04 +09004731static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4732 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004733{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004734 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004735
4736 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004737 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004738 return count;
4739 }
4740 return -EINVAL;
4741}
Akinobu Mita82069372013-10-14 22:48:04 +09004742static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004743
Akinobu Mita82069372013-10-14 22:48:04 +09004744static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004745{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004746 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004747}
Akinobu Mita82069372013-10-14 22:48:04 +09004748static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4749 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004750{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004751 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004752
4753 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004754 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004755 return count;
4756 }
4757 return -EINVAL;
4758}
Akinobu Mita82069372013-10-14 22:48:04 +09004759static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004760
Akinobu Mita82069372013-10-14 22:48:04 +09004761static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004762{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004763 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004764}
Akinobu Mita82069372013-10-14 22:48:04 +09004765static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4766 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004767{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004768 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004769
4770 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004771 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004772 sdebug_fake_rw = (sdebug_fake_rw > 0);
4773 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004774 if ((0 == n) && (NULL == fake_storep)) {
4775 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004776 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004777 1048576;
4778
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004779 fake_storep = vzalloc(sz);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004780 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004781 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004782 return -ENOMEM;
4783 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004784 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004785 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004786 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004787 return count;
4788 }
4789 return -EINVAL;
4790}
Akinobu Mita82069372013-10-14 22:48:04 +09004791static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004792
Akinobu Mita82069372013-10-14 22:48:04 +09004793static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004794{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004795 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004796}
Akinobu Mita82069372013-10-14 22:48:04 +09004797static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4798 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004799{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004800 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004801
4802 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004803 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004804 return count;
4805 }
4806 return -EINVAL;
4807}
Akinobu Mita82069372013-10-14 22:48:04 +09004808static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004809
Akinobu Mita82069372013-10-14 22:48:04 +09004810static ssize_t num_tgts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004811{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004812 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004813}
Akinobu Mita82069372013-10-14 22:48:04 +09004814static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4815 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004816{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004817 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004818
4819 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004820 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004821 sdebug_max_tgts_luns();
4822 return count;
4823 }
4824 return -EINVAL;
4825}
Akinobu Mita82069372013-10-14 22:48:04 +09004826static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004827
Akinobu Mita82069372013-10-14 22:48:04 +09004828static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004829{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004830 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831}
Akinobu Mita82069372013-10-14 22:48:04 +09004832static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004833
Akinobu Mita82069372013-10-14 22:48:04 +09004834static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004835{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004836 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004837}
Akinobu Mita82069372013-10-14 22:48:04 +09004838static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839
Akinobu Mita82069372013-10-14 22:48:04 +09004840static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004841{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004842 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004843}
Akinobu Mita82069372013-10-14 22:48:04 +09004844static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4845 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004846{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004847 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004848
4849 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004850 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004851 if (nth && !sdebug_statistics) {
4852 pr_info("every_nth needs statistics=1, set it\n");
4853 sdebug_statistics = true;
4854 }
4855 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004856 return count;
4857 }
4858 return -EINVAL;
4859}
Akinobu Mita82069372013-10-14 22:48:04 +09004860static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861
Akinobu Mita82069372013-10-14 22:48:04 +09004862static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004863{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004864 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004865}
Akinobu Mita82069372013-10-14 22:48:04 +09004866static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4867 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004868{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004869 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004870 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004871
4872 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004873 if (n > 256) {
4874 pr_warn("max_luns can be no more than 256\n");
4875 return -EINVAL;
4876 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004877 changed = (sdebug_max_luns != n);
4878 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004880 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004881 struct sdebug_host_info *sdhp;
4882 struct sdebug_dev_info *dp;
4883
4884 spin_lock(&sdebug_host_list_lock);
4885 list_for_each_entry(sdhp, &sdebug_host_list,
4886 host_list) {
4887 list_for_each_entry(dp, &sdhp->dev_info_list,
4888 dev_list) {
4889 set_bit(SDEBUG_UA_LUNS_CHANGED,
4890 dp->uas_bm);
4891 }
4892 }
4893 spin_unlock(&sdebug_host_list_lock);
4894 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004895 return count;
4896 }
4897 return -EINVAL;
4898}
Akinobu Mita82069372013-10-14 22:48:04 +09004899static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004900
Akinobu Mita82069372013-10-14 22:48:04 +09004901static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004902{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004903 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004904}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004905/* N.B. max_queue can be changed while there are queued commands. In flight
4906 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004907static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4908 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004909{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004910 int j, n, k, a;
4911 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004912
4913 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004914 (n <= SDEBUG_CANQUEUE)) {
4915 block_unblock_all_queues(true);
4916 k = 0;
4917 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4918 ++j, ++sqp) {
4919 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4920 if (a > k)
4921 k = a;
4922 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004923 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004924 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004925 atomic_set(&retired_max_queue, 0);
4926 else if (k >= n)
4927 atomic_set(&retired_max_queue, k + 1);
4928 else
4929 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004930 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004931 return count;
4932 }
4933 return -EINVAL;
4934}
Akinobu Mita82069372013-10-14 22:48:04 +09004935static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004936
Akinobu Mita82069372013-10-14 22:48:04 +09004937static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004938{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004939 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004940}
Akinobu Mita82069372013-10-14 22:48:04 +09004941static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004942
Akinobu Mita82069372013-10-14 22:48:04 +09004943static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004944{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004945 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004946}
Akinobu Mita82069372013-10-14 22:48:04 +09004947static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004948
Akinobu Mita82069372013-10-14 22:48:04 +09004949static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004950{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004951 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004952}
Akinobu Mita82069372013-10-14 22:48:04 +09004953static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4954 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004955{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004956 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004957 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004958
4959 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004960 changed = (sdebug_virtual_gb != n);
4961 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004962 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004963 if (changed) {
4964 struct sdebug_host_info *sdhp;
4965 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004966
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004967 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004968 list_for_each_entry(sdhp, &sdebug_host_list,
4969 host_list) {
4970 list_for_each_entry(dp, &sdhp->dev_info_list,
4971 dev_list) {
4972 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4973 dp->uas_bm);
4974 }
4975 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004976 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004977 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004978 return count;
4979 }
4980 return -EINVAL;
4981}
Akinobu Mita82069372013-10-14 22:48:04 +09004982static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004983
Akinobu Mita82069372013-10-14 22:48:04 +09004984static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004985{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004986 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004987}
4988
Douglas Gilbertfd321192016-04-25 12:16:33 -04004989static int sdebug_add_adapter(void);
4990static void sdebug_remove_adapter(void);
4991
Akinobu Mita82069372013-10-14 22:48:04 +09004992static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
4993 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004994{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004995 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004996
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09004997 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004998 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004999 if (delta_hosts > 0) {
5000 do {
5001 sdebug_add_adapter();
5002 } while (--delta_hosts);
5003 } else if (delta_hosts < 0) {
5004 do {
5005 sdebug_remove_adapter();
5006 } while (++delta_hosts);
5007 }
5008 return count;
5009}
Akinobu Mita82069372013-10-14 22:48:04 +09005010static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005011
Akinobu Mita82069372013-10-14 22:48:04 +09005012static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005013{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005014 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005015}
Akinobu Mita82069372013-10-14 22:48:04 +09005016static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5017 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005018{
5019 int n;
5020
5021 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005022 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005023 return count;
5024 }
5025 return -EINVAL;
5026}
Akinobu Mita82069372013-10-14 22:48:04 +09005027static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005028
Douglas Gilbertc4837392016-05-06 00:40:26 -04005029static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5030{
5031 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5032}
5033static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5034 size_t count)
5035{
5036 int n;
5037
5038 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5039 if (n > 0)
5040 sdebug_statistics = true;
5041 else {
5042 clear_queue_stats();
5043 sdebug_statistics = false;
5044 }
5045 return count;
5046 }
5047 return -EINVAL;
5048}
5049static DRIVER_ATTR_RW(statistics);
5050
Akinobu Mita82069372013-10-14 22:48:04 +09005051static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005052{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005053 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005054}
Akinobu Mita82069372013-10-14 22:48:04 +09005055static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005056
Douglas Gilbertc4837392016-05-06 00:40:26 -04005057static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5058{
5059 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5060}
5061static DRIVER_ATTR_RO(submit_queues);
5062
Akinobu Mita82069372013-10-14 22:48:04 +09005063static ssize_t dix_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005064{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005065 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005066}
Akinobu Mita82069372013-10-14 22:48:04 +09005067static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005068
Akinobu Mita82069372013-10-14 22:48:04 +09005069static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005070{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005071 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005072}
Akinobu Mita82069372013-10-14 22:48:04 +09005073static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005074
Akinobu Mita82069372013-10-14 22:48:04 +09005075static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005076{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005077 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005078}
Akinobu Mita82069372013-10-14 22:48:04 +09005079static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005080
Akinobu Mita82069372013-10-14 22:48:04 +09005081static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005082{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005083 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005084}
Akinobu Mita82069372013-10-14 22:48:04 +09005085static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005086
Akinobu Mita82069372013-10-14 22:48:04 +09005087static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005088{
5089 ssize_t count;
5090
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005091 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005092 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5093 sdebug_store_sectors);
5094
Tejun Heoc7badc92015-02-13 14:37:51 -08005095 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5096 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005097 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005098 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005099
5100 return count;
5101}
Akinobu Mita82069372013-10-14 22:48:04 +09005102static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005103
Akinobu Mita82069372013-10-14 22:48:04 +09005104static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005105{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005106 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005107}
Akinobu Mita82069372013-10-14 22:48:04 +09005108static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5109 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005110{
5111 int n;
5112
5113 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005114 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005115 return count;
5116 }
5117 return -EINVAL;
5118}
Akinobu Mita82069372013-10-14 22:48:04 +09005119static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005120
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005121static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5122{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005123 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005124}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005125/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005126static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5127 size_t count)
5128{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005129 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005130
5131 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005132 sdebug_host_lock = (n > 0);
5133 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005134 }
5135 return -EINVAL;
5136}
5137static DRIVER_ATTR_RW(host_lock);
5138
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005139static ssize_t strict_show(struct device_driver *ddp, char *buf)
5140{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005141 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005142}
5143static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5144 size_t count)
5145{
5146 int n;
5147
5148 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005149 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005150 return count;
5151 }
5152 return -EINVAL;
5153}
5154static DRIVER_ATTR_RW(strict);
5155
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005156static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5157{
5158 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5159}
5160static DRIVER_ATTR_RO(uuid_ctl);
5161
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005162static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5163{
5164 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5165}
5166static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5167 size_t count)
5168{
5169 int ret, n;
5170
5171 ret = kstrtoint(buf, 0, &n);
5172 if (ret)
5173 return ret;
5174 sdebug_cdb_len = n;
5175 all_config_cdb_len();
5176 return count;
5177}
5178static DRIVER_ATTR_RW(cdb_len);
5179
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005180
Akinobu Mita82069372013-10-14 22:48:04 +09005181/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005182 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5183 files (over those found in the /sys/module/scsi_debug/parameters
5184 directory) is that auxiliary actions can be triggered when an attribute
5185 is changed. For example see: sdebug_add_host_store() above.
5186 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005187
Akinobu Mita82069372013-10-14 22:48:04 +09005188static struct attribute *sdebug_drv_attrs[] = {
5189 &driver_attr_delay.attr,
5190 &driver_attr_opts.attr,
5191 &driver_attr_ptype.attr,
5192 &driver_attr_dsense.attr,
5193 &driver_attr_fake_rw.attr,
5194 &driver_attr_no_lun_0.attr,
5195 &driver_attr_num_tgts.attr,
5196 &driver_attr_dev_size_mb.attr,
5197 &driver_attr_num_parts.attr,
5198 &driver_attr_every_nth.attr,
5199 &driver_attr_max_luns.attr,
5200 &driver_attr_max_queue.attr,
5201 &driver_attr_no_uld.attr,
5202 &driver_attr_scsi_level.attr,
5203 &driver_attr_virtual_gb.attr,
5204 &driver_attr_add_host.attr,
5205 &driver_attr_vpd_use_hostno.attr,
5206 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005207 &driver_attr_statistics.attr,
5208 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005209 &driver_attr_dix.attr,
5210 &driver_attr_dif.attr,
5211 &driver_attr_guard.attr,
5212 &driver_attr_ato.attr,
5213 &driver_attr_map.attr,
5214 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005215 &driver_attr_host_lock.attr,
5216 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005217 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005218 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005219 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005220 NULL,
5221};
5222ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005223
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005224static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005225
Linus Torvalds1da177e2005-04-16 15:20:36 -07005226static int __init scsi_debug_init(void)
5227{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005228 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005229 int host_to_add;
5230 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005231 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005232
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005233 atomic_set(&retired_max_queue, 0);
5234
Douglas Gilbert773642d2016-04-25 12:16:28 -04005235 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005236 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005237 sdebug_ndelay = 0;
5238 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005239 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005240
Douglas Gilbert773642d2016-04-25 12:16:28 -04005241 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005242 case 512:
5243 case 1024:
5244 case 2048:
5245 case 4096:
5246 break;
5247 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005248 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005249 return -EINVAL;
5250 }
5251
Douglas Gilbert773642d2016-04-25 12:16:28 -04005252 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005253 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005254 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005255 case T10_PI_TYPE1_PROTECTION:
5256 case T10_PI_TYPE2_PROTECTION:
5257 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005258 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005259 break;
5260
5261 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005262 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005263 return -EINVAL;
5264 }
5265
Douglas Gilbert773642d2016-04-25 12:16:28 -04005266 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005267 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005268 return -EINVAL;
5269 }
5270
Douglas Gilbert773642d2016-04-25 12:16:28 -04005271 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005272 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005273 return -EINVAL;
5274 }
5275
Douglas Gilbert773642d2016-04-25 12:16:28 -04005276 if (sdebug_physblk_exp > 15) {
5277 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005278 return -EINVAL;
5279 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005280 if (sdebug_max_luns > 256) {
5281 pr_warn("max_luns can be no more than 256, use default\n");
5282 sdebug_max_luns = DEF_MAX_LUNS;
5283 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005284
Douglas Gilbert773642d2016-04-25 12:16:28 -04005285 if (sdebug_lowest_aligned > 0x3fff) {
5286 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005287 return -EINVAL;
5288 }
5289
Douglas Gilbertc4837392016-05-06 00:40:26 -04005290 if (submit_queues < 1) {
5291 pr_err("submit_queues must be 1 or more\n");
5292 return -EINVAL;
5293 }
5294 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5295 GFP_KERNEL);
5296 if (sdebug_q_arr == NULL)
5297 return -ENOMEM;
5298 for (k = 0; k < submit_queues; ++k)
5299 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5300
Douglas Gilbert773642d2016-04-25 12:16:28 -04005301 if (sdebug_dev_size_mb < 1)
5302 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5303 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5304 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005305 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005306
5307 /* play around with geometry, don't waste too much on track 0 */
5308 sdebug_heads = 8;
5309 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005310 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005311 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005312 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005313 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005314 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5315 (sdebug_sectors_per * sdebug_heads);
5316 if (sdebug_cylinders_per >= 1024) {
5317 /* other LLDs do this; implies >= 1GB ram disk ... */
5318 sdebug_heads = 255;
5319 sdebug_sectors_per = 63;
5320 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5321 (sdebug_sectors_per * sdebug_heads);
5322 }
5323
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005324 if (sdebug_fake_rw == 0) {
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005325 fake_storep = vzalloc(sz);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005326 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005327 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005328 ret = -ENOMEM;
5329 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005330 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005331 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005332 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005334
Douglas Gilbert773642d2016-04-25 12:16:28 -04005335 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005336 int dif_size;
5337
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005338 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005339 dif_storep = vmalloc(dif_size);
5340
Tomas Winklerc12879702015-07-28 16:54:20 +03005341 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005342
5343 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005344 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005345 ret = -ENOMEM;
5346 goto free_vm;
5347 }
5348
5349 memset(dif_storep, 0xff, dif_size);
5350 }
5351
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005352 /* Logical Block Provisioning */
5353 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005354 sdebug_unmap_max_blocks =
5355 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005356
Douglas Gilbert773642d2016-04-25 12:16:28 -04005357 sdebug_unmap_max_desc =
5358 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005359
Douglas Gilbert773642d2016-04-25 12:16:28 -04005360 sdebug_unmap_granularity =
5361 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005362
Douglas Gilbert773642d2016-04-25 12:16:28 -04005363 if (sdebug_unmap_alignment &&
5364 sdebug_unmap_granularity <=
5365 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005366 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005367 ret = -EINVAL;
5368 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005369 }
5370
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005371 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
Kees Cook42bc47b2018-06-12 14:27:11 -07005372 map_storep = vmalloc(array_size(sizeof(long),
5373 BITS_TO_LONGS(map_size)));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005374
Tomas Winklerc12879702015-07-28 16:54:20 +03005375 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005376
5377 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005378 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005379 ret = -ENOMEM;
5380 goto free_vm;
5381 }
5382
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005383 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005384
5385 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005386 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005387 map_region(0, 2);
5388 }
5389
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005390 pseudo_primary = root_device_register("pseudo_0");
5391 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005392 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005393 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005394 goto free_vm;
5395 }
5396 ret = bus_register(&pseudo_lld_bus);
5397 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005398 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005399 goto dev_unreg;
5400 }
5401 ret = driver_register(&sdebug_driverfs_driver);
5402 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005403 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005404 goto bus_unreg;
5405 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005406
Douglas Gilbert773642d2016-04-25 12:16:28 -04005407 host_to_add = sdebug_add_host;
5408 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005409
Douglas Gilbert9a051012017-12-23 12:48:10 -05005410 for (k = 0; k < host_to_add; k++) {
5411 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005412 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005413 break;
5414 }
5415 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005416
Douglas Gilbert773642d2016-04-25 12:16:28 -04005417 if (sdebug_verbose)
5418 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005419
Linus Torvalds1da177e2005-04-16 15:20:36 -07005420 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005421
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005422bus_unreg:
5423 bus_unregister(&pseudo_lld_bus);
5424dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005425 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005426free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005427 vfree(map_storep);
5428 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005429 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005430free_q_arr:
5431 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005432 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005433}
5434
5435static void __exit scsi_debug_exit(void)
5436{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005437 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438
5439 stop_all_queued();
5440 for (; k; k--)
5441 sdebug_remove_adapter();
Luis Henriques52ab9762018-06-18 17:08:03 +01005442 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005443 driver_unregister(&sdebug_driverfs_driver);
5444 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005445 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005446
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005447 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005448 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005449 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005450 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451}
5452
5453device_initcall(scsi_debug_init);
5454module_exit(scsi_debug_exit);
5455
John Pittman91d4c752018-02-09 21:12:43 -05005456static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005457{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005458 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005459
5460 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005461 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005462}
5463
5464static int sdebug_add_adapter(void)
5465{
5466 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005467 int error = 0;
5468 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005469 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005470
Douglas Gilbert9a051012017-12-23 12:48:10 -05005471 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5472 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005473 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005474 return -ENOMEM;
5475 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005476
Douglas Gilbert9a051012017-12-23 12:48:10 -05005477 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005478
Douglas Gilbert773642d2016-04-25 12:16:28 -04005479 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005480 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005481 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5482 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005483 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005484 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005485 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005486 }
5487 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Douglas Gilbert9a051012017-12-23 12:48:10 -05005489 spin_lock(&sdebug_host_list_lock);
5490 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5491 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005492
Douglas Gilbert9a051012017-12-23 12:48:10 -05005493 sdbg_host->dev.bus = &pseudo_lld_bus;
5494 sdbg_host->dev.parent = pseudo_primary;
5495 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005496 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005497
Douglas Gilbert9a051012017-12-23 12:48:10 -05005498 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005499
Douglas Gilbert9a051012017-12-23 12:48:10 -05005500 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005501 goto clean;
5502
Douglas Gilbert773642d2016-04-25 12:16:28 -04005503 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005504 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005505
5506clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005507 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5508 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005509 list_del(&sdbg_devinfo->dev_list);
5510 kfree(sdbg_devinfo);
5511 }
5512
5513 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005514 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515}
5516
5517static void sdebug_remove_adapter(void)
5518{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005519 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005520
Douglas Gilbert9a051012017-12-23 12:48:10 -05005521 spin_lock(&sdebug_host_list_lock);
5522 if (!list_empty(&sdebug_host_list)) {
5523 sdbg_host = list_entry(sdebug_host_list.prev,
5524 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005525 list_del(&sdbg_host->host_list);
5526 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005527 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005528
5529 if (!sdbg_host)
5530 return;
5531
Douglas Gilbert773642d2016-04-25 12:16:28 -04005532 device_unregister(&sdbg_host->dev);
5533 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005534}
5535
Douglas Gilbertfd321192016-04-25 12:16:33 -04005536static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005537{
5538 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005539 struct sdebug_dev_info *devip;
5540
Douglas Gilbertc4837392016-05-06 00:40:26 -04005541 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005542 devip = (struct sdebug_dev_info *)sdev->hostdata;
5543 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005544 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005545 return -ENODEV;
5546 }
5547 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005548
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005549 if (qdepth < 1)
5550 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005551 /* allow to exceed max host qc_arr elements for testing */
5552 if (qdepth > SDEBUG_CANQUEUE + 10)
5553 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005554 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005555
Douglas Gilbert773642d2016-04-25 12:16:28 -04005556 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005557 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005558 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005559 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005560 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005561 return sdev->queue_depth;
5562}
5563
Douglas Gilbertc4837392016-05-06 00:40:26 -04005564static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005565{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005566 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005567 if (sdebug_every_nth < -1)
5568 sdebug_every_nth = -1;
5569 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005570 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005571 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005572 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005573 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005574 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005575 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005576}
5577
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005578static bool fake_host_busy(struct scsi_cmnd *scp)
5579{
5580 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5581 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5582}
5583
Douglas Gilbertfd321192016-04-25 12:16:33 -04005584static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5585 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005586{
5587 u8 sdeb_i;
5588 struct scsi_device *sdp = scp->device;
5589 const struct opcode_info_t *oip;
5590 const struct opcode_info_t *r_oip;
5591 struct sdebug_dev_info *devip;
5592 u8 *cmd = scp->cmnd;
5593 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01005594 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005595 int k, na;
5596 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005597 u32 flags;
5598 u16 sa;
5599 u8 opcode = cmd[0];
5600 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005601
5602 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005603 if (sdebug_statistics)
5604 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005605 if (unlikely(sdebug_verbose &&
5606 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005607 char b[120];
5608 int n, len, sb;
5609
5610 len = scp->cmd_len;
5611 sb = (int)sizeof(b);
5612 if (len > 32)
5613 strcpy(b, "too long, over 32 bytes");
5614 else {
5615 for (k = 0, n = 0; k < len && n < sb; ++k)
5616 n += scnprintf(b + n, sb - n, "%02x ",
5617 (u32)cmd[k]);
5618 }
Bart Van Assche458df782018-01-26 08:52:19 -08005619 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5620 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005621 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005622 if (fake_host_busy(scp))
5623 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005624 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005625 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5626 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005627
5628 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5629 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5630 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005631 if (unlikely(!devip)) {
5632 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005633 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005634 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005635 }
5636 na = oip->num_attached;
5637 r_pfp = oip->pfp;
5638 if (na) { /* multiple commands with this opcode */
5639 r_oip = oip;
5640 if (FF_SA & r_oip->flags) {
5641 if (F_SA_LOW & oip->flags)
5642 sa = 0x1f & cmd[1];
5643 else
5644 sa = get_unaligned_be16(cmd + 8);
5645 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5646 if (opcode == oip->opcode && sa == oip->sa)
5647 break;
5648 }
5649 } else { /* since no service action only check opcode */
5650 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5651 if (opcode == oip->opcode)
5652 break;
5653 }
5654 }
5655 if (k > na) {
5656 if (F_SA_LOW & r_oip->flags)
5657 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5658 else if (F_SA_HIGH & r_oip->flags)
5659 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5660 else
5661 mk_sense_invalid_opcode(scp);
5662 goto check_cond;
5663 }
5664 } /* else (when na==0) we assume the oip is a match */
5665 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005666 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005667 mk_sense_invalid_opcode(scp);
5668 goto check_cond;
5669 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005670 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005671 if (sdebug_verbose)
5672 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5673 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005674 mk_sense_invalid_opcode(scp);
5675 goto check_cond;
5676 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005677 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005678 u8 rem;
5679 int j;
5680
5681 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5682 rem = ~oip->len_mask[k] & cmd[k];
5683 if (rem) {
5684 for (j = 7; j >= 0; --j, rem <<= 1) {
5685 if (0x80 & rem)
5686 break;
5687 }
5688 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5689 goto check_cond;
5690 }
5691 }
5692 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005693 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005694 find_first_bit(devip->uas_bm,
5695 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005696 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005697 if (errsts)
5698 goto check_cond;
5699 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005700 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005701 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005702 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005703 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5704 "%s\n", my_name, "initializing command "
5705 "required");
5706 errsts = check_condition_result;
5707 goto fini;
5708 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005709 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005710 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005711 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005712 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005713 return 0; /* ignore command: make trouble */
5714 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005715 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01005716 pfp = oip->pfp; /* calls a resp_* function */
5717 else
5718 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005719
5720fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005721 if (F_DELAY_OVERR & flags)
Martin Wilckf66b8512018-02-14 11:05:57 +01005722 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04005723 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
5724 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05005725 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04005726 * Skip long delays if ndelay <= 10 microseconds. Otherwise
5727 * for Start Stop Unit (SSU) want at least 1 second delay and
5728 * if sdebug_jdelay>1 want a long delay of that many seconds.
5729 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05005730 */
5731 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005732 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05005733
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005734 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01005735 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005736 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01005737 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05005738 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005739check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01005740 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005741err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01005742 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005743}
5744
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005745static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005746 .show_info = scsi_debug_show_info,
5747 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005748 .proc_name = sdebug_proc_name,
5749 .name = "SCSI DEBUG",
5750 .info = scsi_debug_info,
5751 .slave_alloc = scsi_debug_slave_alloc,
5752 .slave_configure = scsi_debug_slave_configure,
5753 .slave_destroy = scsi_debug_slave_destroy,
5754 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005755 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005756 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005757 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005758 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005759 .eh_target_reset_handler = scsi_debug_target_reset,
5760 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005761 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005762 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005763 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005764 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005765 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005766 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01005767 .max_segment_size = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005768 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005769 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005770};
5771
John Pittman91d4c752018-02-09 21:12:43 -05005772static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005773{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005774 int error = 0;
5775 struct sdebug_host_info *sdbg_host;
5776 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005777 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005778
5779 sdbg_host = to_sdebug_host(dev);
5780
Douglas Gilbert773642d2016-04-25 12:16:28 -04005781 sdebug_driver_template.can_queue = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01005782 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01005783 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
5784
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005785 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5786 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005787 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005788 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005789 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005790 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005791 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005792 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005793 my_name, submit_queues, nr_cpu_ids);
5794 submit_queues = nr_cpu_ids;
5795 }
5796 /* Decide whether to tell scsi subsystem that we want mq */
5797 /* Following should give the same answer for each host */
Jens Axboef664a3c2018-11-01 16:36:27 -06005798 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005799
Douglas Gilbert9a051012017-12-23 12:48:10 -05005800 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005801 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005802 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5803 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005804 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005805 hpnt->max_id = sdebug_num_tgts;
5806 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005807 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005808
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005809 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005810
Douglas Gilbert773642d2016-04-25 12:16:28 -04005811 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005812
Christoph Hellwig8475c812016-09-11 19:35:41 +02005813 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005814 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005815 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005816 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005817 break;
5818
Christoph Hellwig8475c812016-09-11 19:35:41 +02005819 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005820 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005821 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005822 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005823 break;
5824
Christoph Hellwig8475c812016-09-11 19:35:41 +02005825 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005826 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005827 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005828 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005829 break;
5830
5831 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005832 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005833 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005834 break;
5835 }
5836
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005837 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005838
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005839 if (have_dif_prot || sdebug_dix)
5840 pr_info("host protection%s%s%s%s%s%s%s\n",
5841 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5842 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5843 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5844 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5845 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5846 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5847 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005848
Douglas Gilbert773642d2016-04-25 12:16:28 -04005849 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005850 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5851 else
5852 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5853
Douglas Gilbert773642d2016-04-25 12:16:28 -04005854 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5855 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005856 if (sdebug_every_nth) /* need stats counters for every_nth */
5857 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005858 error = scsi_add_host(hpnt, &sdbg_host->dev);
5859 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005860 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005861 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005862 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005863 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005864 scsi_scan_host(hpnt);
5865
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005866 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005867}
5868
John Pittman91d4c752018-02-09 21:12:43 -05005869static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005870{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005871 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005872 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005873
5874 sdbg_host = to_sdebug_host(dev);
5875
5876 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005877 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005878 return -ENODEV;
5879 }
5880
Douglas Gilbert9a051012017-12-23 12:48:10 -05005881 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005883 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5884 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005885 list_del(&sdbg_devinfo->dev_list);
5886 kfree(sdbg_devinfo);
5887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888
Douglas Gilbert9a051012017-12-23 12:48:10 -05005889 scsi_host_put(sdbg_host->shost);
5890 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891}
5892
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005893static int pseudo_lld_bus_match(struct device *dev,
5894 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005895{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005896 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005897}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005898
5899static struct bus_type pseudo_lld_bus = {
5900 .name = "pseudo",
5901 .match = pseudo_lld_bus_match,
5902 .probe = sdebug_driver_probe,
5903 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005904 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005905};