blob: 4c9339ea455de3d37ec60cd37a3e94acd4207a0f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3 * Copyright (C) 1992 Eric Youngdale
4 * Simulate a host adapter with 2 disks attached. Do a lot of checking
5 * to make sure that we are not getting blocks mixed up, and PANIC if
6 * anything out of the ordinary is seen.
7 * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
8 *
Douglas Gilbert80c49562018-02-09 21:36:39 -05009 * Copyright (C) 2001 - 2018 Douglas Gilbert
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
Douglas Gilbert773642d2016-04-25 12:16:28 -040011 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2, or (at your option)
14 * any later version.
Linus Torvalds1da177e2005-04-16 15:20:36 -070015 *
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -040016 * For documentation see http://sg.danny.cz/sg/sdebug26.html
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 *
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 */
19
Tomas Winklerc12879702015-07-28 16:54:20 +030020
21#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/module.h>
24
25#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <linux/errno.h>
Douglas Gilbertb333a812016-04-25 12:16:30 -040027#include <linux/jiffies.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090028#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <linux/types.h>
30#include <linux/string.h>
31#include <linux/genhd.h>
32#include <linux/fs.h>
33#include <linux/init.h>
34#include <linux/proc_fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/vmalloc.h>
36#include <linux/moduleparam.h>
Jens Axboe852e0342007-07-16 10:19:24 +020037#include <linux/scatterlist.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070038#include <linux/blkdev.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050039#include <linux/crc-t10dif.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040040#include <linux/spinlock.h>
41#include <linux/interrupt.h>
42#include <linux/atomic.h>
43#include <linux/hrtimer.h>
Douglas Gilbert09ba24c2016-05-06 00:40:28 -040044#include <linux/uuid.h>
Christoph Hellwig6ebf1052016-09-11 19:35:39 +020045#include <linux/t10-pi.h>
Martin K. Petersenc6a44282009-01-04 03:08:19 -050046
47#include <net/checksum.h>
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090048
Martin K. Petersen44d92692009-10-15 14:45:27 -040049#include <asm/unaligned.h>
50
FUJITA Tomonori9ff26ee2008-03-02 18:30:15 +090051#include <scsi/scsi.h>
52#include <scsi/scsi_cmnd.h>
53#include <scsi/scsi_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#include <scsi/scsi_host.h>
55#include <scsi/scsicam.h>
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +090056#include <scsi/scsi_eh.h>
Douglas Gilbertcbf67842014-07-26 11:55:35 -040057#include <scsi/scsi_tcq.h>
Martin K. Petersen395cef02009-09-18 17:33:03 -040058#include <scsi/scsi_dbg.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070059
Martin K. Petersenc6a44282009-01-04 03:08:19 -050060#include "sd.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061#include "scsi_logging.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Douglas Gilbert773642d2016-04-25 12:16:28 -040063/* make sure inq_product_rev string corresponds to this version */
Douglas Gilbert80c49562018-02-09 21:36:39 -050064#define SDEBUG_VERSION "0188" /* format to fit INQUIRY revision field */
65static const char *sdebug_version_date = "20180128";
Douglas Gilbertcbf67842014-07-26 11:55:35 -040066
67#define MY_NAME "scsi_debug"
Linus Torvalds1da177e2005-04-16 15:20:36 -070068
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050069/* Additional Sense Code (ASC) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -040070#define NO_ADDITIONAL_SENSE 0x0
71#define LOGICAL_UNIT_NOT_READY 0x4
Douglas Gilbertc2248fc2014-11-24 20:46:29 -050072#define LOGICAL_UNIT_COMMUNICATION_FAILURE 0x8
Linus Torvalds1da177e2005-04-16 15:20:36 -070073#define UNRECOVERED_READ_ERR 0x11
Douglas Gilbertc65b1442006-06-06 00:11:24 -040074#define PARAMETER_LIST_LENGTH_ERR 0x1a
Linus Torvalds1da177e2005-04-16 15:20:36 -070075#define INVALID_OPCODE 0x20
Douglas Gilbert22017ed2014-11-24 23:04:47 -050076#define LBA_OUT_OF_RANGE 0x21
Linus Torvalds1da177e2005-04-16 15:20:36 -070077#define INVALID_FIELD_IN_CDB 0x24
Douglas Gilbertc65b1442006-06-06 00:11:24 -040078#define INVALID_FIELD_IN_PARAM_LIST 0x26
Douglas Gilbertcbf67842014-07-26 11:55:35 -040079#define UA_RESET_ASC 0x29
80#define UA_CHANGED_ASC 0x2a
Ewan D. Milne19c8ead2014-12-04 11:49:27 -050081#define TARGET_CHANGED_ASC 0x3f
82#define LUNS_CHANGED_ASCQ 0x0e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050083#define INSUFF_RES_ASC 0x55
84#define INSUFF_RES_ASCQ 0x3
Douglas Gilbertcbf67842014-07-26 11:55:35 -040085#define POWER_ON_RESET_ASCQ 0x0
86#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
87#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
Douglas Gilbert22017ed2014-11-24 23:04:47 -050088#define CAPACITY_CHANGED_ASCQ 0x9
Linus Torvalds1da177e2005-04-16 15:20:36 -070089#define SAVING_PARAMS_UNSUP 0x39
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050090#define TRANSPORT_PROBLEM 0x4b
Douglas Gilbertc65b1442006-06-06 00:11:24 -040091#define THRESHOLD_EXCEEDED 0x5d
92#define LOW_POWER_COND_ON 0x5e
Douglas Gilbert22017ed2014-11-24 23:04:47 -050093#define MISCOMPARE_VERIFY_ASC 0x1d
Ewan D. Milneacafd0b2014-12-04 11:49:28 -050094#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
95#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
Douglas Gilbert481b5e52017-12-23 12:48:14 -050096#define WRITE_ERROR_ASC 0xc
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -050098/* Additional Sense Code Qualifier (ASCQ) */
99#define ACK_NAK_TO 0x3
100
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101/* Default values for driver parameters */
102#define DEF_NUM_HOST 1
103#define DEF_NUM_TGTS 1
104#define DEF_MAX_LUNS 1
105/* With these defaults, this driver will make 1 host with 1 target
106 * (id 0) containing 1 logical unit (lun 0). That is 1 device.
107 */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500108#define DEF_ATO 1
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500109#define DEF_CDB_LEN 10
Douglas Gilbertc2206092016-04-25 12:16:31 -0400110#define DEF_JDELAY 1 /* if > 0 unit is a jiffy */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111#define DEF_DEV_SIZE_MB 8
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500112#define DEF_DIF 0
113#define DEF_DIX 0
114#define DEF_D_SENSE 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115#define DEF_EVERY_NTH 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500116#define DEF_FAKE_RW 0
117#define DEF_GUARD 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400118#define DEF_HOST_LOCK 0
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500119#define DEF_LBPU 0
120#define DEF_LBPWS 0
121#define DEF_LBPWS10 0
Eric Sandeenbe1dd782012-03-08 00:03:59 -0600122#define DEF_LBPRZ 1
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500123#define DEF_LOWEST_ALIGNED 0
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400124#define DEF_NDELAY 0 /* if > 0 unit is a nanosecond */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500125#define DEF_NO_LUN_0 0
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126#define DEF_NUM_PARTS 0
127#define DEF_OPTS 0
Martin K. Petersen32c58442015-12-16 17:53:51 -0500128#define DEF_OPT_BLKS 1024
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500129#define DEF_PHYSBLK_EXP 0
Lukas Herbolt86e68282017-01-26 10:00:37 +0100130#define DEF_OPT_XFERLEN_EXP 0
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400131#define DEF_PTYPE TYPE_DISK
Martin Pittd9867882012-09-06 12:04:33 +0200132#define DEF_REMOVABLE false
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400133#define DEF_SCSI_LEVEL 7 /* INQUIRY, byte2 [6->SPC-4; 7->SPC-5] */
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500134#define DEF_SECTOR_SIZE 512
135#define DEF_UNMAP_ALIGNMENT 0
136#define DEF_UNMAP_GRANULARITY 1
Martin K. Petersen60147592010-08-19 11:49:00 -0400137#define DEF_UNMAP_MAX_BLOCKS 0xFFFFFFFF
138#define DEF_UNMAP_MAX_DESC 256
Martin K. Petersen5b94e232011-03-08 02:08:11 -0500139#define DEF_VIRTUAL_GB 0
140#define DEF_VPD_USE_HOSTNO 1
141#define DEF_WRITESAME_LENGTH 0xFFFF
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500142#define DEF_STRICT 0
Douglas Gilbertc4837392016-05-06 00:40:26 -0400143#define DEF_STATISTICS false
144#define DEF_SUBMIT_QUEUES 1
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400145#define DEF_UUID_CTL 0
Douglas Gilbertc2206092016-04-25 12:16:31 -0400146#define JDELAY_OVERRIDDEN -9999
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400148#define SDEBUG_LUN_0_VAL 0
149
Douglas Gilbert773642d2016-04-25 12:16:28 -0400150/* bit mask values for sdebug_opts */
151#define SDEBUG_OPT_NOISE 1
152#define SDEBUG_OPT_MEDIUM_ERR 2
153#define SDEBUG_OPT_TIMEOUT 4
154#define SDEBUG_OPT_RECOVERED_ERR 8
155#define SDEBUG_OPT_TRANSPORT_ERR 16
156#define SDEBUG_OPT_DIF_ERR 32
157#define SDEBUG_OPT_DIX_ERR 64
158#define SDEBUG_OPT_MAC_TIMEOUT 128
159#define SDEBUG_OPT_SHORT_TRANSFER 0x100
160#define SDEBUG_OPT_Q_NOISE 0x200
161#define SDEBUG_OPT_ALL_TSF 0x400
162#define SDEBUG_OPT_RARE_TSF 0x800
163#define SDEBUG_OPT_N_WCE 0x1000
164#define SDEBUG_OPT_RESET_NOISE 0x2000
165#define SDEBUG_OPT_NO_CDB_NOISE 0x4000
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800166#define SDEBUG_OPT_HOST_BUSY 0x8000
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400167#define SDEBUG_OPT_CMD_ABORT 0x10000
Douglas Gilbert773642d2016-04-25 12:16:28 -0400168#define SDEBUG_OPT_ALL_NOISE (SDEBUG_OPT_NOISE | SDEBUG_OPT_Q_NOISE | \
169 SDEBUG_OPT_RESET_NOISE)
170#define SDEBUG_OPT_ALL_INJECTING (SDEBUG_OPT_RECOVERED_ERR | \
171 SDEBUG_OPT_TRANSPORT_ERR | \
172 SDEBUG_OPT_DIF_ERR | SDEBUG_OPT_DIX_ERR | \
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800173 SDEBUG_OPT_SHORT_TRANSFER | \
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400174 SDEBUG_OPT_HOST_BUSY | \
175 SDEBUG_OPT_CMD_ABORT)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176/* When "every_nth" > 0 then modulo "every_nth" commands:
Douglas Gilbertfd321192016-04-25 12:16:33 -0400177 * - a missing response is simulated if SDEBUG_OPT_TIMEOUT is set
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 * - a RECOVERED_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400179 * commands if SDEBUG_OPT_RECOVERED_ERR is set.
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -0500180 * - a TRANSPORT_ERROR is simulated on successful read and write
Douglas Gilbert773642d2016-04-25 12:16:28 -0400181 * commands if SDEBUG_OPT_TRANSPORT_ERR is set.
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400182 * - similarly for DIF_ERR, DIX_ERR, SHORT_TRANSFER, HOST_BUSY and
183 * CMD_ABORT
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 *
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400185 * When "every_nth" < 0 then after "- every_nth" commands the selected
186 * error will be injected. The error will be injected on every subsequent
187 * command until some other action occurs; for example, the user writing
188 * a new value (other than -1 or 1) to every_nth:
189 * echo 0 > /sys/bus/pseudo/drivers/scsi_debug/every_nth
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 */
191
Douglas Gilbertfd321192016-04-25 12:16:33 -0400192/* As indicated in SAM-5 and SPC-4 Unit Attentions (UAs) are returned in
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400193 * priority order. In the subset implemented here lower numbers have higher
194 * priority. The UA numbers should be a sequence starting from 0 with
195 * SDEBUG_NUM_UAS being 1 higher than the highest numbered UA. */
196#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
197#define SDEBUG_UA_BUS_RESET 1
198#define SDEBUG_UA_MODE_CHANGED 2
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500199#define SDEBUG_UA_CAPACITY_CHANGED 3
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500200#define SDEBUG_UA_LUNS_CHANGED 4
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500201#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
202#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
203#define SDEBUG_NUM_UAS 7
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400204
Douglas Gilbert773642d2016-04-25 12:16:28 -0400205/* when 1==SDEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 * sector on read commands: */
207#define OPT_MEDIUM_ERR_ADDR 0x1234 /* that's sector 4660 in decimal */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -0500208#define OPT_MEDIUM_ERR_NUM 10 /* number of consecutive medium errs */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
211 * or "peripheral device" addressing (value 0) */
212#define SAM2_LUN_ADDRESS_METHOD 0
213
Douglas Gilbertc4837392016-05-06 00:40:26 -0400214/* SDEBUG_CANQUEUE is the maximum number of commands that can be queued
215 * (for response) per submit queue at one time. Can be reduced by max_queue
216 * option. Command responses are not queued when jdelay=0 and ndelay=0. The
217 * per-device DEF_CMD_PER_LUN can be changed via sysfs:
218 * /sys/class/scsi_device/<h:c:t:l>/device/queue_depth
219 * but cannot exceed SDEBUG_CANQUEUE .
220 */
221#define SDEBUG_CANQUEUE_WORDS 3 /* a WORD is bits in a long */
222#define SDEBUG_CANQUEUE (SDEBUG_CANQUEUE_WORDS * BITS_PER_LONG)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400223#define DEF_CMD_PER_LUN 255
224
Douglas Gilbertfd321192016-04-25 12:16:33 -0400225#define F_D_IN 1
226#define F_D_OUT 2
227#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
228#define F_D_UNKN 8
229#define F_RL_WLUN_OK 0x10
230#define F_SKIP_UA 0x20
231#define F_DELAY_OVERR 0x40
232#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
233#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
234#define F_INV_OP 0x200
235#define F_FAKE_RW 0x400
236#define F_M_ACCESS 0x800 /* media access */
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400237#define F_SSU_DELAY 0x1000
238#define F_SYNC_DELAY 0x2000
Douglas Gilbertfd321192016-04-25 12:16:33 -0400239
240#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500241#define FF_MEDIA_IO (F_M_ACCESS | F_FAKE_RW)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400242#define FF_SA (F_SA_HIGH | F_SA_LOW)
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400243#define F_LONG_DELAY (F_SSU_DELAY | F_SYNC_DELAY)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400244
245#define SDEBUG_MAX_PARTS 4
246
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400247#define SDEBUG_MAX_CMD_LEN 32
Douglas Gilbertfd321192016-04-25 12:16:33 -0400248
249
250struct sdebug_dev_info {
251 struct list_head dev_list;
252 unsigned int channel;
253 unsigned int target;
254 u64 lun;
Christoph Hellwigbf476432017-05-17 09:55:26 +0200255 uuid_t lu_name;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400256 struct sdebug_host_info *sdbg_host;
257 unsigned long uas_bm[1];
258 atomic_t num_in_q;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400259 atomic_t stopped;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400260 bool used;
261};
262
263struct sdebug_host_info {
264 struct list_head host_list;
265 struct Scsi_Host *shost;
266 struct device dev;
267 struct list_head dev_info_list;
268};
269
270#define to_sdebug_host(d) \
271 container_of(d, struct sdebug_host_info, dev)
272
Douglas Gilbert10bde982018-01-10 16:57:31 -0500273enum sdeb_defer_type {SDEB_DEFER_NONE = 0, SDEB_DEFER_HRT = 1,
274 SDEB_DEFER_WQ = 2};
275
Douglas Gilbertfd321192016-04-25 12:16:33 -0400276struct sdebug_defer {
277 struct hrtimer hrt;
278 struct execute_work ew;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400279 int sqa_idx; /* index of sdebug_queue array */
280 int qc_idx; /* index of sdebug_queued_cmd array within sqa_idx */
281 int issuing_cpu;
Douglas Gilbert10bde982018-01-10 16:57:31 -0500282 bool init_hrt;
283 bool init_wq;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400284 bool aborted; /* true when blk_abort_request() already called */
Douglas Gilbert10bde982018-01-10 16:57:31 -0500285 enum sdeb_defer_type defer_t;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400286};
287
288struct sdebug_queued_cmd {
Douglas Gilbertc4837392016-05-06 00:40:26 -0400289 /* corresponding bit set in in_use_bm[] in owning struct sdebug_queue
290 * instance indicates this slot is in use.
291 */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400292 struct sdebug_defer *sd_dp;
293 struct scsi_cmnd *a_cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400294 unsigned int inj_recovered:1;
295 unsigned int inj_transport:1;
296 unsigned int inj_dif:1;
297 unsigned int inj_dix:1;
298 unsigned int inj_short:1;
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -0800299 unsigned int inj_host_busy:1;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -0400300 unsigned int inj_cmd_abort:1;
Douglas Gilbertfd321192016-04-25 12:16:33 -0400301};
302
Douglas Gilbertc4837392016-05-06 00:40:26 -0400303struct sdebug_queue {
304 struct sdebug_queued_cmd qc_arr[SDEBUG_CANQUEUE];
305 unsigned long in_use_bm[SDEBUG_CANQUEUE_WORDS];
306 spinlock_t qc_lock;
307 atomic_t blocked; /* to temporarily stop more being queued */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400308};
309
Douglas Gilbertc4837392016-05-06 00:40:26 -0400310static atomic_t sdebug_cmnd_count; /* number of incoming commands */
311static atomic_t sdebug_completions; /* count of deferred completions */
312static atomic_t sdebug_miss_cpus; /* submission + completion cpus differ */
313static atomic_t sdebug_a_tsf; /* 'almost task set full' counter */
314
Douglas Gilbertfd321192016-04-25 12:16:33 -0400315struct opcode_info_t {
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400316 u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff */
317 /* for terminating element */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400318 u8 opcode; /* if num_attached > 0, preferred */
319 u16 sa; /* service action */
320 u32 flags; /* OR-ed set of SDEB_F_* */
321 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
322 const struct opcode_info_t *arrp; /* num_attached elements or NULL */
Douglas Gilbert9a051012017-12-23 12:48:10 -0500323 u8 len_mask[16]; /* len_mask[0]-->cdb_len, then mask for cdb */
324 /* 1 to min(cdb_len, 15); ignore cdb[15...] */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400325};
326
327/* SCSI opcodes (first byte of cdb) of interest mapped onto these indexes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500328enum sdeb_opcode_index {
329 SDEB_I_INVALID_OPCODE = 0,
330 SDEB_I_INQUIRY = 1,
331 SDEB_I_REPORT_LUNS = 2,
332 SDEB_I_REQUEST_SENSE = 3,
333 SDEB_I_TEST_UNIT_READY = 4,
334 SDEB_I_MODE_SENSE = 5, /* 6, 10 */
335 SDEB_I_MODE_SELECT = 6, /* 6, 10 */
336 SDEB_I_LOG_SENSE = 7,
337 SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
338 SDEB_I_READ = 9, /* 6, 10, 12, 16 */
339 SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
340 SDEB_I_START_STOP = 11,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500341 SDEB_I_SERV_ACT_IN_16 = 12, /* add ...SERV_ACT_IN_12 if needed */
342 SDEB_I_SERV_ACT_OUT_16 = 13, /* add ...SERV_ACT_OUT_12 if needed */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500343 SDEB_I_MAINT_IN = 14,
344 SDEB_I_MAINT_OUT = 15,
345 SDEB_I_VERIFY = 16, /* 10 only */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500346 SDEB_I_VARIABLE_LEN = 17, /* READ(32), WRITE(32), WR_SCAT(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500347 SDEB_I_RESERVE = 18, /* 6, 10 */
348 SDEB_I_RELEASE = 19, /* 6, 10 */
349 SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
350 SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
351 SDEB_I_ATA_PT = 22, /* 12, 16 */
352 SDEB_I_SEND_DIAG = 23,
353 SDEB_I_UNMAP = 24,
Bart Van Asschec2085562019-02-08 13:21:27 -0800354 SDEB_I_WRITE_BUFFER = 25,
355 SDEB_I_WRITE_SAME = 26, /* 10, 16 */
356 SDEB_I_SYNC_CACHE = 27, /* 10, 16 */
357 SDEB_I_COMP_WRITE = 28,
358 SDEB_I_LAST_ELEMENT = 29, /* keep this last (previous + 1) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500359};
360
Douglas Gilbertc4837392016-05-06 00:40:26 -0400361
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500362static const unsigned char opcode_ind_arr[256] = {
363/* 0x0; 0x0->0x1f: 6 byte cdbs */
364 SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
365 0, 0, 0, 0,
366 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
367 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
368 SDEB_I_RELEASE,
369 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
370 SDEB_I_ALLOW_REMOVAL, 0,
371/* 0x20; 0x20->0x3f: 10 byte cdbs */
372 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
373 SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
374 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
375 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
376/* 0x40; 0x40->0x5f: 10 byte cdbs */
377 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
378 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
Bart Van Asschec2085562019-02-08 13:21:27 -0800379 0, 0, 0, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500380 SDEB_I_RELEASE,
381 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
Douglas Gilbertfd321192016-04-25 12:16:33 -0400382/* 0x60; 0x60->0x7d are reserved, 0x7e is "extended cdb" */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
385 0, SDEB_I_VARIABLE_LEN,
386/* 0x80; 0x80->0x9f: 16 byte cdbs */
387 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
388 SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500389 0, SDEB_I_SYNC_CACHE, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500390 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 -0500391/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
392 SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
393 SDEB_I_MAINT_OUT, 0, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500394 SDEB_I_READ, 0 /* SDEB_I_SERV_ACT_OUT_12 */, SDEB_I_WRITE,
395 0 /* SDEB_I_SERV_ACT_IN_12 */, 0, 0, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500396 0, 0, 0, 0, 0, 0, 0, 0,
397 0, 0, 0, 0, 0, 0, 0, 0,
398/* 0xc0; 0xc0->0xff: vendor specific */
399 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
400 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
401 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
402 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
403};
404
Douglas Gilbert80c49562018-02-09 21:36:39 -0500405/*
406 * The following "response" functions return the SCSI mid-level's 4 byte
407 * tuple-in-an-int. To handle commands with an IMMED bit, for a faster
408 * command completion, they can mask their return value with
409 * SDEG_RES_IMMED_MASK .
410 */
411#define SDEG_RES_IMMED_MASK 0x40000000
412
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500413static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
414static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
415static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
416static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
417static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
418static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
419static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
420static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
421static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500422static int resp_write_scat(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500423static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
424static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
425static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
426static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
427static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500428static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
429static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500430static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
431static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500432static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500433static int resp_write_buffer(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbert80c49562018-02-09 21:36:39 -0500434static int resp_sync_cache(struct scsi_cmnd *, struct sdebug_dev_info *);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500435
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500436/*
437 * The following are overflow arrays for cdbs that "hit" the same index in
438 * the opcode_info_arr array. The most time sensitive (or commonly used) cdb
439 * should be placed in opcode_info_arr[], the others should be placed here.
440 */
441static const struct opcode_info_t msense_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500442 {0, 0x1a, 0, F_D_IN, NULL, NULL,
443 {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
444};
445
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500446static const struct opcode_info_t mselect_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500447 {0, 0x15, 0, F_D_OUT, NULL, NULL,
448 {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
449};
450
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500451static const struct opcode_info_t read_iarr[] = {
452 {0, 0x28, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(10) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500453 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500454 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500455 {0, 0x8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL, /* READ(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500456 {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500457 {0, 0xa8, 0, F_D_IN | FF_MEDIA_IO, resp_read_dt0, NULL,/* READ(12) */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500458 {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500459 0xc7, 0, 0, 0, 0} },
460};
461
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500462static const struct opcode_info_t write_iarr[] = {
463 {0, 0x2a, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(10) */
464 NULL, {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7,
465 0, 0, 0, 0, 0, 0} },
466 {0, 0xa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(6) */
467 NULL, {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0,
468 0, 0, 0} },
469 {0, 0xaa, 0, F_D_OUT | FF_MEDIA_IO, resp_write_dt0, /* WRITE(12) */
470 NULL, {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
471 0xbf, 0xc7, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500472};
473
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500474static const struct opcode_info_t sa_in_16_iarr[] = {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500475 {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
476 {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500477 0xff, 0xff, 0xff, 0, 0xc7} }, /* GET LBA STATUS(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500478};
479
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500480static const struct opcode_info_t vl_iarr[] = { /* VARIABLE LENGTH */
481 {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_dt0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500482 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0xb, 0xfa,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500483 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500484 {0, 0x7f, 0x11, F_SA_HIGH | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
485 NULL, {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x11, 0xf8,
486 0, 0xff, 0xff, 0x0, 0x0} }, /* WRITE SCATTERED(32) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500487};
488
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500489static const struct opcode_info_t maint_in_iarr[] = { /* MAINT IN */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500490 {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500491 {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500492 0xc7, 0, 0, 0, 0} }, /* REPORT SUPPORTED OPERATION CODES */
Douglas Gilbert38d5c832014-11-24 21:27:12 -0500493 {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500494 {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500495 0, 0} }, /* REPORTED SUPPORTED TASK MANAGEMENT FUNCTIONS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500496};
497
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500498static const struct opcode_info_t write_same_iarr[] = {
499 {0, 0x93, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, resp_write_same_16, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500500 {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500501 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* WRITE SAME(16) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500502};
503
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500504static const struct opcode_info_t reserve_iarr[] = {
505 {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500506 {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
507};
508
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500509static const struct opcode_info_t release_iarr[] = {
510 {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500511 {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
512};
513
Douglas Gilbert80c49562018-02-09 21:36:39 -0500514static const struct opcode_info_t sync_cache_iarr[] = {
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400515 {0, 0x91, 0, F_SYNC_DELAY | F_M_ACCESS, resp_sync_cache, NULL,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500516 {16, 0x6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
517 0xff, 0xff, 0xff, 0xff, 0x3f, 0xc7} }, /* SYNC_CACHE (16) */
518};
519
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500520
521/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
522 * plus the terminating elements for logic that scans this table such as
523 * REPORT SUPPORTED OPERATION CODES. */
524static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
525/* 0 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500526 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* unknown opcodes */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500527 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500528 {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL, /* INQUIRY */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500529 {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
530 {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
531 {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500532 0, 0} }, /* REPORT LUNS */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500533 {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
534 {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
535 {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
536 {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500537/* 5 */
538 {ARRAY_SIZE(msense_iarr), 0x5a, 0, F_D_IN, /* MODE SENSE(10) */
539 resp_mode_sense, msense_iarr, {10, 0xf8, 0xff, 0xff, 0, 0, 0,
540 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
541 {ARRAY_SIZE(mselect_iarr), 0x55, 0, F_D_OUT, /* MODE SELECT(10) */
542 resp_mode_select, mselect_iarr, {10, 0xf1, 0, 0, 0, 0, 0, 0xff,
543 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
544 {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL, /* LOG SENSE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500545 {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
546 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500547 {0, 0x25, 0, F_D_IN, resp_readcap, NULL, /* READ CAPACITY(10) */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500548 {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
549 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500550 {ARRAY_SIZE(read_iarr), 0x88, 0, F_D_IN | FF_MEDIA_IO, /* READ(16) */
551 resp_read_dt0, read_iarr, {16, 0xfe, 0xff, 0xff, 0xff, 0xff,
552 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500553/* 10 */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500554 {ARRAY_SIZE(write_iarr), 0x8a, 0, F_D_OUT | FF_MEDIA_IO,
555 resp_write_dt0, write_iarr, /* WRITE(16) */
556 {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500557 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400558 {0, 0x1b, 0, F_SSU_DELAY, resp_start_stop, NULL,/* START STOP UNIT */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500559 {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500560 {ARRAY_SIZE(sa_in_16_iarr), 0x9e, 0x10, F_SA_LOW | F_D_IN,
561 resp_readcap16, sa_in_16_iarr, /* SA_IN(16), READ CAPACITY(16) */
562 {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
563 0xff, 0xff, 0xff, 0xff, 0x1, 0xc7} },
Douglas Gilbert481b5e52017-12-23 12:48:14 -0500564 {0, 0x9f, 0x12, F_SA_LOW | F_D_OUT | FF_MEDIA_IO, resp_write_scat,
565 NULL, {16, 0x12, 0xf9, 0x0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff,
566 0xff, 0xff, 0xff, 0xff, 0xc7} }, /* SA_OUT(16), WRITE SCAT(16) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500567 {ARRAY_SIZE(maint_in_iarr), 0xa3, 0xa, F_SA_LOW | F_D_IN,
568 resp_report_tgtpgs, /* MAINT IN, REPORT TARGET PORT GROUPS */
569 maint_in_iarr, {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff,
570 0xff, 0, 0xc7, 0, 0, 0, 0} },
571/* 15 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500572 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
573 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500574 {0, 0x2f, 0, F_D_OUT_MAYBE | FF_MEDIA_IO, NULL, NULL, /* VERIFY(10) */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500575 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7,
576 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500577 {ARRAY_SIZE(vl_iarr), 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_MEDIA_IO,
578 resp_read_dt0, vl_iarr, /* VARIABLE LENGTH, READ(32) */
579 {32, 0xc7, 0, 0, 0, 0, 0x3f, 0x18, 0x0, 0x9, 0xfe, 0, 0xff, 0xff,
580 0xff, 0xff} },
581 {ARRAY_SIZE(reserve_iarr), 0x56, 0, F_D_OUT,
582 NULL, reserve_iarr, /* RESERVE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500583 {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
584 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500585 {ARRAY_SIZE(release_iarr), 0x57, 0, F_D_OUT,
586 NULL, release_iarr, /* RELEASE(10) <no response function> */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500587 {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
588 0} },
589/* 20 */
Douglas Gilbertf7f9f262015-11-22 12:11:28 -0500590 {0, 0x1e, 0, 0, NULL, NULL, /* ALLOW REMOVAL */
591 {6, 0, 0, 0, 0x3, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500592 {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
593 {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
594 {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
595 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
596 {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
597 {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500598 {0, 0x42, 0, F_D_OUT | FF_MEDIA_IO, resp_unmap, NULL, /* UNMAP */
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500599 {10, 0x1, 0, 0, 0, 0, 0x3f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500600/* 25 */
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500601 {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
602 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
603 0, 0, 0, 0} }, /* WRITE_BUFFER */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500604 {ARRAY_SIZE(write_same_iarr), 0x41, 0, F_D_OUT_MAYBE | FF_MEDIA_IO,
605 resp_write_same_10, write_same_iarr, /* WRITE SAME(10) */
606 {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0,
607 0, 0, 0, 0, 0} },
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400608 {ARRAY_SIZE(sync_cache_iarr), 0x35, 0, F_SYNC_DELAY | F_M_ACCESS,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500609 resp_sync_cache, sync_cache_iarr,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500610 {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3f, 0xff, 0xff, 0xc7, 0, 0,
Douglas Gilbert80c49562018-02-09 21:36:39 -0500611 0, 0, 0, 0} }, /* SYNC_CACHE (10) */
Douglas Gilbert46f64e72017-12-23 12:48:13 -0500612 {0, 0x89, 0, F_D_OUT | FF_MEDIA_IO, resp_comp_write, NULL,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500613 {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
Douglas Gilbertb7e24582017-12-23 12:48:11 -0500614 0, 0xff, 0x3f, 0xc7} }, /* COMPARE AND WRITE */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500615
Bart Van Asschec2085562019-02-08 13:21:27 -0800616/* 29 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -0500617 {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
618 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
619};
620
Douglas Gilbert773642d2016-04-25 12:16:28 -0400621static int sdebug_add_host = DEF_NUM_HOST;
622static int sdebug_ato = DEF_ATO;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500623static int sdebug_cdb_len = DEF_CDB_LEN;
Douglas Gilbertc2206092016-04-25 12:16:31 -0400624static int sdebug_jdelay = DEF_JDELAY; /* if > 0 then unit is jiffies */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400625static int sdebug_dev_size_mb = DEF_DEV_SIZE_MB;
626static int sdebug_dif = DEF_DIF;
627static int sdebug_dix = DEF_DIX;
628static int sdebug_dsense = DEF_D_SENSE;
629static int sdebug_every_nth = DEF_EVERY_NTH;
630static int sdebug_fake_rw = DEF_FAKE_RW;
631static unsigned int sdebug_guard = DEF_GUARD;
632static int sdebug_lowest_aligned = DEF_LOWEST_ALIGNED;
633static int sdebug_max_luns = DEF_MAX_LUNS;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400634static int sdebug_max_queue = SDEBUG_CANQUEUE; /* per submit queue */
Laurence Obermand9da8912018-02-03 13:38:35 -0500635static unsigned int sdebug_medium_error_start = OPT_MEDIUM_ERR_ADDR;
636static int sdebug_medium_error_count = OPT_MEDIUM_ERR_NUM;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400637static atomic_t retired_max_queue; /* if > 0 then was prior max_queue */
Douglas Gilbertc2206092016-04-25 12:16:31 -0400638static int sdebug_ndelay = DEF_NDELAY; /* if > 0 then unit is nanoseconds */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400639static int sdebug_no_lun_0 = DEF_NO_LUN_0;
640static int sdebug_no_uld;
641static int sdebug_num_parts = DEF_NUM_PARTS;
642static int sdebug_num_tgts = DEF_NUM_TGTS; /* targets per host */
643static int sdebug_opt_blks = DEF_OPT_BLKS;
644static int sdebug_opts = DEF_OPTS;
645static int sdebug_physblk_exp = DEF_PHYSBLK_EXP;
Lukas Herbolt86e68282017-01-26 10:00:37 +0100646static int sdebug_opt_xferlen_exp = DEF_OPT_XFERLEN_EXP;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400647static int sdebug_ptype = DEF_PTYPE; /* SCSI peripheral device type */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400648static int sdebug_scsi_level = DEF_SCSI_LEVEL;
649static int sdebug_sector_size = DEF_SECTOR_SIZE;
650static int sdebug_virtual_gb = DEF_VIRTUAL_GB;
651static int sdebug_vpd_use_hostno = DEF_VPD_USE_HOSTNO;
652static unsigned int sdebug_lbpu = DEF_LBPU;
653static unsigned int sdebug_lbpws = DEF_LBPWS;
654static unsigned int sdebug_lbpws10 = DEF_LBPWS10;
655static unsigned int sdebug_lbprz = DEF_LBPRZ;
656static unsigned int sdebug_unmap_alignment = DEF_UNMAP_ALIGNMENT;
657static unsigned int sdebug_unmap_granularity = DEF_UNMAP_GRANULARITY;
658static unsigned int sdebug_unmap_max_blocks = DEF_UNMAP_MAX_BLOCKS;
659static unsigned int sdebug_unmap_max_desc = DEF_UNMAP_MAX_DESC;
660static unsigned int sdebug_write_same_length = DEF_WRITESAME_LENGTH;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -0400661static int sdebug_uuid_ctl = DEF_UUID_CTL;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400662static bool sdebug_removable = DEF_REMOVABLE;
663static bool sdebug_clustering;
664static bool sdebug_host_lock = DEF_HOST_LOCK;
665static bool sdebug_strict = DEF_STRICT;
Douglas Gilbert817fd662014-11-24 20:18:02 -0500666static bool sdebug_any_injecting_opt;
Douglas Gilbert773642d2016-04-25 12:16:28 -0400667static bool sdebug_verbose;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400668static bool have_dif_prot;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -0400669static bool write_since_sync;
Douglas Gilbertc4837392016-05-06 00:40:26 -0400670static bool sdebug_statistics = DEF_STATISTICS;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700671
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400672static unsigned int sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673static sector_t sdebug_capacity; /* in sectors */
674
675/* old BIOS stuff, kernel may get rid of them but some mode sense pages
676 may still need them */
677static int sdebug_heads; /* heads per disk */
678static int sdebug_cylinders_per; /* cylinders per surface */
679static int sdebug_sectors_per; /* sectors per cylinder */
680
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681static LIST_HEAD(sdebug_host_list);
682static DEFINE_SPINLOCK(sdebug_host_list_lock);
683
Douglas Gilbertfd321192016-04-25 12:16:33 -0400684static unsigned char *fake_storep; /* ramdisk storage */
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200685static struct t10_pi_tuple *dif_storep; /* protection info */
Martin K. Petersen44d92692009-10-15 14:45:27 -0400686static void *map_storep; /* provisioning map */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687
Martin K. Petersen44d92692009-10-15 14:45:27 -0400688static unsigned long map_size;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400689static int num_aborts;
690static int num_dev_resets;
691static int num_target_resets;
692static int num_bus_resets;
693static int num_host_resets;
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500694static int dix_writes;
695static int dix_reads;
696static int dif_errors;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Douglas Gilbertc4837392016-05-06 00:40:26 -0400698static int submit_queues = DEF_SUBMIT_QUEUES; /* > 1 for multi-queue (mq) */
699static struct sdebug_queue *sdebug_q_arr; /* ptr to array of submit queues */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400700
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701static DEFINE_RWLOCK(atomic_rw);
702
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400703static char sdebug_proc_name[] = MY_NAME;
704static const char *my_name = MY_NAME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706static struct bus_type pseudo_lld_bus;
707
708static struct device_driver sdebug_driverfs_driver = {
709 .name = sdebug_proc_name,
710 .bus = &pseudo_lld_bus,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711};
712
713static const int check_condition_result =
714 (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
715
Martin K. Petersenc6a44282009-01-04 03:08:19 -0500716static const int illegal_condition_result =
717 (DRIVER_SENSE << 24) | (DID_ABORT << 16) | SAM_STAT_CHECK_CONDITION;
718
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400719static const int device_qfull_result =
720 (DID_OK << 16) | (COMMAND_COMPLETE << 8) | SAM_STAT_TASK_SET_FULL;
721
Douglas Gilbertfd321192016-04-25 12:16:33 -0400722
Douglas Gilbert760f3b02016-05-06 00:40:27 -0400723/* Only do the extra work involved in logical block provisioning if one or
724 * more of the lbpu, lbpws or lbpws10 parameters are given and we are doing
725 * real reads and writes (i.e. not skipping them for speed).
726 */
727static inline bool scsi_debug_lbp(void)
Douglas Gilbertfd321192016-04-25 12:16:33 -0400728{
729 return 0 == sdebug_fake_rw &&
730 (sdebug_lbpu || sdebug_lbpws || sdebug_lbpws10);
731}
Douglas Gilbertc65b1442006-06-06 00:11:24 -0400732
Akinobu Mita14faa942013-09-18 21:27:24 +0900733static void *fake_store(unsigned long long lba)
734{
735 lba = do_div(lba, sdebug_store_sectors);
736
Douglas Gilbert773642d2016-04-25 12:16:28 -0400737 return fake_storep + lba * sdebug_sector_size;
Akinobu Mita14faa942013-09-18 21:27:24 +0900738}
739
Christoph Hellwig6ebf1052016-09-11 19:35:39 +0200740static struct t10_pi_tuple *dif_store(sector_t sector)
Akinobu Mita14faa942013-09-18 21:27:24 +0900741{
Arnd Bergmann49413112015-11-20 17:38:28 +0100742 sector = sector_div(sector, sdebug_store_sectors);
Akinobu Mita14faa942013-09-18 21:27:24 +0900743
744 return dif_storep + sector;
745}
746
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900747static void sdebug_max_tgts_luns(void)
748{
749 struct sdebug_host_info *sdbg_host;
750 struct Scsi_Host *hpnt;
751
752 spin_lock(&sdebug_host_list_lock);
753 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
754 hpnt = sdbg_host->shost;
755 if ((hpnt->this_id >= 0) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -0400756 (sdebug_num_tgts > hpnt->this_id))
757 hpnt->max_id = sdebug_num_tgts + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900758 else
Douglas Gilbert773642d2016-04-25 12:16:28 -0400759 hpnt->max_id = sdebug_num_tgts;
760 /* sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +0300761 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900762 }
763 spin_unlock(&sdebug_host_list_lock);
764}
765
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500766enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
767
768/* Set in_bit to -1 to indicate no bit position of invalid field */
Douglas Gilbertfd321192016-04-25 12:16:33 -0400769static void mk_sense_invalid_fld(struct scsi_cmnd *scp,
770 enum sdeb_cmd_data c_d,
771 int in_byte, int in_bit)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500772{
773 unsigned char *sbuff;
774 u8 sks[4];
775 int sl, asc;
776
777 sbuff = scp->sense_buffer;
778 if (!sbuff) {
779 sdev_printk(KERN_ERR, scp->device,
780 "%s: sense_buffer is NULL\n", __func__);
781 return;
782 }
783 asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
784 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400785 scsi_build_sense_buffer(sdebug_dsense, sbuff, ILLEGAL_REQUEST, asc, 0);
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500786 memset(sks, 0, sizeof(sks));
787 sks[0] = 0x80;
788 if (c_d)
789 sks[0] |= 0x40;
790 if (in_bit >= 0) {
791 sks[0] |= 0x8;
792 sks[0] |= 0x7 & in_bit;
793 }
794 put_unaligned_be16(in_byte, sks + 1);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400795 if (sdebug_dsense) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500796 sl = sbuff[7] + 8;
797 sbuff[7] = sl;
798 sbuff[sl] = 0x2;
799 sbuff[sl + 1] = 0x6;
800 memcpy(sbuff + sl + 4, sks, 3);
801 } else
802 memcpy(sbuff + 15, sks, 3);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400803 if (sdebug_verbose)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500804 sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
805 "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
806 my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
807}
808
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400809static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900810{
811 unsigned char *sbuff;
812
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400813 sbuff = scp->sense_buffer;
814 if (!sbuff) {
815 sdev_printk(KERN_ERR, scp->device,
816 "%s: sense_buffer is NULL\n", __func__);
817 return;
818 }
819 memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900820
Douglas Gilbert773642d2016-04-25 12:16:28 -0400821 scsi_build_sense_buffer(sdebug_dsense, sbuff, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900822
Douglas Gilbert773642d2016-04-25 12:16:28 -0400823 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400824 sdev_printk(KERN_INFO, scp->device,
825 "%s: [sense_key,asc,ascq]: [0x%x,0x%x,0x%x]\n",
826 my_name, key, asc, asq);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +0900827}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
Douglas Gilbertfd321192016-04-25 12:16:33 -0400829static void mk_sense_invalid_opcode(struct scsi_cmnd *scp)
Douglas Gilbert22017ed2014-11-24 23:04:47 -0500830{
831 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
832}
833
Nathan Chancellor6f4e6262019-02-07 09:07:20 -0700834static int scsi_debug_ioctl(struct scsi_device *dev, unsigned int cmd,
835 void __user *arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
Douglas Gilbert773642d2016-04-25 12:16:28 -0400837 if (sdebug_verbose) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400838 if (0x1261 == cmd)
839 sdev_printk(KERN_INFO, dev,
840 "%s: BLKFLSBUF [0x1261]\n", __func__);
841 else if (0x5331 == cmd)
842 sdev_printk(KERN_INFO, dev,
843 "%s: CDROM_GET_CAPABILITY [0x5331]\n",
844 __func__);
845 else
846 sdev_printk(KERN_INFO, dev, "%s: cmd=0x%x\n",
847 __func__, cmd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 }
849 return -EINVAL;
850 /* return -ENOTTY; // correct return but upsets fdisk */
851}
852
Douglas Gilbert9b760fd2017-12-05 00:05:49 -0500853static void config_cdb_len(struct scsi_device *sdev)
854{
855 switch (sdebug_cdb_len) {
856 case 6: /* suggest 6 byte READ, WRITE and MODE SENSE/SELECT */
857 sdev->use_10_for_rw = false;
858 sdev->use_16_for_rw = false;
859 sdev->use_10_for_ms = false;
860 break;
861 case 10: /* suggest 10 byte RWs and 6 byte MODE SENSE/SELECT */
862 sdev->use_10_for_rw = true;
863 sdev->use_16_for_rw = false;
864 sdev->use_10_for_ms = false;
865 break;
866 case 12: /* suggest 10 byte RWs and 10 byte MODE SENSE/SELECT */
867 sdev->use_10_for_rw = true;
868 sdev->use_16_for_rw = false;
869 sdev->use_10_for_ms = true;
870 break;
871 case 16:
872 sdev->use_10_for_rw = false;
873 sdev->use_16_for_rw = true;
874 sdev->use_10_for_ms = true;
875 break;
876 case 32: /* No knobs to suggest this so same as 16 for now */
877 sdev->use_10_for_rw = false;
878 sdev->use_16_for_rw = true;
879 sdev->use_10_for_ms = true;
880 break;
881 default:
882 pr_warn("unexpected cdb_len=%d, force to 10\n",
883 sdebug_cdb_len);
884 sdev->use_10_for_rw = true;
885 sdev->use_16_for_rw = false;
886 sdev->use_10_for_ms = false;
887 sdebug_cdb_len = 10;
888 break;
889 }
890}
891
892static void all_config_cdb_len(void)
893{
894 struct sdebug_host_info *sdbg_host;
895 struct Scsi_Host *shost;
896 struct scsi_device *sdev;
897
898 spin_lock(&sdebug_host_list_lock);
899 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
900 shost = sdbg_host->shost;
901 shost_for_each_device(sdev, shost) {
902 config_cdb_len(sdev);
903 }
904 }
905 spin_unlock(&sdebug_host_list_lock);
906}
907
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500908static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
909{
910 struct sdebug_host_info *sdhp;
911 struct sdebug_dev_info *dp;
912
913 spin_lock(&sdebug_host_list_lock);
914 list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
915 list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
916 if ((devip->sdbg_host == dp->sdbg_host) &&
917 (devip->target == dp->target))
918 clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
919 }
920 }
921 spin_unlock(&sdebug_host_list_lock);
922}
923
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400924static int make_ua(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925{
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400926 int k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400927
928 k = find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS);
929 if (k != SDEBUG_NUM_UAS) {
930 const char *cp = NULL;
931
932 switch (k) {
933 case SDEBUG_UA_POR:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400934 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
935 POWER_ON_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400936 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400937 cp = "power on reset";
938 break;
939 case SDEBUG_UA_BUS_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400940 mk_sense_buffer(scp, UNIT_ATTENTION, UA_RESET_ASC,
941 BUS_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400942 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400943 cp = "bus reset";
944 break;
945 case SDEBUG_UA_MODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400946 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
947 MODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400948 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400949 cp = "mode parameters changed";
950 break;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500951 case SDEBUG_UA_CAPACITY_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400952 mk_sense_buffer(scp, UNIT_ATTENTION, UA_CHANGED_ASC,
953 CAPACITY_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400954 if (sdebug_verbose)
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -0500955 cp = "capacity data changed";
Ewan D. Milnef49accf2014-12-04 11:49:25 -0500956 break;
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500957 case SDEBUG_UA_MICROCODE_CHANGED:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400958 mk_sense_buffer(scp, UNIT_ATTENTION,
Douglas Gilbertb01f6f82016-04-30 22:44:42 -0400959 TARGET_CHANGED_ASC,
960 MICROCODE_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400961 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500962 cp = "microcode has been changed";
963 break;
964 case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400965 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500966 TARGET_CHANGED_ASC,
967 MICROCODE_CHANGED_WO_RESET_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400968 if (sdebug_verbose)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -0500969 cp = "microcode has been changed without reset";
970 break;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500971 case SDEBUG_UA_LUNS_CHANGED:
972 /*
973 * SPC-3 behavior is to report a UNIT ATTENTION with
974 * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
975 * on the target, until a REPORT LUNS command is
976 * received. SPC-4 behavior is to report it only once.
Douglas Gilbert773642d2016-04-25 12:16:28 -0400977 * NOTE: sdebug_scsi_level does not use the same
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500978 * values as struct scsi_device->scsi_level.
979 */
Douglas Gilbert773642d2016-04-25 12:16:28 -0400980 if (sdebug_scsi_level >= 6) /* SPC-4 and above */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500981 clear_luns_changed_on_target(devip);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400982 mk_sense_buffer(scp, UNIT_ATTENTION,
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500983 TARGET_CHANGED_ASC,
984 LUNS_CHANGED_ASCQ);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400985 if (sdebug_verbose)
Ewan D. Milne19c8ead2014-12-04 11:49:27 -0500986 cp = "reported luns data has changed";
987 break;
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400988 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -0400989 pr_warn("unexpected unit attention code=%d\n", k);
990 if (sdebug_verbose)
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400991 cp = "unknown";
992 break;
993 }
994 clear_bit(k, devip->uas_bm);
Douglas Gilbert773642d2016-04-25 12:16:28 -0400995 if (sdebug_verbose)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -0400996 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -0400997 "%s reports: Unit attention: %s\n",
998 my_name, cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 return check_condition_result;
1000 }
1001 return 0;
1002}
1003
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001004/* Build SCSI "data-in" buffer. Returns 0 if ok else (DID_ERROR << 16). */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001005static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001006 int arr_len)
1007{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001008 int act_len;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001009 struct scsi_data_buffer *sdb = &scp->sdb;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001010
FUJITA Tomonori072d0bb2008-01-23 01:32:00 +09001011 if (!sdb->length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001012 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001013 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbert773642d2016-04-25 12:16:28 -04001014 return DID_ERROR << 16;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001015
1016 act_len = sg_copy_from_buffer(sdb->table.sgl, sdb->table.nents,
1017 arr, arr_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001018 scsi_set_resid(scp, scsi_bufflen(scp) - act_len);
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001019
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 return 0;
1021}
1022
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001023/* Partial build of SCSI "data-in" buffer. Returns 0 if ok else
1024 * (DID_ERROR << 16). Can write to offset in data-in buffer. If multiple
1025 * calls, not required to write in ascending offset order. Assumes resid
1026 * set to scsi_bufflen() prior to any calls.
1027 */
1028static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr,
1029 int arr_len, unsigned int off_dst)
1030{
1031 int act_len, n;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001032 struct scsi_data_buffer *sdb = &scp->sdb;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001033 off_t skip = off_dst;
1034
1035 if (sdb->length <= off_dst)
1036 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001037 if (scp->sc_data_direction != DMA_FROM_DEVICE)
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001038 return DID_ERROR << 16;
1039
1040 act_len = sg_pcopy_from_buffer(sdb->table.sgl, sdb->table.nents,
1041 arr, arr_len, skip);
1042 pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n",
Bart Van Assche42d387b2019-02-08 13:25:00 -08001043 __func__, off_dst, scsi_bufflen(scp), act_len,
1044 scsi_get_resid(scp));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001045 n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len);
Bart Van Assche42d387b2019-02-08 13:25:00 -08001046 scsi_set_resid(scp, min(scsi_get_resid(scp), n));
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04001047 return 0;
1048}
1049
1050/* Fetches from SCSI "data-out" buffer. Returns number of bytes fetched into
1051 * 'arr' or -1 if error.
1052 */
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001053static int fetch_to_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr,
1054 int arr_len)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001055{
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001056 if (!scsi_bufflen(scp))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001057 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01001058 if (scp->sc_data_direction != DMA_TO_DEVICE)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 return -1;
FUJITA Tomonori21a61822008-03-09 13:44:30 +09001060
1061 return scsi_sg_copy_to_buffer(scp, arr, arr_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001062}
1063
1064
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001065static char sdebug_inq_vendor_id[9] = "Linux ";
1066static char sdebug_inq_product_id[17] = "scsi_debug ";
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001067static char sdebug_inq_product_rev[5] = SDEBUG_VERSION;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001068/* Use some locally assigned NAAs for SAS addresses. */
1069static const u64 naa3_comp_a = 0x3222222000000000ULL;
1070static const u64 naa3_comp_b = 0x3333333000000000ULL;
1071static const u64 naa3_comp_c = 0x3111111000000000ULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001073/* Device identification VPD page. Returns number of bytes placed in arr */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001074static int inquiry_vpd_83(unsigned char *arr, int port_group_id,
1075 int target_dev_id, int dev_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001076 const char *dev_id_str, int dev_id_str_len,
Christoph Hellwigbf476432017-05-17 09:55:26 +02001077 const uuid_t *lu_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001079 int num, port_a;
1080 char b[32];
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001082 port_a = target_dev_id + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083 /* T10 vendor identifier field format (faked) */
1084 arr[0] = 0x2; /* ASCII */
1085 arr[1] = 0x1;
1086 arr[2] = 0x0;
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001087 memcpy(&arr[4], sdebug_inq_vendor_id, 8);
1088 memcpy(&arr[12], sdebug_inq_product_id, 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 memcpy(&arr[28], dev_id_str, dev_id_str_len);
1090 num = 8 + 16 + dev_id_str_len;
1091 arr[3] = num;
1092 num += 4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001093 if (dev_id_num >= 0) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001094 if (sdebug_uuid_ctl) {
1095 /* Locally assigned UUID */
1096 arr[num++] = 0x1; /* binary (not necessarily sas) */
1097 arr[num++] = 0xa; /* PIV=0, lu, naa */
1098 arr[num++] = 0x0;
1099 arr[num++] = 0x12;
1100 arr[num++] = 0x10; /* uuid type=1, locally assigned */
1101 arr[num++] = 0x0;
1102 memcpy(arr + num, lu_name, 16);
1103 num += 16;
1104 } else {
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001105 /* NAA-3, Logical unit identifier (binary) */
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001106 arr[num++] = 0x1; /* binary (not necessarily sas) */
1107 arr[num++] = 0x3; /* PIV=0, lu, naa */
1108 arr[num++] = 0x0;
1109 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001110 put_unaligned_be64(naa3_comp_b + dev_id_num, arr + num);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001111 num += 8;
1112 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001113 /* Target relative port number */
1114 arr[num++] = 0x61; /* proto=sas, binary */
1115 arr[num++] = 0x94; /* PIV=1, target port, rel port */
1116 arr[num++] = 0x0; /* reserved */
1117 arr[num++] = 0x4; /* length */
1118 arr[num++] = 0x0; /* reserved */
1119 arr[num++] = 0x0; /* reserved */
1120 arr[num++] = 0x0;
1121 arr[num++] = 0x1; /* relative port A */
1122 }
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001123 /* NAA-3, Target port identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001124 arr[num++] = 0x61; /* proto=sas, binary */
1125 arr[num++] = 0x93; /* piv=1, target port, naa */
1126 arr[num++] = 0x0;
1127 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001128 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001129 num += 8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001130 /* NAA-3, Target port group identifier */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001131 arr[num++] = 0x61; /* proto=sas, binary */
1132 arr[num++] = 0x95; /* piv=1, target port group id */
1133 arr[num++] = 0x0;
1134 arr[num++] = 0x4;
1135 arr[num++] = 0;
1136 arr[num++] = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001137 put_unaligned_be16(port_group_id, arr + num);
1138 num += 2;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001139 /* NAA-3, Target device identifier */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001140 arr[num++] = 0x61; /* proto=sas, binary */
1141 arr[num++] = 0xa3; /* piv=1, target device, naa */
1142 arr[num++] = 0x0;
1143 arr[num++] = 0x8;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001144 put_unaligned_be64(naa3_comp_a + target_dev_id, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001145 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001146 /* SCSI name string: Target device identifier */
1147 arr[num++] = 0x63; /* proto=sas, UTF-8 */
1148 arr[num++] = 0xa8; /* piv=1, target device, SCSI name string */
1149 arr[num++] = 0x0;
1150 arr[num++] = 24;
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001151 memcpy(arr + num, "naa.32222220", 12);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001152 num += 12;
1153 snprintf(b, sizeof(b), "%08X", target_dev_id);
1154 memcpy(arr + num, b, 8);
1155 num += 8;
1156 memset(arr + num, 0, 4);
1157 num += 4;
1158 return num;
1159}
1160
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001161static unsigned char vpd84_data[] = {
1162/* from 4th byte */ 0x22,0x22,0x22,0x0,0xbb,0x0,
1163 0x22,0x22,0x22,0x0,0xbb,0x1,
1164 0x22,0x22,0x22,0x0,0xbb,0x2,
1165};
1166
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001167/* Software interface identification VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001168static int inquiry_vpd_84(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001169{
1170 memcpy(arr, vpd84_data, sizeof(vpd84_data));
1171 return sizeof(vpd84_data);
1172}
1173
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001174/* Management network addresses VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001175static int inquiry_vpd_85(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001176{
1177 int num = 0;
John Pittman91d4c752018-02-09 21:12:43 -05001178 const char *na1 = "https://www.kernel.org/config";
1179 const char *na2 = "http://www.kernel.org/log";
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001180 int plen, olen;
1181
1182 arr[num++] = 0x1; /* lu, storage config */
1183 arr[num++] = 0x0; /* reserved */
1184 arr[num++] = 0x0;
1185 olen = strlen(na1);
1186 plen = olen + 1;
1187 if (plen % 4)
1188 plen = ((plen / 4) + 1) * 4;
1189 arr[num++] = plen; /* length, null termianted, padded */
1190 memcpy(arr + num, na1, olen);
1191 memset(arr + num + olen, 0, plen - olen);
1192 num += plen;
1193
1194 arr[num++] = 0x4; /* lu, logging */
1195 arr[num++] = 0x0; /* reserved */
1196 arr[num++] = 0x0;
1197 olen = strlen(na2);
1198 plen = olen + 1;
1199 if (plen % 4)
1200 plen = ((plen / 4) + 1) * 4;
1201 arr[num++] = plen; /* length, null terminated, padded */
1202 memcpy(arr + num, na2, olen);
1203 memset(arr + num + olen, 0, plen - olen);
1204 num += plen;
1205
1206 return num;
1207}
1208
1209/* SCSI ports VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001210static int inquiry_vpd_88(unsigned char *arr, int target_dev_id)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001211{
1212 int num = 0;
1213 int port_a, port_b;
1214
1215 port_a = target_dev_id + 1;
1216 port_b = port_a + 1;
1217 arr[num++] = 0x0; /* reserved */
1218 arr[num++] = 0x0; /* reserved */
1219 arr[num++] = 0x0;
1220 arr[num++] = 0x1; /* relative port 1 (primary) */
1221 memset(arr + num, 0, 6);
1222 num += 6;
1223 arr[num++] = 0x0;
1224 arr[num++] = 12; /* length tp descriptor */
1225 /* naa-5 target port identifier (A) */
1226 arr[num++] = 0x61; /* proto=sas, binary */
1227 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1228 arr[num++] = 0x0; /* reserved */
1229 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001230 put_unaligned_be64(naa3_comp_a + port_a, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001231 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001232 arr[num++] = 0x0; /* reserved */
1233 arr[num++] = 0x0; /* reserved */
1234 arr[num++] = 0x0;
1235 arr[num++] = 0x2; /* relative port 2 (secondary) */
1236 memset(arr + num, 0, 6);
1237 num += 6;
1238 arr[num++] = 0x0;
1239 arr[num++] = 12; /* length tp descriptor */
1240 /* naa-5 target port identifier (B) */
1241 arr[num++] = 0x61; /* proto=sas, binary */
1242 arr[num++] = 0x93; /* PIV=1, target port, NAA */
1243 arr[num++] = 0x0; /* reserved */
1244 arr[num++] = 0x8; /* length */
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04001245 put_unaligned_be64(naa3_comp_a + port_b, arr + num);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001246 num += 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001247
1248 return num;
1249}
1250
1251
1252static unsigned char vpd89_data[] = {
1253/* from 4th byte */ 0,0,0,0,
1254'l','i','n','u','x',' ',' ',' ',
1255'S','A','T',' ','s','c','s','i','_','d','e','b','u','g',' ',' ',
1256'1','2','3','4',
12570x34,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,
12580xec,0,0,0,
12590x5a,0xc,0xff,0x3f,0x37,0xc8,0x10,0,0,0,0,0,0x3f,0,0,0,
12600,0,0,0,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x58,0x20,0x20,0x20,0x20,
12610x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0,0,0,0x40,0x4,0,0x2e,0x33,
12620x38,0x31,0x20,0x20,0x20,0x20,0x54,0x53,0x38,0x33,0x30,0x30,0x33,0x31,
12630x53,0x41,
12640x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12650x20,0x20,
12660x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
12670x10,0x80,
12680,0,0,0x2f,0,0,0,0x2,0,0x2,0x7,0,0xff,0xff,0x1,0,
12690x3f,0,0xc1,0xff,0x3e,0,0x10,0x1,0xb0,0xf8,0x50,0x9,0,0,0x7,0,
12700x3,0,0x78,0,0x78,0,0xf0,0,0x78,0,0,0,0,0,0,0,
12710,0,0,0,0,0,0,0,0x2,0,0,0,0,0,0,0,
12720x7e,0,0x1b,0,0x6b,0x34,0x1,0x7d,0x3,0x40,0x69,0x34,0x1,0x3c,0x3,0x40,
12730x7f,0x40,0,0,0,0,0xfe,0xfe,0,0,0,0,0,0xfe,0,0,
12740,0,0,0,0,0,0,0,0xb0,0xf8,0x50,0x9,0,0,0,0,
12750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12760,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12770,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12780x1,0,0xb0,0xf8,0x50,0x9,0xb0,0xf8,0x50,0x9,0x20,0x20,0x2,0,0xb6,0x42,
12790,0x80,0x8a,0,0x6,0x3c,0xa,0x3c,0xff,0xff,0xc6,0x7,0,0x1,0,0x8,
12800xf0,0xf,0,0x10,0x2,0,0x30,0,0,0,0,0,0,0,0x6,0xfe,
12810,0,0x2,0,0x50,0,0x8a,0,0x4f,0x95,0,0,0x21,0,0xb,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,0,0,
12910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
12930,0,0,0,0,0,0,0,0,0,0,0,0,0,0xa5,0x51,
1294};
1295
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001296/* ATA Information VPD page */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001297static int inquiry_vpd_89(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001298{
1299 memcpy(arr, vpd89_data, sizeof(vpd89_data));
1300 return sizeof(vpd89_data);
1301}
1302
1303
1304static unsigned char vpdb0_data[] = {
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001305 /* from 4th byte */ 0,0,0,4, 0,0,0x4,0, 0,0,0,64,
1306 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1307 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1308 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001309};
1310
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001311/* Block limits VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001312static int inquiry_vpd_b0(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001313{
Martin K. Petersenea61fca2009-05-15 00:40:33 -04001314 unsigned int gran;
1315
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001316 memcpy(arr, vpdb0_data, sizeof(vpdb0_data));
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001317
1318 /* Optimal transfer length granularity */
Lukas Herbolt86e68282017-01-26 10:00:37 +01001319 if (sdebug_opt_xferlen_exp != 0 &&
1320 sdebug_physblk_exp < sdebug_opt_xferlen_exp)
1321 gran = 1 << sdebug_opt_xferlen_exp;
1322 else
1323 gran = 1 << sdebug_physblk_exp;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001324 put_unaligned_be16(gran, arr + 2);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001325
1326 /* Maximum Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001327 if (sdebug_store_sectors > 0x400)
1328 put_unaligned_be32(sdebug_store_sectors, arr + 4);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001329
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001330 /* Optimal Transfer Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001331 put_unaligned_be32(sdebug_opt_blks, &arr[8]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001332
Douglas Gilbert773642d2016-04-25 12:16:28 -04001333 if (sdebug_lbpu) {
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001334 /* Maximum Unmap LBA Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001335 put_unaligned_be32(sdebug_unmap_max_blocks, &arr[16]);
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001336
1337 /* Maximum Unmap Block Descriptor Count */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001338 put_unaligned_be32(sdebug_unmap_max_desc, &arr[20]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001339 }
1340
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001341 /* Unmap Granularity Alignment */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001342 if (sdebug_unmap_alignment) {
1343 put_unaligned_be32(sdebug_unmap_alignment, &arr[28]);
Martin K. Petersen44d92692009-10-15 14:45:27 -04001344 arr[28] |= 0x80; /* UGAVALID */
1345 }
1346
Martin K. Petersene308b3d2010-03-23 01:12:27 -04001347 /* Optimal Unmap Granularity */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001348 put_unaligned_be32(sdebug_unmap_granularity, &arr[24]);
Martin K. Petersen60147592010-08-19 11:49:00 -04001349
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001350 /* Maximum WRITE SAME Length */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001351 put_unaligned_be64(sdebug_write_same_length, &arr[32]);
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001352
1353 return 0x3c; /* Mandatory page length for Logical Block Provisioning */
Martin K. Petersen44d92692009-10-15 14:45:27 -04001354
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001355 return sizeof(vpdb0_data);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356}
1357
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001358/* Block device characteristics VPD page (SBC-3) */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001359static int inquiry_vpd_b1(unsigned char *arr)
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001360{
1361 memset(arr, 0, 0x3c);
1362 arr[0] = 0;
Douglas Gilbert1e49f782009-10-29 01:48:31 -04001363 arr[1] = 1; /* non rotating medium (e.g. solid state) */
1364 arr[2] = 0;
1365 arr[3] = 5; /* less than 1.8" */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001366
1367 return 0x3c;
1368}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001370/* Logical block provisioning VPD page (SBC-4) */
1371static int inquiry_vpd_b2(unsigned char *arr)
Martin K. Petersen60147592010-08-19 11:49:00 -04001372{
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001373 memset(arr, 0, 0x4);
Martin K. Petersen60147592010-08-19 11:49:00 -04001374 arr[0] = 0; /* threshold exponent */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001375 if (sdebug_lbpu)
Martin K. Petersen60147592010-08-19 11:49:00 -04001376 arr[1] = 1 << 7;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001377 if (sdebug_lbpws)
Martin K. Petersen60147592010-08-19 11:49:00 -04001378 arr[1] |= 1 << 6;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001379 if (sdebug_lbpws10)
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001380 arr[1] |= 1 << 5;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001381 if (sdebug_lbprz && scsi_debug_lbp())
1382 arr[1] |= (sdebug_lbprz & 0x7) << 2; /* sbc4r07 and later */
1383 /* anc_sup=0; dp=0 (no provisioning group descriptor) */
1384 /* minimum_percentage=0; provisioning_type=0 (unknown) */
1385 /* threshold_percentage=0 */
Martin K. Petersen3f0bc3b2012-03-08 10:48:29 -05001386 return 0x4;
Martin K. Petersen60147592010-08-19 11:49:00 -04001387}
1388
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389#define SDEBUG_LONG_INQ_SZ 96
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001390#define SDEBUG_MAX_INQ_ARR_SZ 584
Linus Torvalds1da177e2005-04-16 15:20:36 -07001391
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001392static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393{
1394 unsigned char pq_pdt;
John Pittman91d4c752018-02-09 21:12:43 -05001395 unsigned char *arr;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001396 unsigned char *cmd = scp->cmnd;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001397 int alloc_len, n, ret;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001398 bool have_wlun, is_disk;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399
Douglas Gilbert773642d2016-04-25 12:16:28 -04001400 alloc_len = get_unaligned_be16(cmd + 3);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001401 arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
1402 if (! arr)
1403 return DID_REQUEUE << 16;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001404 is_disk = (sdebug_ptype == TYPE_DISK);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001405 have_wlun = scsi_is_wlun(scp->device->lun);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001406 if (have_wlun)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001407 pq_pdt = TYPE_WLUN; /* present, wlun */
1408 else if (sdebug_no_lun_0 && (devip->lun == SDEBUG_LUN_0_VAL))
1409 pq_pdt = 0x7f; /* not present, PQ=3, PDT=0x1f */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001410 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04001411 pq_pdt = (sdebug_ptype & 0x1f);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001412 arr[0] = pq_pdt;
1413 if (0x2 & cmd[1]) { /* CMDDT bit set */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001414 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001415 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416 return check_condition_result;
1417 } else if (0x1 & cmd[1]) { /* EVPD bit set */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001418 int lu_id_num, port_group_id, target_dev_id, len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001419 char lu_id_str[6];
1420 int host_no = devip->sdbg_host->shost->host_no;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001422 port_group_id = (((host_no + 1) & 0x7f) << 8) +
1423 (devip->channel & 0x7f);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001424 if (sdebug_vpd_use_hostno == 0)
Douglas Gilbert23183912006-09-16 20:30:47 -04001425 host_no = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001426 lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001427 (devip->target * 1000) + devip->lun);
1428 target_dev_id = ((host_no + 1) * 2000) +
1429 (devip->target * 1000) - 3;
1430 len = scnprintf(lu_id_str, 6, "%d", lu_id_num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 if (0 == cmd[2]) { /* supported vital product data pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001432 arr[1] = cmd[2]; /*sanity */
1433 n = 4;
1434 arr[n++] = 0x0; /* this page */
1435 arr[n++] = 0x80; /* unit serial number */
1436 arr[n++] = 0x83; /* device identification */
1437 arr[n++] = 0x84; /* software interface ident. */
1438 arr[n++] = 0x85; /* management network addresses */
1439 arr[n++] = 0x86; /* extended inquiry */
1440 arr[n++] = 0x87; /* mode page policy */
1441 arr[n++] = 0x88; /* SCSI ports */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001442 if (is_disk) { /* SBC only */
1443 arr[n++] = 0x89; /* ATA information */
1444 arr[n++] = 0xb0; /* Block limits */
1445 arr[n++] = 0xb1; /* Block characteristics */
1446 arr[n++] = 0xb2; /* Logical Block Prov */
1447 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001448 arr[3] = n - 4; /* number of supported VPD pages */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001449 } else if (0x80 == cmd[2]) { /* unit serial number */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001450 arr[1] = cmd[2]; /*sanity */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451 arr[3] = len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001452 memcpy(&arr[4], lu_id_str, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001453 } else if (0x83 == cmd[2]) { /* device identification */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001454 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001455 arr[3] = inquiry_vpd_83(&arr[4], port_group_id,
1456 target_dev_id, lu_id_num,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04001457 lu_id_str, len,
1458 &devip->lu_name);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001459 } else if (0x84 == cmd[2]) { /* Software interface ident. */
1460 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001461 arr[3] = inquiry_vpd_84(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001462 } else if (0x85 == cmd[2]) { /* Management network addresses */
1463 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001464 arr[3] = inquiry_vpd_85(&arr[4]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001465 } else if (0x86 == cmd[2]) { /* extended inquiry */
1466 arr[1] = cmd[2]; /*sanity */
1467 arr[3] = 0x3c; /* number of following entries */
Christoph Hellwig8475c812016-09-11 19:35:41 +02001468 if (sdebug_dif == T10_PI_TYPE3_PROTECTION)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001469 arr[4] = 0x4; /* SPT: GRD_CHK:1 */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001470 else if (have_dif_prot)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001471 arr[4] = 0x5; /* SPT: GRD_CHK:1, REF_CHK:1 */
1472 else
1473 arr[4] = 0x0; /* no protection stuff */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001474 arr[5] = 0x7; /* head of q, ordered + simple q's */
1475 } else if (0x87 == cmd[2]) { /* mode page policy */
1476 arr[1] = cmd[2]; /*sanity */
1477 arr[3] = 0x8; /* number of following entries */
1478 arr[4] = 0x2; /* disconnect-reconnect mp */
1479 arr[6] = 0x80; /* mlus, shared */
1480 arr[8] = 0x18; /* protocol specific lu */
1481 arr[10] = 0x82; /* mlus, per initiator port */
1482 } else if (0x88 == cmd[2]) { /* SCSI Ports */
1483 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001484 arr[3] = inquiry_vpd_88(&arr[4], target_dev_id);
1485 } else if (is_disk && 0x89 == cmd[2]) { /* ATA information */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001486 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001487 n = inquiry_vpd_89(&arr[4]);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001488 put_unaligned_be16(n, arr + 2);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001489 } else if (is_disk && 0xb0 == cmd[2]) { /* Block limits */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001490 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001491 arr[3] = inquiry_vpd_b0(&arr[4]);
1492 } else if (is_disk && 0xb1 == cmd[2]) { /* Block char. */
Matthew Wilcoxeac6e8e42008-06-19 10:02:58 -06001493 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001494 arr[3] = inquiry_vpd_b1(&arr[4]);
1495 } else if (is_disk && 0xb2 == cmd[2]) { /* LB Prov. */
Martin K. Petersen60147592010-08-19 11:49:00 -04001496 arr[1] = cmd[2]; /*sanity */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001497 arr[3] = inquiry_vpd_b2(&arr[4]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001498 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001499 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001500 kfree(arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001501 return check_condition_result;
1502 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001503 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001504 ret = fill_from_dev_buffer(scp, arr,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001505 min(len, SDEBUG_MAX_INQ_ARR_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001506 kfree(arr);
1507 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
1509 /* drops through here for a standard inquiry */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001510 arr[1] = sdebug_removable ? 0x80 : 0; /* Removable disk */
1511 arr[2] = sdebug_scsi_level;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512 arr[3] = 2; /* response_data_format==2 */
1513 arr[4] = SDEBUG_LONG_INQ_SZ - 5;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04001514 arr[5] = (int)have_dif_prot; /* PROTECT bit */
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001515 if (sdebug_vpd_use_hostno == 0)
Martin K. Petersen70bdf202017-05-19 12:39:36 -04001516 arr[5] |= 0x10; /* claim: implicit TPGS */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001517 arr[6] = 0x10; /* claim: MultiP */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 /* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001519 arr[7] = 0xa; /* claim: LINKED + CMDQUE */
Hannes Reineckee5203cf2017-10-02 16:26:33 +02001520 memcpy(&arr[8], sdebug_inq_vendor_id, 8);
1521 memcpy(&arr[16], sdebug_inq_product_id, 16);
1522 memcpy(&arr[32], sdebug_inq_product_rev, 4);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05001523 /* Use Vendor Specific area to place driver date in ASCII hex */
1524 memcpy(&arr[36], sdebug_version_date, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 /* version descriptors (2 bytes each) follow */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001526 put_unaligned_be16(0xc0, arr + 58); /* SAM-6 no version claimed */
1527 put_unaligned_be16(0x5c0, arr + 60); /* SPC-5 no version claimed */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001528 n = 62;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001529 if (is_disk) { /* SBC-4 no version claimed */
1530 put_unaligned_be16(0x600, arr + n);
1531 n += 2;
1532 } else if (sdebug_ptype == TYPE_TAPE) { /* SSC-4 rev 3 */
1533 put_unaligned_be16(0x525, arr + n);
1534 n += 2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001535 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001536 put_unaligned_be16(0x2100, arr + n); /* SPL-4 no version claimed */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001537 ret = fill_from_dev_buffer(scp, arr,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 min(alloc_len, SDEBUG_LONG_INQ_SZ));
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001539 kfree(arr);
1540 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541}
1542
Douglas Gilbertfd321192016-04-25 12:16:33 -04001543static unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
1544 0, 0, 0x0, 0x0};
1545
John Pittman91d4c752018-02-09 21:12:43 -05001546static int resp_requests(struct scsi_cmnd *scp,
1547 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001548{
John Pittman91d4c752018-02-09 21:12:43 -05001549 unsigned char *sbuff;
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001550 unsigned char *cmd = scp->cmnd;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001551 unsigned char arr[SCSI_SENSE_BUFFERSIZE];
Tomas Winkler2492fc02015-07-28 16:54:26 +03001552 bool dsense;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 int len = 18;
1554
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001555 memset(arr, 0, sizeof(arr));
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001556 dsense = !!(cmd[1] & 1);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001557 sbuff = scp->sense_buffer;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001558 if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001559 if (dsense) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001560 arr[0] = 0x72;
1561 arr[1] = 0x0; /* NO_SENSE in sense_key */
1562 arr[2] = THRESHOLD_EXCEEDED;
1563 arr[3] = 0xff; /* TEST set and MRIE==6 */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001564 len = 8;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001565 } else {
1566 arr[0] = 0x70;
1567 arr[2] = 0x0; /* NO_SENSE in sense_key */
1568 arr[7] = 0xa; /* 18 byte sense buffer */
1569 arr[12] = THRESHOLD_EXCEEDED;
1570 arr[13] = 0xff; /* TEST set and MRIE==6 */
1571 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001572 } else {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001573 memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001574 if (arr[0] >= 0x70 && dsense == sdebug_dsense)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001575 ; /* have sense and formats match */
1576 else if (arr[0] <= 0x70) {
1577 if (dsense) {
1578 memset(arr, 0, 8);
1579 arr[0] = 0x72;
1580 len = 8;
1581 } else {
1582 memset(arr, 0, 18);
1583 arr[0] = 0x70;
1584 arr[7] = 0xa;
1585 }
1586 } else if (dsense) {
1587 memset(arr, 0, 8);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001588 arr[0] = 0x72;
1589 arr[1] = sbuff[2]; /* sense key */
1590 arr[2] = sbuff[12]; /* asc */
1591 arr[3] = sbuff[13]; /* ascq */
1592 len = 8;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001593 } else {
1594 memset(arr, 0, 18);
1595 arr[0] = 0x70;
1596 arr[2] = sbuff[1];
1597 arr[7] = 0xa;
1598 arr[12] = sbuff[1];
1599 arr[13] = sbuff[3];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001600 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05001601
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001602 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001603 mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604 return fill_from_dev_buffer(scp, arr, len);
1605}
1606
John Pittman91d4c752018-02-09 21:12:43 -05001607static int resp_start_stop(struct scsi_cmnd *scp,
1608 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001609{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001610 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001611 int power_cond, stop;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001612 bool changing;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001613
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001614 power_cond = (cmd[4] & 0xf0) >> 4;
1615 if (power_cond) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05001616 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001617 return check_condition_result;
1618 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04001619 stop = !(cmd[4] & 1);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001620 changing = atomic_read(&devip->stopped) == !stop;
Douglas Gilbertc4837392016-05-06 00:40:26 -04001621 atomic_xchg(&devip->stopped, stop);
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04001622 if (!changing || cmd[1] & 0x1) /* state unchanged or IMMED set */
1623 return SDEG_RES_IMMED_MASK;
1624 else
1625 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001626}
1627
FUJITA Tomonori28898872008-03-30 00:59:55 +09001628static sector_t get_sdebug_capacity(void)
1629{
Douglas Gilbert773642d2016-04-25 12:16:28 -04001630 static const unsigned int gibibyte = 1073741824;
1631
1632 if (sdebug_virtual_gb > 0)
1633 return (sector_t)sdebug_virtual_gb *
1634 (gibibyte / sdebug_sector_size);
FUJITA Tomonori28898872008-03-30 00:59:55 +09001635 else
1636 return sdebug_store_sectors;
1637}
1638
Linus Torvalds1da177e2005-04-16 15:20:36 -07001639#define SDEBUG_READCAP_ARR_SZ 8
John Pittman91d4c752018-02-09 21:12:43 -05001640static int resp_readcap(struct scsi_cmnd *scp,
1641 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642{
1643 unsigned char arr[SDEBUG_READCAP_ARR_SZ];
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001644 unsigned int capac;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001646 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001647 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001649 if (sdebug_capacity < 0xffffffff) {
1650 capac = (unsigned int)sdebug_capacity - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001651 put_unaligned_be32(capac, arr + 0);
1652 } else
1653 put_unaligned_be32(0xffffffff, arr + 0);
1654 put_unaligned_be16(sdebug_sector_size, arr + 6);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
1656}
1657
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001658#define SDEBUG_READCAP16_ARR_SZ 32
John Pittman91d4c752018-02-09 21:12:43 -05001659static int resp_readcap16(struct scsi_cmnd *scp,
1660 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001661{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001662 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001663 unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
Douglas Gilbert773642d2016-04-25 12:16:28 -04001664 int alloc_len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001665
Douglas Gilbert773642d2016-04-25 12:16:28 -04001666 alloc_len = get_unaligned_be32(cmd + 10);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001667 /* following just in case virtual_gb changed */
FUJITA Tomonori28898872008-03-30 00:59:55 +09001668 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001669 memset(arr, 0, SDEBUG_READCAP16_ARR_SZ);
Douglas Gilbert773642d2016-04-25 12:16:28 -04001670 put_unaligned_be64((u64)(sdebug_capacity - 1), arr + 0);
1671 put_unaligned_be32(sdebug_sector_size, arr + 8);
1672 arr[13] = sdebug_physblk_exp & 0xf;
1673 arr[14] = (sdebug_lowest_aligned >> 8) & 0x3f;
Martin K. Petersen44d92692009-10-15 14:45:27 -04001674
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001675 if (scsi_debug_lbp()) {
Martin K. Petersen5b94e232011-03-08 02:08:11 -05001676 arr[14] |= 0x80; /* LBPME */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001677 /* from sbc4r07, this LBPRZ field is 1 bit, but the LBPRZ in
1678 * the LB Provisioning VPD page is 3 bits. Note that lbprz=2
1679 * in the wider field maps to 0 in this field.
1680 */
1681 if (sdebug_lbprz & 1) /* precisely what the draft requires */
1682 arr[14] |= 0x40;
Eric Sandeenbe1dd782012-03-08 00:03:59 -06001683 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04001684
Douglas Gilbert773642d2016-04-25 12:16:28 -04001685 arr[15] = sdebug_lowest_aligned & 0xff;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001686
Douglas Gilbert760f3b02016-05-06 00:40:27 -04001687 if (have_dif_prot) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001688 arr[12] = (sdebug_dif - 1) << 1; /* P_TYPE */
Martin K. Petersenc6a44282009-01-04 03:08:19 -05001689 arr[12] |= 1; /* PROT_EN */
1690 }
1691
Douglas Gilbertc65b1442006-06-06 00:11:24 -04001692 return fill_from_dev_buffer(scp, arr,
1693 min(alloc_len, SDEBUG_READCAP16_ARR_SZ));
1694}
1695
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001696#define SDEBUG_MAX_TGTPGS_ARR_SZ 1412
1697
John Pittman91d4c752018-02-09 21:12:43 -05001698static int resp_report_tgtpgs(struct scsi_cmnd *scp,
1699 struct sdebug_dev_info *devip)
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001700{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02001701 unsigned char *cmd = scp->cmnd;
John Pittman91d4c752018-02-09 21:12:43 -05001702 unsigned char *arr;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001703 int host_no = devip->sdbg_host->shost->host_no;
1704 int n, ret, alen, rlen;
1705 int port_group_a, port_group_b, port_a, port_b;
1706
Douglas Gilbert773642d2016-04-25 12:16:28 -04001707 alen = get_unaligned_be32(cmd + 6);
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05001708 arr = kzalloc(SDEBUG_MAX_TGTPGS_ARR_SZ, GFP_ATOMIC);
1709 if (! arr)
1710 return DID_REQUEUE << 16;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001711 /*
1712 * EVPD page 0x88 states we have two ports, one
1713 * real and a fake port with no device connected.
1714 * So we create two port groups with one port each
1715 * and set the group with port B to unavailable.
1716 */
1717 port_a = 0x1; /* relative port A */
1718 port_b = 0x2; /* relative port B */
1719 port_group_a = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001720 (devip->channel & 0x7f);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001721 port_group_b = (((host_no + 1) & 0x7f) << 8) +
Douglas Gilbert773642d2016-04-25 12:16:28 -04001722 (devip->channel & 0x7f) + 0x80;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001723
1724 /*
1725 * The asymmetric access state is cycled according to the host_id.
1726 */
1727 n = 4;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04001728 if (sdebug_vpd_use_hostno == 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001729 arr[n++] = host_no % 3; /* Asymm access state */
1730 arr[n++] = 0x0F; /* claim: all states are supported */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001731 } else {
Douglas Gilbert773642d2016-04-25 12:16:28 -04001732 arr[n++] = 0x0; /* Active/Optimized path */
1733 arr[n++] = 0x01; /* only support active/optimized paths */
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001734 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04001735 put_unaligned_be16(port_group_a, arr + n);
1736 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001737 arr[n++] = 0; /* Reserved */
1738 arr[n++] = 0; /* Status code */
1739 arr[n++] = 0; /* Vendor unique */
1740 arr[n++] = 0x1; /* One port per group */
1741 arr[n++] = 0; /* Reserved */
1742 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001743 put_unaligned_be16(port_a, arr + n);
1744 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001745 arr[n++] = 3; /* Port unavailable */
1746 arr[n++] = 0x08; /* claim: only unavailalbe paths are supported */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001747 put_unaligned_be16(port_group_b, arr + n);
1748 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001749 arr[n++] = 0; /* Reserved */
1750 arr[n++] = 0; /* Status code */
1751 arr[n++] = 0; /* Vendor unique */
1752 arr[n++] = 0x1; /* One port per group */
1753 arr[n++] = 0; /* Reserved */
1754 arr[n++] = 0; /* Reserved */
Douglas Gilbert773642d2016-04-25 12:16:28 -04001755 put_unaligned_be16(port_b, arr + n);
1756 n += 2;
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001757
1758 rlen = n - 4;
Douglas Gilbert773642d2016-04-25 12:16:28 -04001759 put_unaligned_be32(rlen, arr + 0);
Hannes Reinecke5a09e392006-10-20 09:58:47 +02001760
1761 /*
1762 * Return the smallest value of either
1763 * - The allocated length
1764 * - The constructed command length
1765 * - The maximum array size
1766 */
1767 rlen = min(alen,n);
1768 ret = fill_from_dev_buffer(scp, arr,
1769 min(rlen, SDEBUG_MAX_TGTPGS_ARR_SZ));
1770 kfree(arr);
1771 return ret;
1772}
1773
Douglas Gilbertfd321192016-04-25 12:16:33 -04001774static int resp_rsup_opcodes(struct scsi_cmnd *scp,
1775 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001776{
1777 bool rctd;
1778 u8 reporting_opts, req_opcode, sdeb_i, supp;
1779 u16 req_sa, u;
1780 u32 alloc_len, a_len;
1781 int k, offset, len, errsts, count, bump, na;
1782 const struct opcode_info_t *oip;
1783 const struct opcode_info_t *r_oip;
1784 u8 *arr;
1785 u8 *cmd = scp->cmnd;
1786
1787 rctd = !!(cmd[2] & 0x80);
1788 reporting_opts = cmd[2] & 0x7;
1789 req_opcode = cmd[3];
1790 req_sa = get_unaligned_be16(cmd + 4);
1791 alloc_len = get_unaligned_be32(cmd + 6);
Colin Ian King6d310df2015-01-22 11:20:40 +00001792 if (alloc_len < 4 || alloc_len > 0xffff) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001793 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1794 return check_condition_result;
1795 }
1796 if (alloc_len > 8192)
1797 a_len = 8192;
1798 else
1799 a_len = alloc_len;
Sasha Levin99531e62015-01-17 17:47:37 -05001800 arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_ATOMIC);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001801 if (NULL == arr) {
1802 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
1803 INSUFF_RES_ASCQ);
1804 return check_condition_result;
1805 }
1806 switch (reporting_opts) {
1807 case 0: /* all commands */
1808 /* count number of commands */
1809 for (count = 0, oip = opcode_info_arr;
1810 oip->num_attached != 0xff; ++oip) {
1811 if (F_INV_OP & oip->flags)
1812 continue;
1813 count += (oip->num_attached + 1);
1814 }
1815 bump = rctd ? 20 : 8;
1816 put_unaligned_be32(count * bump, arr);
1817 for (offset = 4, oip = opcode_info_arr;
1818 oip->num_attached != 0xff && offset < a_len; ++oip) {
1819 if (F_INV_OP & oip->flags)
1820 continue;
1821 na = oip->num_attached;
1822 arr[offset] = oip->opcode;
1823 put_unaligned_be16(oip->sa, arr + offset + 2);
1824 if (rctd)
1825 arr[offset + 5] |= 0x2;
1826 if (FF_SA & oip->flags)
1827 arr[offset + 5] |= 0x1;
1828 put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
1829 if (rctd)
1830 put_unaligned_be16(0xa, arr + offset + 8);
1831 r_oip = oip;
1832 for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
1833 if (F_INV_OP & oip->flags)
1834 continue;
1835 offset += bump;
1836 arr[offset] = oip->opcode;
1837 put_unaligned_be16(oip->sa, arr + offset + 2);
1838 if (rctd)
1839 arr[offset + 5] |= 0x2;
1840 if (FF_SA & oip->flags)
1841 arr[offset + 5] |= 0x1;
1842 put_unaligned_be16(oip->len_mask[0],
1843 arr + offset + 6);
1844 if (rctd)
1845 put_unaligned_be16(0xa,
1846 arr + offset + 8);
1847 }
1848 oip = r_oip;
1849 offset += bump;
1850 }
1851 break;
1852 case 1: /* one command: opcode only */
1853 case 2: /* one command: opcode plus service action */
1854 case 3: /* one command: if sa==0 then opcode only else opcode+sa */
1855 sdeb_i = opcode_ind_arr[req_opcode];
1856 oip = &opcode_info_arr[sdeb_i];
1857 if (F_INV_OP & oip->flags) {
1858 supp = 1;
1859 offset = 4;
1860 } else {
1861 if (1 == reporting_opts) {
1862 if (FF_SA & oip->flags) {
1863 mk_sense_invalid_fld(scp, SDEB_IN_CDB,
1864 2, 2);
1865 kfree(arr);
1866 return check_condition_result;
1867 }
1868 req_sa = 0;
1869 } else if (2 == reporting_opts &&
1870 0 == (FF_SA & oip->flags)) {
1871 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
1872 kfree(arr); /* point at requested sa */
1873 return check_condition_result;
1874 }
1875 if (0 == (FF_SA & oip->flags) &&
1876 req_opcode == oip->opcode)
1877 supp = 3;
1878 else if (0 == (FF_SA & oip->flags)) {
1879 na = oip->num_attached;
1880 for (k = 0, oip = oip->arrp; k < na;
1881 ++k, ++oip) {
1882 if (req_opcode == oip->opcode)
1883 break;
1884 }
1885 supp = (k >= na) ? 1 : 3;
1886 } else if (req_sa != oip->sa) {
1887 na = oip->num_attached;
1888 for (k = 0, oip = oip->arrp; k < na;
1889 ++k, ++oip) {
1890 if (req_sa == oip->sa)
1891 break;
1892 }
1893 supp = (k >= na) ? 1 : 3;
1894 } else
1895 supp = 3;
1896 if (3 == supp) {
1897 u = oip->len_mask[0];
1898 put_unaligned_be16(u, arr + 2);
1899 arr[4] = oip->opcode;
1900 for (k = 1; k < u; ++k)
1901 arr[4 + k] = (k < 16) ?
1902 oip->len_mask[k] : 0xff;
1903 offset = 4 + u;
1904 } else
1905 offset = 4;
1906 }
1907 arr[1] = (rctd ? 0x80 : 0) | supp;
1908 if (rctd) {
1909 put_unaligned_be16(0xa, arr + offset);
1910 offset += 12;
1911 }
1912 break;
1913 default:
1914 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
1915 kfree(arr);
1916 return check_condition_result;
1917 }
1918 offset = (offset < a_len) ? offset : a_len;
1919 len = (offset < alloc_len) ? offset : alloc_len;
1920 errsts = fill_from_dev_buffer(scp, arr, len);
1921 kfree(arr);
1922 return errsts;
1923}
1924
Douglas Gilbertfd321192016-04-25 12:16:33 -04001925static int resp_rsup_tmfs(struct scsi_cmnd *scp,
1926 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05001927{
1928 bool repd;
1929 u32 alloc_len, len;
1930 u8 arr[16];
1931 u8 *cmd = scp->cmnd;
1932
1933 memset(arr, 0, sizeof(arr));
1934 repd = !!(cmd[2] & 0x80);
1935 alloc_len = get_unaligned_be32(cmd + 6);
1936 if (alloc_len < 4) {
1937 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
1938 return check_condition_result;
1939 }
1940 arr[0] = 0xc8; /* ATS | ATSS | LURS */
1941 arr[1] = 0x1; /* ITNRS */
1942 if (repd) {
1943 arr[3] = 0xc;
1944 len = 16;
1945 } else
1946 len = 4;
1947
1948 len = (len < alloc_len) ? len : alloc_len;
1949 return fill_from_dev_buffer(scp, arr, len);
1950}
1951
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952/* <<Following mode page info copied from ST318451LW>> */
1953
John Pittman91d4c752018-02-09 21:12:43 -05001954static int resp_err_recov_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955{ /* Read-Write Error Recovery page for mode_sense */
1956 unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
1957 5, 0, 0xff, 0xff};
1958
1959 memcpy(p, err_recov_pg, sizeof(err_recov_pg));
1960 if (1 == pcontrol)
1961 memset(p + 2, 0, sizeof(err_recov_pg) - 2);
1962 return sizeof(err_recov_pg);
1963}
1964
John Pittman91d4c752018-02-09 21:12:43 -05001965static int resp_disconnect_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001966{ /* Disconnect-Reconnect page for mode_sense */
1967 unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
1968 0, 0, 0, 0, 0, 0, 0, 0};
1969
1970 memcpy(p, disconnect_pg, sizeof(disconnect_pg));
1971 if (1 == pcontrol)
1972 memset(p + 2, 0, sizeof(disconnect_pg) - 2);
1973 return sizeof(disconnect_pg);
1974}
1975
John Pittman91d4c752018-02-09 21:12:43 -05001976static int resp_format_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001977{ /* Format device page for mode_sense */
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001978 unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
1979 0, 0, 0, 0, 0, 0, 0, 0,
1980 0, 0, 0, 0, 0x40, 0, 0, 0};
Linus Torvalds1da177e2005-04-16 15:20:36 -07001981
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001982 memcpy(p, format_pg, sizeof(format_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04001983 put_unaligned_be16(sdebug_sectors_per, p + 10);
1984 put_unaligned_be16(sdebug_sector_size, p + 12);
1985 if (sdebug_removable)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04001986 p[20] |= 0x20; /* should agree with INQUIRY */
1987 if (1 == pcontrol)
1988 memset(p + 2, 0, sizeof(format_pg) - 2);
1989 return sizeof(format_pg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001990}
1991
Douglas Gilbertfd321192016-04-25 12:16:33 -04001992static unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
1993 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,
1994 0, 0, 0, 0};
1995
John Pittman91d4c752018-02-09 21:12:43 -05001996static int resp_caching_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001997{ /* Caching page for mode_sense */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04001998 unsigned char ch_caching_pg[] = {/* 0x8, 18, */ 0x4, 0, 0, 0, 0, 0,
1999 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
2000 unsigned char d_caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002001 0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0, 0, 0, 0, 0};
2002
Douglas Gilbert773642d2016-04-25 12:16:28 -04002003 if (SDEBUG_OPT_N_WCE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002004 caching_pg[2] &= ~0x4; /* set WCE=0 (default WCE=1) */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 memcpy(p, caching_pg, sizeof(caching_pg));
2006 if (1 == pcontrol)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002007 memcpy(p + 2, ch_caching_pg, sizeof(ch_caching_pg));
2008 else if (2 == pcontrol)
2009 memcpy(p, d_caching_pg, sizeof(d_caching_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002010 return sizeof(caching_pg);
2011}
2012
Douglas Gilbertfd321192016-04-25 12:16:33 -04002013static unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
2014 0, 0, 0x2, 0x4b};
2015
John Pittman91d4c752018-02-09 21:12:43 -05002016static int resp_ctrl_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002017{ /* Control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002018 unsigned char ch_ctrl_m_pg[] = {/* 0xa, 10, */ 0x6, 0, 0, 0, 0, 0,
Douglas Gilbert9a051012017-12-23 12:48:10 -05002019 0, 0, 0, 0};
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002020 unsigned char d_ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002021 0, 0, 0x2, 0x4b};
2022
Douglas Gilbert773642d2016-04-25 12:16:28 -04002023 if (sdebug_dsense)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024 ctrl_m_pg[2] |= 0x4;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002025 else
2026 ctrl_m_pg[2] &= ~0x4;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002027
Douglas Gilbert773642d2016-04-25 12:16:28 -04002028 if (sdebug_ato)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002029 ctrl_m_pg[5] |= 0x80; /* ATO=1 */
2030
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
2032 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002033 memcpy(p + 2, ch_ctrl_m_pg, sizeof(ch_ctrl_m_pg));
2034 else if (2 == pcontrol)
2035 memcpy(p, d_ctrl_m_pg, sizeof(d_ctrl_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002036 return sizeof(ctrl_m_pg);
2037}
2038
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002039
John Pittman91d4c752018-02-09 21:12:43 -05002040static int resp_iec_m_pg(unsigned char *p, int pcontrol, int target)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041{ /* Informational Exceptions control mode page for mode_sense */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002042 unsigned char ch_iec_m_pg[] = {/* 0x1c, 0xa, */ 0x4, 0xf, 0, 0, 0, 0,
2043 0, 0, 0x0, 0x0};
2044 unsigned char d_iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
2045 0, 0, 0x0, 0x0};
2046
Linus Torvalds1da177e2005-04-16 15:20:36 -07002047 memcpy(p, iec_m_pg, sizeof(iec_m_pg));
2048 if (1 == pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002049 memcpy(p + 2, ch_iec_m_pg, sizeof(ch_iec_m_pg));
2050 else if (2 == pcontrol)
2051 memcpy(p, d_iec_m_pg, sizeof(d_iec_m_pg));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002052 return sizeof(iec_m_pg);
2053}
2054
John Pittman91d4c752018-02-09 21:12:43 -05002055static int resp_sas_sf_m_pg(unsigned char *p, int pcontrol, int target)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002056{ /* SAS SSP mode page - short format for mode_sense */
2057 unsigned char sas_sf_m_pg[] = {0x19, 0x6,
2058 0x6, 0x0, 0x7, 0xd0, 0x0, 0x0};
2059
2060 memcpy(p, sas_sf_m_pg, sizeof(sas_sf_m_pg));
2061 if (1 == pcontrol)
2062 memset(p + 2, 0, sizeof(sas_sf_m_pg) - 2);
2063 return sizeof(sas_sf_m_pg);
2064}
2065
2066
John Pittman91d4c752018-02-09 21:12:43 -05002067static int resp_sas_pcd_m_spg(unsigned char *p, int pcontrol, int target,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002068 int target_dev_id)
2069{ /* SAS phy control and discover mode page for mode_sense */
2070 unsigned char sas_pcd_m_pg[] = {0x59, 0x1, 0, 0x64, 0, 0x6, 0, 2,
2071 0, 0, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002072 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2073 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002074 0x2, 0, 0, 0, 0, 0, 0, 0,
2075 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2076 0, 0, 0, 0, 0, 0, 0, 0,
2077 0, 1, 0, 0, 0x10, 0x9, 0x8, 0x0,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002078 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
2079 0, 0, 0, 0, 0, 0, 0, 0, /* insert SAS addr */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002080 0x3, 0, 0, 0, 0, 0, 0, 0,
2081 0x88, 0x99, 0, 0, 0, 0, 0, 0,
2082 0, 0, 0, 0, 0, 0, 0, 0,
2083 };
2084 int port_a, port_b;
2085
Douglas Gilbert1b37bd62016-05-06 00:40:29 -04002086 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 16);
2087 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 24);
2088 put_unaligned_be64(naa3_comp_a, sas_pcd_m_pg + 64);
2089 put_unaligned_be64(naa3_comp_c + 1, sas_pcd_m_pg + 72);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002090 port_a = target_dev_id + 1;
2091 port_b = port_a + 1;
2092 memcpy(p, sas_pcd_m_pg, sizeof(sas_pcd_m_pg));
Douglas Gilbert773642d2016-04-25 12:16:28 -04002093 put_unaligned_be32(port_a, p + 20);
2094 put_unaligned_be32(port_b, p + 48 + 20);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002095 if (1 == pcontrol)
2096 memset(p + 4, 0, sizeof(sas_pcd_m_pg) - 4);
2097 return sizeof(sas_pcd_m_pg);
2098}
2099
John Pittman91d4c752018-02-09 21:12:43 -05002100static int resp_sas_sha_m_spg(unsigned char *p, int pcontrol)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002101{ /* SAS SSP shared protocol specific port mode subpage */
2102 unsigned char sas_sha_m_pg[] = {0x59, 0x2, 0, 0xc, 0, 0x6, 0x10, 0,
2103 0, 0, 0, 0, 0, 0, 0, 0,
2104 };
2105
2106 memcpy(p, sas_sha_m_pg, sizeof(sas_sha_m_pg));
2107 if (1 == pcontrol)
2108 memset(p + 4, 0, sizeof(sas_sha_m_pg) - 4);
2109 return sizeof(sas_sha_m_pg);
2110}
2111
Linus Torvalds1da177e2005-04-16 15:20:36 -07002112#define SDEBUG_MAX_MSENSE_SZ 256
2113
Douglas Gilbertfd321192016-04-25 12:16:33 -04002114static int resp_mode_sense(struct scsi_cmnd *scp,
2115 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116{
Douglas Gilbert23183912006-09-16 20:30:47 -04002117 int pcontrol, pcode, subpcode, bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002118 unsigned char dev_spec;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002119 int alloc_len, offset, len, target_dev_id;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002120 int target = scp->device->id;
John Pittman91d4c752018-02-09 21:12:43 -05002121 unsigned char *ap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002123 unsigned char *cmd = scp->cmnd;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002124 bool dbd, llbaa, msense_6, is_disk, bad_pcode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002125
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002126 dbd = !!(cmd[1] & 0x8); /* disable block descriptors */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 pcontrol = (cmd[2] & 0xc0) >> 6;
2128 pcode = cmd[2] & 0x3f;
2129 subpcode = cmd[3];
2130 msense_6 = (MODE_SENSE == cmd[0]);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002131 llbaa = msense_6 ? false : !!(cmd[1] & 0x10);
2132 is_disk = (sdebug_ptype == TYPE_DISK);
2133 if (is_disk && !dbd)
Douglas Gilbert23183912006-09-16 20:30:47 -04002134 bd_len = llbaa ? 16 : 8;
2135 else
2136 bd_len = 0;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002137 alloc_len = msense_6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002138 memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
2139 if (0x3 == pcontrol) { /* Saving values not supported */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002140 mk_sense_buffer(scp, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 return check_condition_result;
2142 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002143 target_dev_id = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
2144 (devip->target * 1000) - 3;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002145 /* for disks set DPOFUA bit and clear write protect (WP) bit */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002146 if (is_disk)
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04002147 dev_spec = 0x10; /* =0x90 if WP=1 implies read-only */
Douglas Gilbert23183912006-09-16 20:30:47 -04002148 else
2149 dev_spec = 0x0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002150 if (msense_6) {
2151 arr[2] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002152 arr[3] = bd_len;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002153 offset = 4;
2154 } else {
2155 arr[3] = dev_spec;
Douglas Gilbert23183912006-09-16 20:30:47 -04002156 if (16 == bd_len)
2157 arr[4] = 0x1; /* set LONGLBA bit */
2158 arr[7] = bd_len; /* assume 255 or less */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002159 offset = 8;
2160 }
2161 ap = arr + offset;
FUJITA Tomonori28898872008-03-30 00:59:55 +09002162 if ((bd_len > 0) && (!sdebug_capacity))
2163 sdebug_capacity = get_sdebug_capacity();
2164
Douglas Gilbert23183912006-09-16 20:30:47 -04002165 if (8 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002166 if (sdebug_capacity > 0xfffffffe)
2167 put_unaligned_be32(0xffffffff, ap + 0);
2168 else
2169 put_unaligned_be32(sdebug_capacity, ap + 0);
2170 put_unaligned_be16(sdebug_sector_size, ap + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002171 offset += bd_len;
2172 ap = arr + offset;
2173 } else if (16 == bd_len) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002174 put_unaligned_be64((u64)sdebug_capacity, ap + 0);
2175 put_unaligned_be32(sdebug_sector_size, ap + 12);
Douglas Gilbert23183912006-09-16 20:30:47 -04002176 offset += bd_len;
2177 ap = arr + offset;
2178 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002180 if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
2181 /* TODO: Control Extension page */
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002182 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002183 return check_condition_result;
2184 }
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002185 bad_pcode = false;
2186
Linus Torvalds1da177e2005-04-16 15:20:36 -07002187 switch (pcode) {
2188 case 0x1: /* Read-Write error recovery page, direct access */
2189 len = resp_err_recov_pg(ap, pcontrol, target);
2190 offset += len;
2191 break;
2192 case 0x2: /* Disconnect-Reconnect page, all devices */
2193 len = resp_disconnect_pg(ap, pcontrol, target);
2194 offset += len;
2195 break;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002196 case 0x3: /* Format device page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002197 if (is_disk) {
2198 len = resp_format_pg(ap, pcontrol, target);
2199 offset += len;
2200 } else
2201 bad_pcode = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002202 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002203 case 0x8: /* Caching page, direct access */
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002204 if (is_disk) {
2205 len = resp_caching_pg(ap, pcontrol, target);
2206 offset += len;
2207 } else
2208 bad_pcode = true;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002209 break;
2210 case 0xa: /* Control Mode page, all devices */
2211 len = resp_ctrl_m_pg(ap, pcontrol, target);
2212 offset += len;
2213 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002214 case 0x19: /* if spc==1 then sas phy, control+discover */
2215 if ((subpcode > 0x2) && (subpcode < 0xff)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002216 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002217 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002218 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002219 len = 0;
2220 if ((0x0 == subpcode) || (0xff == subpcode))
2221 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2222 if ((0x1 == subpcode) || (0xff == subpcode))
2223 len += resp_sas_pcd_m_spg(ap + len, pcontrol, target,
2224 target_dev_id);
2225 if ((0x2 == subpcode) || (0xff == subpcode))
2226 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2227 offset += len;
2228 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002229 case 0x1c: /* Informational Exceptions Mode page, all devices */
2230 len = resp_iec_m_pg(ap, pcontrol, target);
2231 offset += len;
2232 break;
2233 case 0x3f: /* Read all Mode pages */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002234 if ((0 == subpcode) || (0xff == subpcode)) {
2235 len = resp_err_recov_pg(ap, pcontrol, target);
2236 len += resp_disconnect_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002237 if (is_disk) {
2238 len += resp_format_pg(ap + len, pcontrol,
2239 target);
2240 len += resp_caching_pg(ap + len, pcontrol,
2241 target);
2242 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002243 len += resp_ctrl_m_pg(ap + len, pcontrol, target);
2244 len += resp_sas_sf_m_pg(ap + len, pcontrol, target);
2245 if (0xff == subpcode) {
2246 len += resp_sas_pcd_m_spg(ap + len, pcontrol,
2247 target, target_dev_id);
2248 len += resp_sas_sha_m_spg(ap + len, pcontrol);
2249 }
2250 len += resp_iec_m_pg(ap + len, pcontrol, target);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002251 offset += len;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002252 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002253 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002254 return check_condition_result;
Douglas Gilbert9a051012017-12-23 12:48:10 -05002255 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002256 break;
2257 default:
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002258 bad_pcode = true;
2259 break;
2260 }
2261 if (bad_pcode) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002262 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002263 return check_condition_result;
2264 }
2265 if (msense_6)
2266 arr[0] = offset - 1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002267 else
2268 put_unaligned_be16((offset - 2), arr + 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
2270}
2271
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002272#define SDEBUG_MAX_MSELECT_SZ 512
2273
Douglas Gilbertfd321192016-04-25 12:16:33 -04002274static int resp_mode_select(struct scsi_cmnd *scp,
2275 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002276{
2277 int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002278 int param_len, res, mpage;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002279 unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002280 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002281 int mselect6 = (MODE_SELECT == cmd[0]);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002282
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002283 memset(arr, 0, sizeof(arr));
2284 pf = cmd[1] & 0x10;
2285 sp = cmd[1] & 0x1;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002286 param_len = mselect6 ? cmd[4] : get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002287 if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002288 mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002289 return check_condition_result;
2290 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002291 res = fetch_to_dev_buffer(scp, arr, param_len);
2292 if (-1 == res)
Douglas Gilbert773642d2016-04-25 12:16:28 -04002293 return DID_ERROR << 16;
2294 else if (sdebug_verbose && (res < param_len))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002295 sdev_printk(KERN_INFO, scp->device,
2296 "%s: cdb indicated=%d, IO sent=%d bytes\n",
2297 __func__, param_len, res);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002298 md_len = mselect6 ? (arr[0] + 1) : (get_unaligned_be16(arr + 0) + 2);
2299 bd_len = mselect6 ? arr[3] : get_unaligned_be16(arr + 6);
Douglas Gilbert23183912006-09-16 20:30:47 -04002300 if (md_len > 2) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002301 mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002302 return check_condition_result;
2303 }
2304 off = bd_len + (mselect6 ? 4 : 8);
2305 mpage = arr[off] & 0x3f;
2306 ps = !!(arr[off] & 0x80);
2307 if (ps) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002308 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002309 return check_condition_result;
2310 }
2311 spf = !!(arr[off] & 0x40);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002312 pg_len = spf ? (get_unaligned_be16(arr + off + 2) + 4) :
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002313 (arr[off + 1] + 2);
2314 if ((pg_len + off) > param_len) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002315 mk_sense_buffer(scp, ILLEGAL_REQUEST,
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002316 PARAMETER_LIST_LENGTH_ERR, 0);
2317 return check_condition_result;
2318 }
2319 switch (mpage) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002320 case 0x8: /* Caching Mode page */
2321 if (caching_pg[1] == arr[off + 1]) {
2322 memcpy(caching_pg + 2, arr + off + 2,
2323 sizeof(caching_pg) - 2);
2324 goto set_mode_changed_ua;
2325 }
2326 break;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002327 case 0xa: /* Control Mode page */
2328 if (ctrl_m_pg[1] == arr[off + 1]) {
2329 memcpy(ctrl_m_pg + 2, arr + off + 2,
2330 sizeof(ctrl_m_pg) - 2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002331 sdebug_dsense = !!(ctrl_m_pg[2] & 0x4);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002332 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002333 }
2334 break;
2335 case 0x1c: /* Informational Exceptions Mode page */
2336 if (iec_m_pg[1] == arr[off + 1]) {
2337 memcpy(iec_m_pg + 2, arr + off + 2,
2338 sizeof(iec_m_pg) - 2);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002339 goto set_mode_changed_ua;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002340 }
2341 break;
2342 default:
2343 break;
2344 }
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002345 mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002346 return check_condition_result;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002347set_mode_changed_ua:
2348 set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
2349 return 0;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002350}
2351
John Pittman91d4c752018-02-09 21:12:43 -05002352static int resp_temp_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002353{
2354 unsigned char temp_l_pg[] = {0x0, 0x0, 0x3, 0x2, 0x0, 38,
2355 0x0, 0x1, 0x3, 0x2, 0x0, 65,
2356 };
2357
Douglas Gilbert9a051012017-12-23 12:48:10 -05002358 memcpy(arr, temp_l_pg, sizeof(temp_l_pg));
2359 return sizeof(temp_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002360}
2361
John Pittman91d4c752018-02-09 21:12:43 -05002362static int resp_ie_l_pg(unsigned char *arr)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002363{
2364 unsigned char ie_l_pg[] = {0x0, 0x0, 0x3, 0x3, 0x0, 0x0, 38,
2365 };
2366
Douglas Gilbert9a051012017-12-23 12:48:10 -05002367 memcpy(arr, ie_l_pg, sizeof(ie_l_pg));
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002368 if (iec_m_pg[2] & 0x4) { /* TEST bit set */
2369 arr[4] = THRESHOLD_EXCEEDED;
2370 arr[5] = 0xff;
2371 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05002372 return sizeof(ie_l_pg);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002373}
2374
2375#define SDEBUG_MAX_LSENSE_SZ 512
2376
Douglas Gilbert9a051012017-12-23 12:48:10 -05002377static int resp_log_sense(struct scsi_cmnd *scp,
2378 struct sdebug_dev_info *devip)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002379{
Bart Van Asscheab172412017-08-25 13:46:42 -07002380 int ppc, sp, pcode, subpcode, alloc_len, len, n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002381 unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
Douglas Gilbert01123ef2014-08-05 12:20:02 +02002382 unsigned char *cmd = scp->cmnd;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002383
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002384 memset(arr, 0, sizeof(arr));
2385 ppc = cmd[1] & 0x2;
2386 sp = cmd[1] & 0x1;
2387 if (ppc || sp) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002388 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002389 return check_condition_result;
2390 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002391 pcode = cmd[2] & 0x3f;
Douglas Gilbert23183912006-09-16 20:30:47 -04002392 subpcode = cmd[3] & 0xff;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002393 alloc_len = get_unaligned_be16(cmd + 7);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002394 arr[0] = pcode;
Douglas Gilbert23183912006-09-16 20:30:47 -04002395 if (0 == subpcode) {
2396 switch (pcode) {
2397 case 0x0: /* Supported log pages log page */
2398 n = 4;
2399 arr[n++] = 0x0; /* this page */
2400 arr[n++] = 0xd; /* Temperature */
2401 arr[n++] = 0x2f; /* Informational exceptions */
2402 arr[3] = n - 4;
2403 break;
2404 case 0xd: /* Temperature log page */
2405 arr[3] = resp_temp_l_pg(arr + 4);
2406 break;
2407 case 0x2f: /* Informational exceptions log page */
2408 arr[3] = resp_ie_l_pg(arr + 4);
2409 break;
2410 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002411 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002412 return check_condition_result;
2413 }
2414 } else if (0xff == subpcode) {
2415 arr[0] |= 0x40;
2416 arr[1] = subpcode;
2417 switch (pcode) {
2418 case 0x0: /* Supported log pages and subpages log page */
2419 n = 4;
2420 arr[n++] = 0x0;
2421 arr[n++] = 0x0; /* 0,0 page */
2422 arr[n++] = 0x0;
2423 arr[n++] = 0xff; /* this page */
2424 arr[n++] = 0xd;
2425 arr[n++] = 0x0; /* Temperature */
2426 arr[n++] = 0x2f;
2427 arr[n++] = 0x0; /* Informational exceptions */
2428 arr[3] = n - 4;
2429 break;
2430 case 0xd: /* Temperature subpages */
2431 n = 4;
2432 arr[n++] = 0xd;
2433 arr[n++] = 0x0; /* Temperature */
2434 arr[3] = n - 4;
2435 break;
2436 case 0x2f: /* Informational exceptions subpages */
2437 n = 4;
2438 arr[n++] = 0x2f;
2439 arr[n++] = 0x0; /* Informational exceptions */
2440 arr[3] = n - 4;
2441 break;
2442 default:
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002443 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
Douglas Gilbert23183912006-09-16 20:30:47 -04002444 return check_condition_result;
2445 }
2446 } else {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002447 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002448 return check_condition_result;
2449 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04002450 len = min(get_unaligned_be16(arr + 2) + 4, alloc_len);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002451 return fill_from_dev_buffer(scp, arr,
2452 min(len, SDEBUG_MAX_INQ_ARR_SZ));
2453}
2454
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002455static int check_device_access_params(struct scsi_cmnd *scp,
FUJITA Tomonori19789102008-03-30 00:59:56 +09002456 unsigned long long lba, unsigned int num)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002457{
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002458 if (lba + num > sdebug_capacity) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002459 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002460 return check_condition_result;
2461 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002462 /* transfer length excessive (tie in to block limits VPD page) */
2463 if (num > sdebug_store_sectors) {
Douglas Gilbert22017ed2014-11-24 23:04:47 -05002464 /* needs work to find which cdb byte 'num' comes from */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002465 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002466 return check_condition_result;
2467 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002468 return 0;
2469}
2470
Akinobu Mitaa4517512013-07-08 16:01:57 -07002471/* Returns number of bytes copied or -1 if error. */
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002472static int do_device_access(struct scsi_cmnd *scmd, u32 sg_skip, u64 lba,
2473 u32 num, bool do_write)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002474{
2475 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002476 u64 block, rest = 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01002477 struct scsi_data_buffer *sdb = &scmd->sdb;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002478 enum dma_data_direction dir;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002479
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002480 if (do_write) {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002481 dir = DMA_TO_DEVICE;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04002482 write_since_sync = true;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002483 } else {
Akinobu Mitaa4517512013-07-08 16:01:57 -07002484 dir = DMA_FROM_DEVICE;
Akinobu Mitaa4517512013-07-08 16:01:57 -07002485 }
2486
2487 if (!sdb->length)
2488 return 0;
Christoph Hellwigae3d56d2019-01-29 09:33:07 +01002489 if (scmd->sc_data_direction != dir)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002490 return -1;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002491
2492 block = do_div(lba, sdebug_store_sectors);
2493 if (block + num > sdebug_store_sectors)
2494 rest = block + num - sdebug_store_sectors;
2495
Dave Gordon386ecb12015-06-30 14:58:57 -07002496 ret = sg_copy_buffer(sdb->table.sgl, sdb->table.nents,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002497 fake_storep + (block * sdebug_sector_size),
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002498 (num - rest) * sdebug_sector_size, sg_skip, do_write);
Douglas Gilbert773642d2016-04-25 12:16:28 -04002499 if (ret != (num - rest) * sdebug_sector_size)
Akinobu Mitaa4517512013-07-08 16:01:57 -07002500 return ret;
2501
2502 if (rest) {
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, rest * sdebug_sector_size,
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002505 sg_skip + ((num - rest) * sdebug_sector_size),
2506 do_write);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002507 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002508
2509 return ret;
2510}
2511
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002512/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
2513 * arr into fake_store(lba,num) and return true. If comparison fails then
2514 * return false. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04002515static bool comp_write_worker(u64 lba, u32 num, const u8 *arr)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002516{
2517 bool res;
2518 u64 block, rest = 0;
2519 u32 store_blks = sdebug_store_sectors;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002520 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05002521
2522 block = do_div(lba, store_blks);
2523 if (block + num > store_blks)
2524 rest = block + num - store_blks;
2525
2526 res = !memcmp(fake_storep + (block * lb_size), arr,
2527 (num - rest) * lb_size);
2528 if (!res)
2529 return res;
2530 if (rest)
2531 res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
2532 rest * lb_size);
2533 if (!res)
2534 return res;
2535 arr += num * lb_size;
2536 memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
2537 if (rest)
2538 memcpy(fake_storep, arr + ((num - rest) * lb_size),
2539 rest * lb_size);
2540 return res;
2541}
2542
Akinobu Mita51d648a2013-09-18 21:27:28 +09002543static __be16 dif_compute_csum(const void *buf, int len)
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002544{
Akinobu Mita51d648a2013-09-18 21:27:28 +09002545 __be16 csum;
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002546
Douglas Gilbert773642d2016-04-25 12:16:28 -04002547 if (sdebug_guard)
Akinobu Mita51d648a2013-09-18 21:27:28 +09002548 csum = (__force __be16)ip_compute_csum(buf, len);
2549 else
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002550 csum = cpu_to_be16(crc_t10dif(buf, len));
Akinobu Mita51d648a2013-09-18 21:27:28 +09002551
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002552 return csum;
2553}
2554
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002555static int dif_verify(struct t10_pi_tuple *sdt, const void *data,
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002556 sector_t sector, u32 ei_lba)
2557{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002558 __be16 csum = dif_compute_csum(data, sdebug_sector_size);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002559
2560 if (sdt->guard_tag != csum) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002561 pr_err("GUARD check failed on sector %lu rcvd 0x%04x, data 0x%04x\n",
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002562 (unsigned long)sector,
2563 be16_to_cpu(sdt->guard_tag),
2564 be16_to_cpu(csum));
2565 return 0x01;
2566 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002567 if (sdebug_dif == T10_PI_TYPE1_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002568 be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002569 pr_err("REF check failed on sector %lu\n",
2570 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002571 return 0x03;
2572 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002573 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002574 be32_to_cpu(sdt->ref_tag) != ei_lba) {
Tomas Winklerc12879702015-07-28 16:54:20 +03002575 pr_err("REF check failed on sector %lu\n",
2576 (unsigned long)sector);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002577 return 0x03;
2578 }
2579 return 0;
2580}
2581
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002582static void dif_copy_prot(struct scsi_cmnd *SCpnt, sector_t sector,
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002583 unsigned int sectors, bool read)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002584{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002585 size_t resid;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002586 void *paddr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002587 const void *dif_store_end = dif_storep + sdebug_store_sectors;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002588 struct sg_mapping_iter miter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002589
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002590 /* Bytes of protection data to copy into sgl */
2591 resid = sectors * sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002592
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002593 sg_miter_start(&miter, scsi_prot_sglist(SCpnt),
2594 scsi_prot_sg_count(SCpnt), SG_MITER_ATOMIC |
2595 (read ? SG_MITER_TO_SG : SG_MITER_FROM_SG));
2596
2597 while (sg_miter_next(&miter) && resid > 0) {
2598 size_t len = min(miter.length, resid);
Akinobu Mita14faa942013-09-18 21:27:24 +09002599 void *start = dif_store(sector);
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002600 size_t rest = 0;
Akinobu Mita14faa942013-09-18 21:27:24 +09002601
2602 if (dif_store_end < start + len)
2603 rest = start + len - dif_store_end;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002604
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002605 paddr = miter.addr;
Akinobu Mita14faa942013-09-18 21:27:24 +09002606
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002607 if (read)
2608 memcpy(paddr, start, len - rest);
2609 else
2610 memcpy(start, paddr, len - rest);
2611
2612 if (rest) {
2613 if (read)
2614 memcpy(paddr + len - rest, dif_storep, rest);
2615 else
2616 memcpy(dif_storep, paddr + len - rest, rest);
2617 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002618
Akinobu Mitae18d8be2013-06-29 17:59:18 +09002619 sector += len / sizeof(*dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002620 resid -= len;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002621 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002622 sg_miter_stop(&miter);
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002623}
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002624
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002625static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
2626 unsigned int sectors, u32 ei_lba)
2627{
2628 unsigned int i;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002629 struct t10_pi_tuple *sdt;
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002630 sector_t sector;
2631
Akinobu Mitac45eabec2014-02-26 22:56:58 +09002632 for (i = 0; i < sectors; i++, ei_lba++) {
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002633 int ret;
2634
2635 sector = start_sec + i;
2636 sdt = dif_store(sector);
2637
Akinobu Mita51d648a2013-09-18 21:27:28 +09002638 if (sdt->app_tag == cpu_to_be16(0xffff))
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002639 continue;
2640
2641 ret = dif_verify(sdt, fake_store(sector), sector, ei_lba);
2642 if (ret) {
2643 dif_errors++;
2644 return ret;
2645 }
Akinobu Mitabb8c0632013-09-18 21:27:25 +09002646 }
2647
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002648 dif_copy_prot(SCpnt, start_sec, sectors, true);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002649 dix_reads++;
2650
2651 return 0;
2652}
2653
Douglas Gilbertfd321192016-04-25 12:16:33 -04002654static int resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
FUJITA Tomonori19789102008-03-30 00:59:56 +09002655{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002656 u8 *cmd = scp->cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002657 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002658 u64 lba;
2659 u32 num;
2660 u32 ei_lba;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002661 unsigned long iflags;
2662 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002663 bool check_prot;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002664
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002665 switch (cmd[0]) {
2666 case READ_16:
2667 ei_lba = 0;
2668 lba = get_unaligned_be64(cmd + 2);
2669 num = get_unaligned_be32(cmd + 10);
2670 check_prot = true;
2671 break;
2672 case READ_10:
2673 ei_lba = 0;
2674 lba = get_unaligned_be32(cmd + 2);
2675 num = get_unaligned_be16(cmd + 7);
2676 check_prot = true;
2677 break;
2678 case READ_6:
2679 ei_lba = 0;
2680 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2681 (u32)(cmd[1] & 0x1f) << 16;
2682 num = (0 == cmd[4]) ? 256 : cmd[4];
2683 check_prot = true;
2684 break;
2685 case READ_12:
2686 ei_lba = 0;
2687 lba = get_unaligned_be32(cmd + 2);
2688 num = get_unaligned_be32(cmd + 6);
2689 check_prot = true;
2690 break;
2691 case XDWRITEREAD_10:
2692 ei_lba = 0;
2693 lba = get_unaligned_be32(cmd + 2);
2694 num = get_unaligned_be16(cmd + 7);
2695 check_prot = false;
2696 break;
2697 default: /* assume READ(32) */
2698 lba = get_unaligned_be64(cmd + 12);
2699 ei_lba = get_unaligned_be32(cmd + 20);
2700 num = get_unaligned_be32(cmd + 28);
2701 check_prot = false;
2702 break;
2703 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002704 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02002705 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002706 (cmd[1] & 0xe0)) {
2707 mk_sense_invalid_opcode(scp);
2708 return check_condition_result;
2709 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02002710 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
2711 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002712 (cmd[1] & 0xe0) == 0)
2713 sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
2714 "to DIF device\n");
2715 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002716 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04002717 sqcp = (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002718
Douglas Gilbertc4837392016-05-06 00:40:26 -04002719 if (sqcp) {
2720 if (sqcp->inj_short)
2721 num /= 2;
2722 }
2723 } else
2724 sqcp = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002725
2726 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002727 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002728 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
2729 return check_condition_result;
2730 }
2731 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002732 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002733 /* needs work to find which cdb byte 'num' comes from */
2734 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
2735 return check_condition_result;
2736 }
FUJITA Tomonori19789102008-03-30 00:59:56 +09002737
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002738 if (unlikely((SDEBUG_OPT_MEDIUM_ERR & sdebug_opts) &&
Laurence Obermand9da8912018-02-03 13:38:35 -05002739 (lba <= (sdebug_medium_error_start + sdebug_medium_error_count - 1)) &&
2740 ((lba + num) > sdebug_medium_error_start))) {
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002741 /* claim unrecoverable read error */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002742 mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002743 /* set info field and valid bit for fixed descriptor */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002744 if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
2745 scp->sense_buffer[0] |= 0x80; /* Valid bit */
Douglas Gilbert32f7ef72011-03-11 10:43:35 -05002746 ret = (lba < OPT_MEDIUM_ERR_ADDR)
2747 ? OPT_MEDIUM_ERR_ADDR : (int)lba;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002748 put_unaligned_be32(ret, scp->sense_buffer + 3);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04002749 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002750 scsi_set_resid(scp, scsi_bufflen(scp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002751 return check_condition_result;
2752 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002753
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002754 read_lock_irqsave(&atomic_rw, iflags);
2755
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002756 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002757 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002758 int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002759
2760 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09002761 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002762 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002763 return illegal_condition_result;
2764 }
2765 }
2766
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05002767 ret = do_device_access(scp, 0, lba, num, false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 read_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04002769 if (unlikely(ret == -1))
Akinobu Mitaa4517512013-07-08 16:01:57 -07002770 return DID_ERROR << 16;
2771
Bart Van Assche42d387b2019-02-08 13:25:00 -08002772 scsi_set_resid(scp, scsi_bufflen(scp) - ret);
Akinobu Mitaa4517512013-07-08 16:01:57 -07002773
Douglas Gilbertc4837392016-05-06 00:40:26 -04002774 if (unlikely(sqcp)) {
2775 if (sqcp->inj_recovered) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002776 mk_sense_buffer(scp, RECOVERED_ERROR,
2777 THRESHOLD_EXCEEDED, 0);
2778 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002779 } else if (sqcp->inj_transport) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002780 mk_sense_buffer(scp, ABORTED_COMMAND,
2781 TRANSPORT_PROBLEM, ACK_NAK_TO);
2782 return check_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002783 } else if (sqcp->inj_dif) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002784 /* Logical block guard check failed */
2785 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
2786 return illegal_condition_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04002787 } else if (sqcp->inj_dix) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002788 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
2789 return illegal_condition_result;
2790 }
2791 }
Akinobu Mitaa4517512013-07-08 16:01:57 -07002792 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793}
2794
Tomas Winkler58a86352015-07-28 16:54:23 +03002795static void dump_sector(unsigned char *buf, int len)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002796{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002797 int i, j, n;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002798
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002799 pr_err(">>> Sector Dump <<<\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002800 for (i = 0 ; i < len ; i += 16) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002801 char b[128];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002802
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002803 for (j = 0, n = 0; j < 16; j++) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002804 unsigned char c = buf[i+j];
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002805
Douglas Gilbertcbf67842014-07-26 11:55:35 -04002806 if (c >= 0x20 && c < 0x7e)
2807 n += scnprintf(b + n, sizeof(b) - n,
2808 " %c ", buf[i+j]);
2809 else
2810 n += scnprintf(b + n, sizeof(b) - n,
2811 "%02x ", buf[i+j]);
2812 }
2813 pr_err("%04d: %s\n", i, b);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002814 }
2815}
2816
2817static int prot_verify_write(struct scsi_cmnd *SCpnt, sector_t start_sec,
Martin K. Petersen395cef02009-09-18 17:33:03 -04002818 unsigned int sectors, u32 ei_lba)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002819{
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002820 int ret;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002821 struct t10_pi_tuple *sdt;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002822 void *daddr;
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002823 sector_t sector = start_sec;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002824 int ppage_offset;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002825 int dpage_offset;
2826 struct sg_mapping_iter diter;
2827 struct sg_mapping_iter piter;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002828
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002829 BUG_ON(scsi_sg_count(SCpnt) == 0);
2830 BUG_ON(scsi_prot_sg_count(SCpnt) == 0);
2831
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002832 sg_miter_start(&piter, scsi_prot_sglist(SCpnt),
2833 scsi_prot_sg_count(SCpnt),
2834 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
2835 sg_miter_start(&diter, scsi_sglist(SCpnt), scsi_sg_count(SCpnt),
2836 SG_MITER_ATOMIC | SG_MITER_FROM_SG);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002837
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002838 /* For each protection page */
2839 while (sg_miter_next(&piter)) {
2840 dpage_offset = 0;
2841 if (WARN_ON(!sg_miter_next(&diter))) {
2842 ret = 0x01;
2843 goto out;
2844 }
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002845
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002846 for (ppage_offset = 0; ppage_offset < piter.length;
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02002847 ppage_offset += sizeof(struct t10_pi_tuple)) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002848 /* If we're at the end of the current
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002849 * data page advance to the next one
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002850 */
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002851 if (dpage_offset >= diter.length) {
2852 if (WARN_ON(!sg_miter_next(&diter))) {
2853 ret = 0x01;
2854 goto out;
2855 }
2856 dpage_offset = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002857 }
2858
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002859 sdt = piter.addr + ppage_offset;
2860 daddr = diter.addr + dpage_offset;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002861
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002862 ret = dif_verify(sdt, daddr, sector, ei_lba);
Akinobu Mitabeb40ea2013-06-29 17:59:19 +09002863 if (ret) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04002864 dump_sector(daddr, sdebug_sector_size);
Martin K. Petersen395cef02009-09-18 17:33:03 -04002865 goto out;
2866 }
2867
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002868 sector++;
Martin K. Petersen395cef02009-09-18 17:33:03 -04002869 ei_lba++;
Douglas Gilbert773642d2016-04-25 12:16:28 -04002870 dpage_offset += sdebug_sector_size;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002871 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002872 diter.consumed = dpage_offset;
2873 sg_miter_stop(&diter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002874 }
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002875 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002876
Akinobu Mita65f72f2a2013-09-18 21:27:26 +09002877 dif_copy_prot(SCpnt, start_sec, sectors, false);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002878 dix_writes++;
2879
2880 return 0;
2881
2882out:
2883 dif_errors++;
Akinobu Mitabe4e11b2014-02-26 22:57:02 +09002884 sg_miter_stop(&diter);
2885 sg_miter_stop(&piter);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05002886 return ret;
2887}
2888
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002889static unsigned long lba_to_map_index(sector_t lba)
2890{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002891 if (sdebug_unmap_alignment)
2892 lba += sdebug_unmap_granularity - sdebug_unmap_alignment;
2893 sector_div(lba, sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002894 return lba;
2895}
2896
2897static sector_t map_index_to_lba(unsigned long index)
2898{
Douglas Gilbert773642d2016-04-25 12:16:28 -04002899 sector_t lba = index * sdebug_unmap_granularity;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002900
Douglas Gilbert773642d2016-04-25 12:16:28 -04002901 if (sdebug_unmap_alignment)
2902 lba -= sdebug_unmap_granularity - sdebug_unmap_alignment;
Akinobu Mitaa027b5b2013-08-26 22:08:41 +09002903 return lba;
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002904}
2905
Martin K. Petersen44d92692009-10-15 14:45:27 -04002906static unsigned int map_state(sector_t lba, unsigned int *num)
2907{
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002908 sector_t end;
2909 unsigned int mapped;
2910 unsigned long index;
2911 unsigned long next;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002912
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002913 index = lba_to_map_index(lba);
2914 mapped = test_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002915
2916 if (mapped)
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002917 next = find_next_zero_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002918 else
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002919 next = find_next_bit(map_storep, map_size, index);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002920
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002921 end = min_t(sector_t, sdebug_store_sectors, map_index_to_lba(next));
Martin K. Petersen44d92692009-10-15 14:45:27 -04002922 *num = end - lba;
Martin K. Petersen44d92692009-10-15 14:45:27 -04002923 return mapped;
2924}
2925
2926static void map_region(sector_t lba, unsigned int len)
2927{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002928 sector_t end = lba + len;
2929
Martin K. Petersen44d92692009-10-15 14:45:27 -04002930 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002931 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002932
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002933 if (index < map_size)
2934 set_bit(index, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002935
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002936 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002937 }
2938}
2939
2940static void unmap_region(sector_t lba, unsigned int len)
2941{
Martin K. Petersen44d92692009-10-15 14:45:27 -04002942 sector_t end = lba + len;
2943
Martin K. Petersen44d92692009-10-15 14:45:27 -04002944 while (lba < end) {
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002945 unsigned long index = lba_to_map_index(lba);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002946
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002947 if (lba == map_index_to_lba(index) &&
Douglas Gilbert773642d2016-04-25 12:16:28 -04002948 lba + sdebug_unmap_granularity <= end &&
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002949 index < map_size) {
2950 clear_bit(index, map_storep);
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002951 if (sdebug_lbprz) { /* for LBPRZ=2 return 0xff_s */
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002952 memset(fake_storep +
Douglas Gilbert760f3b02016-05-06 00:40:27 -04002953 lba * sdebug_sector_size,
2954 (sdebug_lbprz & 1) ? 0 : 0xff,
Douglas Gilbert773642d2016-04-25 12:16:28 -04002955 sdebug_sector_size *
2956 sdebug_unmap_granularity);
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002957 }
Akinobu Mitae9926b42013-06-29 17:59:17 +09002958 if (dif_storep) {
2959 memset(dif_storep + lba, 0xff,
2960 sizeof(*dif_storep) *
Douglas Gilbert773642d2016-04-25 12:16:28 -04002961 sdebug_unmap_granularity);
Akinobu Mitae9926b42013-06-29 17:59:17 +09002962 }
Eric Sandeenbe1dd782012-03-08 00:03:59 -06002963 }
Akinobu Mitab90ebc32013-04-16 22:11:58 +09002964 lba = map_index_to_lba(index + 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04002965 }
2966}
2967
Douglas Gilbertfd321192016-04-25 12:16:33 -04002968static int resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002969{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002970 u8 *cmd = scp->cmnd;
2971 u64 lba;
2972 u32 num;
2973 u32 ei_lba;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002974 unsigned long iflags;
FUJITA Tomonori19789102008-03-30 00:59:56 +09002975 int ret;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002976 bool check_prot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002977
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05002978 switch (cmd[0]) {
2979 case WRITE_16:
2980 ei_lba = 0;
2981 lba = get_unaligned_be64(cmd + 2);
2982 num = get_unaligned_be32(cmd + 10);
2983 check_prot = true;
2984 break;
2985 case WRITE_10:
2986 ei_lba = 0;
2987 lba = get_unaligned_be32(cmd + 2);
2988 num = get_unaligned_be16(cmd + 7);
2989 check_prot = true;
2990 break;
2991 case WRITE_6:
2992 ei_lba = 0;
2993 lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
2994 (u32)(cmd[1] & 0x1f) << 16;
2995 num = (0 == cmd[4]) ? 256 : cmd[4];
2996 check_prot = true;
2997 break;
2998 case WRITE_12:
2999 ei_lba = 0;
3000 lba = get_unaligned_be32(cmd + 2);
3001 num = get_unaligned_be32(cmd + 6);
3002 check_prot = true;
3003 break;
3004 case 0x53: /* XDWRITEREAD(10) */
3005 ei_lba = 0;
3006 lba = get_unaligned_be32(cmd + 2);
3007 num = get_unaligned_be16(cmd + 7);
3008 check_prot = false;
3009 break;
3010 default: /* assume WRITE(32) */
3011 lba = get_unaligned_be64(cmd + 12);
3012 ei_lba = get_unaligned_be32(cmd + 20);
3013 num = get_unaligned_be32(cmd + 28);
3014 check_prot = false;
3015 break;
3016 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003017 if (unlikely(have_dif_prot && check_prot)) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02003018 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003019 (cmd[1] & 0xe0)) {
3020 mk_sense_invalid_opcode(scp);
3021 return check_condition_result;
3022 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003023 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3024 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003025 (cmd[1] & 0xe0) == 0)
3026 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3027 "to DIF device\n");
3028 }
3029
3030 /* inline check_device_access_params() */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003031 if (unlikely(lba + num > sdebug_capacity)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003032 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3033 return check_condition_result;
3034 }
3035 /* transfer length excessive (tie in to block limits VPD page) */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003036 if (unlikely(num > sdebug_store_sectors)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003037 /* needs work to find which cdb byte 'num' comes from */
3038 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3039 return check_condition_result;
3040 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003041
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003042 write_lock_irqsave(&atomic_rw, iflags);
3043
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003044 /* DIX + T10 DIF */
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003045 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003046 int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003047
3048 if (prot_ret) {
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003049 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003050 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05003051 return illegal_condition_result;
3052 }
3053 }
3054
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003055 ret = do_device_access(scp, 0, lba, num, true);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003056 if (unlikely(scsi_debug_lbp()))
Martin K. Petersen44d92692009-10-15 14:45:27 -04003057 map_region(lba, num);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003058 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003059 if (unlikely(-1 == ret))
Douglas Gilbert773642d2016-04-25 12:16:28 -04003060 return DID_ERROR << 16;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003061 else if (unlikely(sdebug_verbose &&
3062 (ret < (num * sdebug_sector_size))))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003063 sdev_printk(KERN_INFO, scp->device,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003064 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04003065 my_name, num * sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003066
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003067 if (unlikely(sdebug_any_injecting_opt)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003068 struct sdebug_queued_cmd *sqcp =
3069 (struct sdebug_queued_cmd *)scp->host_scribble;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003070
Douglas Gilbertc4837392016-05-06 00:40:26 -04003071 if (sqcp) {
3072 if (sqcp->inj_recovered) {
3073 mk_sense_buffer(scp, RECOVERED_ERROR,
3074 THRESHOLD_EXCEEDED, 0);
3075 return check_condition_result;
3076 } else if (sqcp->inj_dif) {
3077 /* Logical block guard check failed */
3078 mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
3079 return illegal_condition_result;
3080 } else if (sqcp->inj_dix) {
3081 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
3082 return illegal_condition_result;
3083 }
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003084 }
3085 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003086 return 0;
3087}
3088
Douglas Gilbert481b5e52017-12-23 12:48:14 -05003089/*
3090 * T10 has only specified WRITE SCATTERED(16) and WRITE SCATTERED(32).
3091 * No READ GATHERED yet (requires bidi or long cdb holding gather list).
3092 */
3093static int resp_write_scat(struct scsi_cmnd *scp,
3094 struct sdebug_dev_info *devip)
3095{
3096 u8 *cmd = scp->cmnd;
3097 u8 *lrdp = NULL;
3098 u8 *up;
3099 u8 wrprotect;
3100 u16 lbdof, num_lrd, k;
3101 u32 num, num_by, bt_len, lbdof_blen, sg_off, cum_lb;
3102 u32 lb_size = sdebug_sector_size;
3103 u32 ei_lba;
3104 u64 lba;
3105 unsigned long iflags;
3106 int ret, res;
3107 bool is_16;
3108 static const u32 lrd_size = 32; /* + parameter list header size */
3109
3110 if (cmd[0] == VARIABLE_LENGTH_CMD) {
3111 is_16 = false;
3112 wrprotect = (cmd[10] >> 5) & 0x7;
3113 lbdof = get_unaligned_be16(cmd + 12);
3114 num_lrd = get_unaligned_be16(cmd + 16);
3115 bt_len = get_unaligned_be32(cmd + 28);
3116 } else { /* that leaves WRITE SCATTERED(16) */
3117 is_16 = true;
3118 wrprotect = (cmd[2] >> 5) & 0x7;
3119 lbdof = get_unaligned_be16(cmd + 4);
3120 num_lrd = get_unaligned_be16(cmd + 8);
3121 bt_len = get_unaligned_be32(cmd + 10);
3122 if (unlikely(have_dif_prot)) {
3123 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
3124 wrprotect) {
3125 mk_sense_invalid_opcode(scp);
3126 return illegal_condition_result;
3127 }
3128 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3129 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
3130 wrprotect == 0)
3131 sdev_printk(KERN_ERR, scp->device,
3132 "Unprotected WR to DIF device\n");
3133 }
3134 }
3135 if ((num_lrd == 0) || (bt_len == 0))
3136 return 0; /* T10 says these do-nothings are not errors */
3137 if (lbdof == 0) {
3138 if (sdebug_verbose)
3139 sdev_printk(KERN_INFO, scp->device,
3140 "%s: %s: LB Data Offset field bad\n",
3141 my_name, __func__);
3142 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3143 return illegal_condition_result;
3144 }
3145 lbdof_blen = lbdof * lb_size;
3146 if ((lrd_size + (num_lrd * lrd_size)) > lbdof_blen) {
3147 if (sdebug_verbose)
3148 sdev_printk(KERN_INFO, scp->device,
3149 "%s: %s: LBA range descriptors don't fit\n",
3150 my_name, __func__);
3151 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3152 return illegal_condition_result;
3153 }
3154 lrdp = kzalloc(lbdof_blen, GFP_ATOMIC);
3155 if (lrdp == NULL)
3156 return SCSI_MLQUEUE_HOST_BUSY;
3157 if (sdebug_verbose)
3158 sdev_printk(KERN_INFO, scp->device,
3159 "%s: %s: Fetch header+scatter_list, lbdof_blen=%u\n",
3160 my_name, __func__, lbdof_blen);
3161 res = fetch_to_dev_buffer(scp, lrdp, lbdof_blen);
3162 if (res == -1) {
3163 ret = DID_ERROR << 16;
3164 goto err_out;
3165 }
3166
3167 write_lock_irqsave(&atomic_rw, iflags);
3168 sg_off = lbdof_blen;
3169 /* Spec says Buffer xfer Length field in number of LBs in dout */
3170 cum_lb = 0;
3171 for (k = 0, up = lrdp + lrd_size; k < num_lrd; ++k, up += lrd_size) {
3172 lba = get_unaligned_be64(up + 0);
3173 num = get_unaligned_be32(up + 8);
3174 if (sdebug_verbose)
3175 sdev_printk(KERN_INFO, scp->device,
3176 "%s: %s: k=%d LBA=0x%llx num=%u sg_off=%u\n",
3177 my_name, __func__, k, lba, num, sg_off);
3178 if (num == 0)
3179 continue;
3180 ret = check_device_access_params(scp, lba, num);
3181 if (ret)
3182 goto err_out_unlock;
3183 num_by = num * lb_size;
3184 ei_lba = is_16 ? 0 : get_unaligned_be32(up + 12);
3185
3186 if ((cum_lb + num) > bt_len) {
3187 if (sdebug_verbose)
3188 sdev_printk(KERN_INFO, scp->device,
3189 "%s: %s: sum of blocks > data provided\n",
3190 my_name, __func__);
3191 mk_sense_buffer(scp, ILLEGAL_REQUEST, WRITE_ERROR_ASC,
3192 0);
3193 ret = illegal_condition_result;
3194 goto err_out_unlock;
3195 }
3196
3197 /* DIX + T10 DIF */
3198 if (unlikely(sdebug_dix && scsi_prot_sg_count(scp))) {
3199 int prot_ret = prot_verify_write(scp, lba, num,
3200 ei_lba);
3201
3202 if (prot_ret) {
3203 mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10,
3204 prot_ret);
3205 ret = illegal_condition_result;
3206 goto err_out_unlock;
3207 }
3208 }
3209
3210 ret = do_device_access(scp, sg_off, lba, num, true);
3211 if (unlikely(scsi_debug_lbp()))
3212 map_region(lba, num);
3213 if (unlikely(-1 == ret)) {
3214 ret = DID_ERROR << 16;
3215 goto err_out_unlock;
3216 } else if (unlikely(sdebug_verbose && (ret < num_by)))
3217 sdev_printk(KERN_INFO, scp->device,
3218 "%s: write: cdb indicated=%u, IO sent=%d bytes\n",
3219 my_name, num_by, ret);
3220
3221 if (unlikely(sdebug_any_injecting_opt)) {
3222 struct sdebug_queued_cmd *sqcp =
3223 (struct sdebug_queued_cmd *)scp->host_scribble;
3224
3225 if (sqcp) {
3226 if (sqcp->inj_recovered) {
3227 mk_sense_buffer(scp, RECOVERED_ERROR,
3228 THRESHOLD_EXCEEDED, 0);
3229 ret = illegal_condition_result;
3230 goto err_out_unlock;
3231 } else if (sqcp->inj_dif) {
3232 /* Logical block guard check failed */
3233 mk_sense_buffer(scp, ABORTED_COMMAND,
3234 0x10, 1);
3235 ret = illegal_condition_result;
3236 goto err_out_unlock;
3237 } else if (sqcp->inj_dix) {
3238 mk_sense_buffer(scp, ILLEGAL_REQUEST,
3239 0x10, 1);
3240 ret = illegal_condition_result;
3241 goto err_out_unlock;
3242 }
3243 }
3244 }
3245 sg_off += num_by;
3246 cum_lb += num;
3247 }
3248 ret = 0;
3249err_out_unlock:
3250 write_unlock_irqrestore(&atomic_rw, iflags);
3251err_out:
3252 kfree(lrdp);
3253 return ret;
3254}
3255
Douglas Gilbertfd321192016-04-25 12:16:33 -04003256static int resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num,
3257 u32 ei_lba, bool unmap, bool ndob)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003258{
3259 unsigned long iflags;
3260 unsigned long long i;
3261 int ret;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003262 u64 lba_off;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003263
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003264 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003265 if (ret)
3266 return ret;
3267
3268 write_lock_irqsave(&atomic_rw, iflags);
3269
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003270 if (unmap && scsi_debug_lbp()) {
Martin K. Petersen44d92692009-10-15 14:45:27 -04003271 unmap_region(lba, num);
3272 goto out;
3273 }
3274
Douglas Gilbert773642d2016-04-25 12:16:28 -04003275 lba_off = lba * sdebug_sector_size;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003276 /* if ndob then zero 1 logical block, else fetch 1 logical block */
3277 if (ndob) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003278 memset(fake_storep + lba_off, 0, sdebug_sector_size);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003279 ret = 0;
3280 } else
Douglas Gilbert773642d2016-04-25 12:16:28 -04003281 ret = fetch_to_dev_buffer(scp, fake_storep + lba_off,
3282 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003283
3284 if (-1 == ret) {
3285 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003286 return DID_ERROR << 16;
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003287 } else if (sdebug_verbose && !ndob && (ret < sdebug_sector_size))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003288 sdev_printk(KERN_INFO, scp->device,
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003289 "%s: %s: lb size=%u, IO sent=%d bytes\n",
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003290 my_name, "write same",
Douglas Gilberte33d7c52017-10-29 10:47:19 -04003291 sdebug_sector_size, ret);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003292
3293 /* Copy first sector to remaining blocks */
3294 for (i = 1 ; i < num ; i++)
Douglas Gilbert773642d2016-04-25 12:16:28 -04003295 memcpy(fake_storep + ((lba + i) * sdebug_sector_size),
3296 fake_storep + lba_off,
3297 sdebug_sector_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003298
Akinobu Mita9ed8d3d2013-04-16 22:11:55 +09003299 if (scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04003300 map_region(lba, num);
3301out:
3302 write_unlock_irqrestore(&atomic_rw, iflags);
3303
3304 return 0;
3305}
3306
Douglas Gilbertfd321192016-04-25 12:16:33 -04003307static int resp_write_same_10(struct scsi_cmnd *scp,
3308 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003309{
3310 u8 *cmd = scp->cmnd;
3311 u32 lba;
3312 u16 num;
3313 u32 ei_lba = 0;
3314 bool unmap = false;
3315
3316 if (cmd[1] & 0x8) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04003317 if (sdebug_lbpws10 == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003318 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3319 return check_condition_result;
3320 } else
3321 unmap = true;
3322 }
3323 lba = get_unaligned_be32(cmd + 2);
3324 num = get_unaligned_be16(cmd + 7);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003325 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003326 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
3327 return check_condition_result;
3328 }
3329 return resp_write_same(scp, lba, num, ei_lba, unmap, false);
3330}
3331
Douglas Gilbertfd321192016-04-25 12:16:33 -04003332static int resp_write_same_16(struct scsi_cmnd *scp,
3333 struct sdebug_dev_info *devip)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003334{
3335 u8 *cmd = scp->cmnd;
3336 u64 lba;
3337 u32 num;
3338 u32 ei_lba = 0;
3339 bool unmap = false;
3340 bool ndob = false;
3341
3342 if (cmd[1] & 0x8) { /* UNMAP */
Douglas Gilbert773642d2016-04-25 12:16:28 -04003343 if (sdebug_lbpws == 0) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003344 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
3345 return check_condition_result;
3346 } else
3347 unmap = true;
3348 }
3349 if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
3350 ndob = true;
3351 lba = get_unaligned_be64(cmd + 2);
3352 num = get_unaligned_be32(cmd + 10);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003353 if (num > sdebug_write_same_length) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003354 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
3355 return check_condition_result;
3356 }
3357 return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
3358}
3359
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003360/* Note the mode field is in the same position as the (lower) service action
3361 * field. For the Report supported operation codes command, SPC-4 suggests
3362 * each mode of this command should be reported separately; for future. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003363static int resp_write_buffer(struct scsi_cmnd *scp,
3364 struct sdebug_dev_info *devip)
Ewan D. Milneacafd0b2014-12-04 11:49:28 -05003365{
3366 u8 *cmd = scp->cmnd;
3367 struct scsi_device *sdp = scp->device;
3368 struct sdebug_dev_info *dp;
3369 u8 mode;
3370
3371 mode = cmd[1] & 0x1f;
3372 switch (mode) {
3373 case 0x4: /* download microcode (MC) and activate (ACT) */
3374 /* set UAs on this device only */
3375 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
3376 set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
3377 break;
3378 case 0x5: /* download MC, save and ACT */
3379 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
3380 break;
3381 case 0x6: /* download MC with offsets and ACT */
3382 /* set UAs on most devices (LUs) in this target */
3383 list_for_each_entry(dp,
3384 &devip->sdbg_host->dev_info_list,
3385 dev_list)
3386 if (dp->target == sdp->id) {
3387 set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
3388 if (devip != dp)
3389 set_bit(SDEBUG_UA_MICROCODE_CHANGED,
3390 dp->uas_bm);
3391 }
3392 break;
3393 case 0x7: /* download MC with offsets, save, and ACT */
3394 /* set UA on all devices (LUs) in this target */
3395 list_for_each_entry(dp,
3396 &devip->sdbg_host->dev_info_list,
3397 dev_list)
3398 if (dp->target == sdp->id)
3399 set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
3400 dp->uas_bm);
3401 break;
3402 default:
3403 /* do nothing for this command for other mode values */
3404 break;
3405 }
3406 return 0;
3407}
3408
Douglas Gilbertfd321192016-04-25 12:16:33 -04003409static int resp_comp_write(struct scsi_cmnd *scp,
3410 struct sdebug_dev_info *devip)
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003411{
3412 u8 *cmd = scp->cmnd;
3413 u8 *arr;
3414 u8 *fake_storep_hold;
3415 u64 lba;
3416 u32 dnum;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003417 u32 lb_size = sdebug_sector_size;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003418 u8 num;
3419 unsigned long iflags;
3420 int ret;
Douglas Gilbertd467d312014-11-26 12:33:48 -05003421 int retval = 0;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003422
Douglas Gilbertd467d312014-11-26 12:33:48 -05003423 lba = get_unaligned_be64(cmd + 2);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003424 num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
3425 if (0 == num)
3426 return 0; /* degenerate case, not an error */
Christoph Hellwig8475c812016-09-11 19:35:41 +02003427 if (sdebug_dif == T10_PI_TYPE2_PROTECTION &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003428 (cmd[1] & 0xe0)) {
3429 mk_sense_invalid_opcode(scp);
3430 return check_condition_result;
3431 }
Christoph Hellwig8475c812016-09-11 19:35:41 +02003432 if ((sdebug_dif == T10_PI_TYPE1_PROTECTION ||
3433 sdebug_dif == T10_PI_TYPE3_PROTECTION) &&
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003434 (cmd[1] & 0xe0) == 0)
3435 sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
3436 "to DIF device\n");
3437
3438 /* inline check_device_access_params() */
3439 if (lba + num > sdebug_capacity) {
3440 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3441 return check_condition_result;
3442 }
3443 /* transfer length excessive (tie in to block limits VPD page) */
3444 if (num > sdebug_store_sectors) {
3445 /* needs work to find which cdb byte 'num' comes from */
3446 mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
3447 return check_condition_result;
3448 }
Douglas Gilbertd467d312014-11-26 12:33:48 -05003449 dnum = 2 * num;
Kees Cook6396bb22018-06-12 14:03:40 -07003450 arr = kcalloc(lb_size, dnum, GFP_ATOMIC);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003451 if (NULL == arr) {
3452 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3453 INSUFF_RES_ASCQ);
3454 return check_condition_result;
3455 }
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003456
3457 write_lock_irqsave(&atomic_rw, iflags);
3458
3459 /* trick do_device_access() to fetch both compare and write buffers
3460 * from data-in into arr. Safe (atomic) since write_lock held. */
3461 fake_storep_hold = fake_storep;
3462 fake_storep = arr;
Douglas Gilbert0a7e69c2017-12-23 12:48:12 -05003463 ret = do_device_access(scp, 0, 0, dnum, true);
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003464 fake_storep = fake_storep_hold;
3465 if (ret == -1) {
Douglas Gilbertd467d312014-11-26 12:33:48 -05003466 retval = DID_ERROR << 16;
3467 goto cleanup;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003468 } else if (sdebug_verbose && (ret < (dnum * lb_size)))
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003469 sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
3470 "indicated=%u, IO sent=%d bytes\n", my_name,
3471 dnum * lb_size, ret);
3472 if (!comp_write_worker(lba, num, arr)) {
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003473 mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003474 retval = check_condition_result;
3475 goto cleanup;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003476 }
3477 if (scsi_debug_lbp())
3478 map_region(lba, num);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003479cleanup:
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003480 write_unlock_irqrestore(&atomic_rw, iflags);
Douglas Gilbertd467d312014-11-26 12:33:48 -05003481 kfree(arr);
3482 return retval;
Douglas Gilbert38d5c832014-11-24 21:27:12 -05003483}
3484
Martin K. Petersen44d92692009-10-15 14:45:27 -04003485struct unmap_block_desc {
3486 __be64 lba;
3487 __be32 blocks;
3488 __be32 __reserved;
3489};
3490
Douglas Gilbertfd321192016-04-25 12:16:33 -04003491static int resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003492{
3493 unsigned char *buf;
3494 struct unmap_block_desc *desc;
3495 unsigned int i, payload_len, descriptors;
3496 int ret;
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003497 unsigned long iflags;
Martin K. Petersen44d92692009-10-15 14:45:27 -04003498
Martin K. Petersen44d92692009-10-15 14:45:27 -04003499
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003500 if (!scsi_debug_lbp())
3501 return 0; /* fib and say its done */
3502 payload_len = get_unaligned_be16(scp->cmnd + 7);
3503 BUG_ON(scsi_bufflen(scp) != payload_len);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003504
3505 descriptors = (payload_len - 8) / 16;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003506 if (descriptors > sdebug_unmap_max_desc) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003507 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003508 return check_condition_result;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003509 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003510
Douglas Gilbertb333a812016-04-25 12:16:30 -04003511 buf = kzalloc(scsi_bufflen(scp), GFP_ATOMIC);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003512 if (!buf) {
3513 mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
3514 INSUFF_RES_ASCQ);
3515 return check_condition_result;
3516 }
3517
3518 scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
Martin K. Petersen44d92692009-10-15 14:45:27 -04003519
3520 BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
3521 BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
3522
3523 desc = (void *)&buf[8];
3524
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003525 write_lock_irqsave(&atomic_rw, iflags);
3526
Martin K. Petersen44d92692009-10-15 14:45:27 -04003527 for (i = 0 ; i < descriptors ; i++) {
3528 unsigned long long lba = get_unaligned_be64(&desc[i].lba);
3529 unsigned int num = get_unaligned_be32(&desc[i].blocks);
3530
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003531 ret = check_device_access_params(scp, lba, num);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003532 if (ret)
3533 goto out;
3534
3535 unmap_region(lba, num);
3536 }
3537
3538 ret = 0;
3539
3540out:
Akinobu Mita6c78cc02014-02-26 22:57:03 +09003541 write_unlock_irqrestore(&atomic_rw, iflags);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003542 kfree(buf);
3543
3544 return ret;
3545}
3546
3547#define SDEBUG_GET_LBA_STATUS_LEN 32
3548
Douglas Gilbertfd321192016-04-25 12:16:33 -04003549static int resp_get_lba_status(struct scsi_cmnd *scp,
3550 struct sdebug_dev_info *devip)
Martin K. Petersen44d92692009-10-15 14:45:27 -04003551{
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003552 u8 *cmd = scp->cmnd;
3553 u64 lba;
3554 u32 alloc_len, mapped, num;
3555 u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
Martin K. Petersen44d92692009-10-15 14:45:27 -04003556 int ret;
3557
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003558 lba = get_unaligned_be64(cmd + 2);
3559 alloc_len = get_unaligned_be32(cmd + 10);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003560
3561 if (alloc_len < 24)
3562 return 0;
3563
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003564 ret = check_device_access_params(scp, lba, 1);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003565 if (ret)
3566 return ret;
3567
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003568 if (scsi_debug_lbp())
3569 mapped = map_state(lba, &num);
3570 else {
3571 mapped = 1;
3572 /* following just in case virtual_gb changed */
3573 sdebug_capacity = get_sdebug_capacity();
3574 if (sdebug_capacity - lba <= 0xffffffff)
3575 num = sdebug_capacity - lba;
3576 else
3577 num = 0xffffffff;
3578 }
Martin K. Petersen44d92692009-10-15 14:45:27 -04003579
3580 memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003581 put_unaligned_be32(20, arr); /* Parameter Data Length */
3582 put_unaligned_be64(lba, arr + 8); /* LBA */
3583 put_unaligned_be32(num, arr + 16); /* Number of blocks */
3584 arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
Martin K. Petersen44d92692009-10-15 14:45:27 -04003585
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003586 return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
Martin K. Petersen44d92692009-10-15 14:45:27 -04003587}
3588
Douglas Gilbert80c49562018-02-09 21:36:39 -05003589static int resp_sync_cache(struct scsi_cmnd *scp,
3590 struct sdebug_dev_info *devip)
3591{
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003592 int res = 0;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003593 u64 lba;
3594 u32 num_blocks;
3595 u8 *cmd = scp->cmnd;
3596
3597 if (cmd[0] == SYNCHRONIZE_CACHE) { /* 10 byte cdb */
3598 lba = get_unaligned_be32(cmd + 2);
3599 num_blocks = get_unaligned_be16(cmd + 7);
3600 } else { /* SYNCHRONIZE_CACHE(16) */
3601 lba = get_unaligned_be64(cmd + 2);
3602 num_blocks = get_unaligned_be32(cmd + 10);
3603 }
3604 if (lba + num_blocks > sdebug_capacity) {
3605 mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
3606 return check_condition_result;
3607 }
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04003608 if (!write_since_sync || cmd[1] & 0x2)
3609 res = SDEG_RES_IMMED_MASK;
3610 else /* delay if write_since_sync and IMMED clear */
3611 write_since_sync = false;
3612 return res;
Douglas Gilbert80c49562018-02-09 21:36:39 -05003613}
3614
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003615#define RL_BUCKET_ELEMS 8
3616
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003617/* Even though each pseudo target has a REPORT LUNS "well known logical unit"
3618 * (W-LUN), the normal Linux scanning logic does not associate it with a
3619 * device (e.g. /dev/sg7). The following magic will make that association:
3620 * "cd /sys/class/scsi_host/host<n> ; echo '- - 49409' > scan"
3621 * where <n> is a host number. If there are multiple targets in a host then
3622 * the above will associate a W-LUN to each target. To only get a W-LUN
3623 * for target 2, then use "echo '- 2 49409' > scan" .
3624 */
3625static int resp_report_luns(struct scsi_cmnd *scp,
3626 struct sdebug_dev_info *devip)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003627{
Douglas Gilbert01123ef2014-08-05 12:20:02 +02003628 unsigned char *cmd = scp->cmnd;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003629 unsigned int alloc_len;
3630 unsigned char select_report;
3631 u64 lun;
3632 struct scsi_lun *lun_p;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003633 u8 arr[RL_BUCKET_ELEMS * sizeof(struct scsi_lun)];
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003634 unsigned int lun_cnt; /* normal LUN count (max: 256) */
3635 unsigned int wlun_cnt; /* report luns W-LUN count */
3636 unsigned int tlun_cnt; /* total LUN count */
3637 unsigned int rlen; /* response length (in bytes) */
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003638 int k, j, n, res;
3639 unsigned int off_rsp = 0;
3640 const int sz_lun = sizeof(struct scsi_lun);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003641
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05003642 clear_luns_changed_on_target(devip);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003643
3644 select_report = cmd[2];
3645 alloc_len = get_unaligned_be32(cmd + 6);
3646
3647 if (alloc_len < 4) {
3648 pr_err("alloc len too small %d\n", alloc_len);
3649 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003650 return check_condition_result;
3651 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003652
3653 switch (select_report) {
3654 case 0: /* all LUNs apart from W-LUNs */
3655 lun_cnt = sdebug_max_luns;
3656 wlun_cnt = 0;
3657 break;
3658 case 1: /* only W-LUNs */
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003659 lun_cnt = 0;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003660 wlun_cnt = 1;
3661 break;
3662 case 2: /* all LUNs */
3663 lun_cnt = sdebug_max_luns;
3664 wlun_cnt = 1;
3665 break;
3666 case 0x10: /* only administrative LUs */
3667 case 0x11: /* see SPC-5 */
3668 case 0x12: /* only subsiduary LUs owned by referenced LU */
3669 default:
3670 pr_debug("select report invalid %d\n", select_report);
3671 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
3672 return check_condition_result;
3673 }
3674
3675 if (sdebug_no_lun_0 && (lun_cnt > 0))
Douglas Gilbertc65b1442006-06-06 00:11:24 -04003676 --lun_cnt;
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003677
3678 tlun_cnt = lun_cnt + wlun_cnt;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003679 rlen = tlun_cnt * sz_lun; /* excluding 8 byte header */
3680 scsi_set_resid(scp, scsi_bufflen(scp));
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003681 pr_debug("select_report %d luns = %d wluns = %d no_lun0 %d\n",
3682 select_report, lun_cnt, wlun_cnt, sdebug_no_lun_0);
3683
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003684 /* loops rely on sizeof response header same as sizeof lun (both 8) */
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003685 lun = sdebug_no_lun_0 ? 1 : 0;
Douglas Gilbertfb0cc8d2016-05-31 17:15:07 -04003686 for (k = 0, j = 0, res = 0; true; ++k, j = 0) {
3687 memset(arr, 0, sizeof(arr));
3688 lun_p = (struct scsi_lun *)&arr[0];
3689 if (k == 0) {
3690 put_unaligned_be32(rlen, &arr[0]);
3691 ++lun_p;
3692 j = 1;
3693 }
3694 for ( ; j < RL_BUCKET_ELEMS; ++j, ++lun_p) {
3695 if ((k * RL_BUCKET_ELEMS) + j > lun_cnt)
3696 break;
3697 int_to_scsilun(lun++, lun_p);
3698 }
3699 if (j < RL_BUCKET_ELEMS)
3700 break;
3701 n = j * sz_lun;
3702 res = p_fill_from_dev_buffer(scp, arr, n, off_rsp);
3703 if (res)
3704 return res;
3705 off_rsp += n;
3706 }
3707 if (wlun_cnt) {
3708 int_to_scsilun(SCSI_W_LUN_REPORT_LUNS, lun_p);
3709 ++j;
3710 }
3711 if (j > 0)
3712 res = p_fill_from_dev_buffer(scp, arr, j * sz_lun, off_rsp);
Douglas Gilbert8d039e22016-04-30 22:44:43 -04003713 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003714}
3715
Douglas Gilbertc4837392016-05-06 00:40:26 -04003716static struct sdebug_queue *get_queue(struct scsi_cmnd *cmnd)
3717{
Bart Van Assche458df782018-01-26 08:52:19 -08003718 u32 tag = blk_mq_unique_tag(cmnd->request);
3719 u16 hwq = blk_mq_unique_tag_to_hwq(tag);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003720
Bart Van Assche458df782018-01-26 08:52:19 -08003721 pr_debug("tag=%#x, hwq=%d\n", tag, hwq);
3722 if (WARN_ON_ONCE(hwq >= submit_queues))
3723 hwq = 0;
3724 return sdebug_q_arr + hwq;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003725}
3726
3727/* Queued (deferred) command completions converge here. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003728static void sdebug_q_cmd_complete(struct sdebug_defer *sd_dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003729{
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003730 bool aborted = sd_dp->aborted;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003731 int qc_idx;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003732 int retiring = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003733 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003734 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003735 struct sdebug_queued_cmd *sqcp;
3736 struct scsi_cmnd *scp;
3737 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003738
Douglas Gilbert10bde982018-01-10 16:57:31 -05003739 sd_dp->defer_t = SDEB_DEFER_NONE;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003740 if (unlikely(aborted))
3741 sd_dp->aborted = false;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003742 qc_idx = sd_dp->qc_idx;
3743 sqp = sdebug_q_arr + sd_dp->sqa_idx;
3744 if (sdebug_statistics) {
3745 atomic_inc(&sdebug_completions);
3746 if (raw_smp_processor_id() != sd_dp->issuing_cpu)
3747 atomic_inc(&sdebug_miss_cpus);
3748 }
3749 if (unlikely((qc_idx < 0) || (qc_idx >= SDEBUG_CANQUEUE))) {
3750 pr_err("wild qc_idx=%d\n", qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003751 return;
3752 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003753 spin_lock_irqsave(&sqp->qc_lock, iflags);
3754 sqcp = &sqp->qc_arr[qc_idx];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003755 scp = sqcp->a_cmnd;
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003756 if (unlikely(scp == NULL)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04003757 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
3758 pr_err("scp is NULL, sqa_idx=%d, qc_idx=%d\n",
3759 sd_dp->sqa_idx, qc_idx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003760 return;
3761 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003762 devip = (struct sdebug_dev_info *)scp->device->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003763 if (likely(devip))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003764 atomic_dec(&devip->num_in_q);
3765 else
Tomas Winklerc12879702015-07-28 16:54:20 +03003766 pr_err("devip=NULL\n");
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003767 if (unlikely(atomic_read(&retired_max_queue) > 0))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003768 retiring = 1;
3769
3770 sqcp->a_cmnd = NULL;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003771 if (unlikely(!test_and_clear_bit(qc_idx, sqp->in_use_bm))) {
3772 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003773 pr_err("Unexpected completion\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003774 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003775 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003776
3777 if (unlikely(retiring)) { /* user has reduced max_queue */
3778 int k, retval;
3779
3780 retval = atomic_read(&retired_max_queue);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003781 if (qc_idx >= retval) {
3782 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Tomas Winklerc12879702015-07-28 16:54:20 +03003783 pr_err("index %d too large\n", retval);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003784 return;
3785 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003786 k = find_last_bit(sqp->in_use_bm, retval);
Douglas Gilbert773642d2016-04-25 12:16:28 -04003787 if ((k < sdebug_max_queue) || (k == retval))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003788 atomic_set(&retired_max_queue, 0);
3789 else
3790 atomic_set(&retired_max_queue, k + 1);
3791 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003792 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04003793 if (unlikely(aborted)) {
3794 if (sdebug_verbose)
3795 pr_info("bypassing scsi_done() due to aborted cmd\n");
3796 return;
3797 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003798 scp->scsi_done(scp); /* callback to mid level */
Linus Torvalds1da177e2005-04-16 15:20:36 -07003799}
3800
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003801/* When high resolution timer goes off this function is called. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003802static enum hrtimer_restart sdebug_q_cmd_hrt_complete(struct hrtimer *timer)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003803{
Douglas Gilberta10bc122016-04-25 12:16:32 -04003804 struct sdebug_defer *sd_dp = container_of(timer, struct sdebug_defer,
3805 hrt);
3806 sdebug_q_cmd_complete(sd_dp);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003807 return HRTIMER_NORESTART;
3808}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003809
Douglas Gilberta10bc122016-04-25 12:16:32 -04003810/* When work queue schedules work, it calls this function. */
Douglas Gilbertfd321192016-04-25 12:16:33 -04003811static void sdebug_q_cmd_wq_complete(struct work_struct *work)
Douglas Gilberta10bc122016-04-25 12:16:32 -04003812{
3813 struct sdebug_defer *sd_dp = container_of(work, struct sdebug_defer,
3814 ew.work);
3815 sdebug_q_cmd_complete(sd_dp);
3816}
3817
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003818static bool got_shared_uuid;
Christoph Hellwigbf476432017-05-17 09:55:26 +02003819static uuid_t shared_uuid;
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003820
Douglas Gilbertfd321192016-04-25 12:16:33 -04003821static struct sdebug_dev_info *sdebug_device_create(
3822 struct sdebug_host_info *sdbg_host, gfp_t flags)
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003823{
3824 struct sdebug_dev_info *devip;
3825
3826 devip = kzalloc(sizeof(*devip), flags);
3827 if (devip) {
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003828 if (sdebug_uuid_ctl == 1)
Christoph Hellwigbf476432017-05-17 09:55:26 +02003829 uuid_gen(&devip->lu_name);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003830 else if (sdebug_uuid_ctl == 2) {
3831 if (got_shared_uuid)
3832 devip->lu_name = shared_uuid;
3833 else {
Christoph Hellwigbf476432017-05-17 09:55:26 +02003834 uuid_gen(&shared_uuid);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04003835 got_shared_uuid = true;
3836 devip->lu_name = shared_uuid;
3837 }
3838 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003839 devip->sdbg_host = sdbg_host;
3840 list_add_tail(&devip->dev_list, &sdbg_host->dev_info_list);
3841 }
3842 return devip;
3843}
3844
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003845static struct sdebug_dev_info *find_build_dev_info(struct scsi_device *sdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003846{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003847 struct sdebug_host_info *sdbg_host;
3848 struct sdebug_dev_info *open_devip = NULL;
3849 struct sdebug_dev_info *devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003850
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09003851 sdbg_host = *(struct sdebug_host_info **)shost_priv(sdev->host);
3852 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003853 pr_err("Host info NULL\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07003854 return NULL;
Douglas Gilbert9a051012017-12-23 12:48:10 -05003855 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003856 list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
3857 if ((devip->used) && (devip->channel == sdev->channel) &&
Douglas Gilbert9a051012017-12-23 12:48:10 -05003858 (devip->target == sdev->id) &&
3859 (devip->lun == sdev->lun))
3860 return devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003861 else {
3862 if ((!devip->used) && (!open_devip))
3863 open_devip = devip;
3864 }
3865 }
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09003866 if (!open_devip) { /* try and make a new one */
3867 open_devip = sdebug_device_create(sdbg_host, GFP_ATOMIC);
3868 if (!open_devip) {
Tomas Winklerc12879702015-07-28 16:54:20 +03003869 pr_err("out of memory at line %d\n", __LINE__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07003870 return NULL;
3871 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07003872 }
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003873
3874 open_devip->channel = sdev->channel;
3875 open_devip->target = sdev->id;
3876 open_devip->lun = sdev->lun;
3877 open_devip->sdbg_host = sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003878 atomic_set(&open_devip->num_in_q, 0);
3879 set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003880 open_devip->used = true;
FUJITA Tomonoria75869d2008-03-20 11:09:17 +09003881 return open_devip;
Linus Torvalds1da177e2005-04-16 15:20:36 -07003882}
3883
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003884static int scsi_debug_slave_alloc(struct scsi_device *sdp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07003885{
Douglas Gilbert773642d2016-04-25 12:16:28 -04003886 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003887 pr_info("slave_alloc <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003888 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003889 return 0;
3890}
Linus Torvalds1da177e2005-04-16 15:20:36 -07003891
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003892static int scsi_debug_slave_configure(struct scsi_device *sdp)
3893{
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003894 struct sdebug_dev_info *devip =
3895 (struct sdebug_dev_info *)sdp->hostdata;
FUJITA Tomonoria34c4e92008-03-25 09:26:50 +09003896
Douglas Gilbert773642d2016-04-25 12:16:28 -04003897 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003898 pr_info("slave_configure <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003899 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003900 if (sdp->host->max_cmd_len != SDEBUG_MAX_CMD_LEN)
3901 sdp->host->max_cmd_len = SDEBUG_MAX_CMD_LEN;
3902 if (devip == NULL) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003903 devip = find_build_dev_info(sdp);
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04003904 if (devip == NULL)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04003905 return 1; /* no resources, will be marked offline */
3906 }
Christoph Hellwigc8b09f62014-11-03 20:15:14 +01003907 sdp->hostdata = devip;
Douglas Gilbert773642d2016-04-25 12:16:28 -04003908 if (sdebug_no_uld)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04003909 sdp->no_uld_attach = 1;
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05003910 config_cdb_len(sdp);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003911 return 0;
3912}
3913
3914static void scsi_debug_slave_destroy(struct scsi_device *sdp)
3915{
3916 struct sdebug_dev_info *devip =
3917 (struct sdebug_dev_info *)sdp->hostdata;
3918
Douglas Gilbert773642d2016-04-25 12:16:28 -04003919 if (sdebug_verbose)
Tomas Winklerc12879702015-07-28 16:54:20 +03003920 pr_info("slave_destroy <%u %u %u %llu>\n",
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003921 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
3922 if (devip) {
Lucas De Marchi25985ed2011-03-30 22:57:33 -03003923 /* make this slot available for re-use */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05003924 devip->used = false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003925 sdp->hostdata = NULL;
3926 }
3927}
3928
Douglas Gilbert10bde982018-01-10 16:57:31 -05003929static void stop_qc_helper(struct sdebug_defer *sd_dp,
3930 enum sdeb_defer_type defer_t)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003931{
3932 if (!sd_dp)
3933 return;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003934 if (defer_t == SDEB_DEFER_HRT)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003935 hrtimer_cancel(&sd_dp->hrt);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003936 else if (defer_t == SDEB_DEFER_WQ)
Douglas Gilbertc4837392016-05-06 00:40:26 -04003937 cancel_work_sync(&sd_dp->ew.work);
3938}
3939
Douglas Gilberta10bc122016-04-25 12:16:32 -04003940/* If @cmnd found deletes its timer or work queue and returns true; else
3941 returns false */
3942static bool stop_queued_cmnd(struct scsi_cmnd *cmnd)
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003943{
3944 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003945 int j, k, qmax, r_qmax;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003946 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003947 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003948 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003949 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003950 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003951
Douglas Gilbertc4837392016-05-06 00:40:26 -04003952 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3953 spin_lock_irqsave(&sqp->qc_lock, iflags);
3954 qmax = sdebug_max_queue;
3955 r_qmax = atomic_read(&retired_max_queue);
3956 if (r_qmax > qmax)
3957 qmax = r_qmax;
3958 for (k = 0; k < qmax; ++k) {
3959 if (test_bit(k, sqp->in_use_bm)) {
3960 sqcp = &sqp->qc_arr[k];
3961 if (cmnd != sqcp->a_cmnd)
3962 continue;
3963 /* found */
3964 devip = (struct sdebug_dev_info *)
3965 cmnd->device->hostdata;
3966 if (devip)
3967 atomic_dec(&devip->num_in_q);
3968 sqcp->a_cmnd = NULL;
3969 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003970 if (sd_dp) {
3971 l_defer_t = sd_dp->defer_t;
3972 sd_dp->defer_t = SDEB_DEFER_NONE;
3973 } else
3974 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003975 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05003976 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04003977 clear_bit(k, sqp->in_use_bm);
3978 return true;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003979 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003980 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04003981 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003982 }
Douglas Gilberta10bc122016-04-25 12:16:32 -04003983 return false;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003984}
3985
Douglas Gilberta10bc122016-04-25 12:16:32 -04003986/* Deletes (stops) timers or work queues of all queued commands */
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003987static void stop_all_queued(void)
3988{
3989 unsigned long iflags;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003990 int j, k;
Douglas Gilbert10bde982018-01-10 16:57:31 -05003991 enum sdeb_defer_type l_defer_t;
Douglas Gilbertc4837392016-05-06 00:40:26 -04003992 struct sdebug_queue *sqp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003993 struct sdebug_queued_cmd *sqcp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04003994 struct sdebug_dev_info *devip;
Douglas Gilberta10bc122016-04-25 12:16:32 -04003995 struct sdebug_defer *sd_dp;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09003996
Douglas Gilbertc4837392016-05-06 00:40:26 -04003997 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
3998 spin_lock_irqsave(&sqp->qc_lock, iflags);
3999 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4000 if (test_bit(k, sqp->in_use_bm)) {
4001 sqcp = &sqp->qc_arr[k];
4002 if (sqcp->a_cmnd == NULL)
4003 continue;
4004 devip = (struct sdebug_dev_info *)
4005 sqcp->a_cmnd->device->hostdata;
4006 if (devip)
4007 atomic_dec(&devip->num_in_q);
4008 sqcp->a_cmnd = NULL;
4009 sd_dp = sqcp->sd_dp;
Douglas Gilbert10bde982018-01-10 16:57:31 -05004010 if (sd_dp) {
4011 l_defer_t = sd_dp->defer_t;
4012 sd_dp->defer_t = SDEB_DEFER_NONE;
4013 } else
4014 l_defer_t = SDEB_DEFER_NONE;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004015 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004016 stop_qc_helper(sd_dp, l_defer_t);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004017 clear_bit(k, sqp->in_use_bm);
4018 spin_lock_irqsave(&sqp->qc_lock, iflags);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004019 }
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004020 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004021 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09004022 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004023}
4024
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004025/* Free queued command memory on heap */
4026static void free_all_queued(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004027{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004028 int j, k;
4029 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004030 struct sdebug_queued_cmd *sqcp;
4031
Douglas Gilbertc4837392016-05-06 00:40:26 -04004032 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4033 for (k = 0; k < SDEBUG_CANQUEUE; ++k) {
4034 sqcp = &sqp->qc_arr[k];
4035 kfree(sqcp->sd_dp);
4036 sqcp->sd_dp = NULL;
4037 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004038 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004039}
4040
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004041static int scsi_debug_abort(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004042{
Douglas Gilberta10bc122016-04-25 12:16:32 -04004043 bool ok;
4044
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004045 ++num_aborts;
4046 if (SCpnt) {
Douglas Gilberta10bc122016-04-25 12:16:32 -04004047 ok = stop_queued_cmnd(SCpnt);
4048 if (SCpnt->device && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
4049 sdev_printk(KERN_INFO, SCpnt->device,
4050 "%s: command%s found\n", __func__,
4051 ok ? "" : " not");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004052 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004053 return SUCCESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004054}
4055
John Pittman91d4c752018-02-09 21:12:43 -05004056static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004057{
Linus Torvalds1da177e2005-04-16 15:20:36 -07004058 ++num_dev_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004059 if (SCpnt && SCpnt->device) {
4060 struct scsi_device *sdp = SCpnt->device;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004061 struct sdebug_dev_info *devip =
4062 (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004063
Douglas Gilbert773642d2016-04-25 12:16:28 -04004064 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004065 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004066 if (devip)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004067 set_bit(SDEBUG_UA_POR, devip->uas_bm);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004068 }
4069 return SUCCESS;
4070}
4071
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004072static int scsi_debug_target_reset(struct scsi_cmnd *SCpnt)
4073{
4074 struct sdebug_host_info *sdbg_host;
4075 struct sdebug_dev_info *devip;
4076 struct scsi_device *sdp;
4077 struct Scsi_Host *hp;
4078 int k = 0;
4079
4080 ++num_target_resets;
4081 if (!SCpnt)
4082 goto lie;
4083 sdp = SCpnt->device;
4084 if (!sdp)
4085 goto lie;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004086 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004087 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4088 hp = sdp->host;
4089 if (!hp)
4090 goto lie;
4091 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
4092 if (sdbg_host) {
4093 list_for_each_entry(devip,
4094 &sdbg_host->dev_info_list,
4095 dev_list)
4096 if (devip->target == sdp->id) {
4097 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4098 ++k;
4099 }
4100 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004101 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004102 sdev_printk(KERN_INFO, sdp,
4103 "%s: %d device(s) found in target\n", __func__, k);
4104lie:
4105 return SUCCESS;
4106}
4107
John Pittman91d4c752018-02-09 21:12:43 -05004108static int scsi_debug_bus_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004109{
4110 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004111 struct sdebug_dev_info *devip;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004112 struct scsi_device *sdp;
4113 struct Scsi_Host *hp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004114 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004115
Linus Torvalds1da177e2005-04-16 15:20:36 -07004116 ++num_bus_resets;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004117 if (!(SCpnt && SCpnt->device))
4118 goto lie;
4119 sdp = SCpnt->device;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004120 if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004121 sdev_printk(KERN_INFO, sdp, "%s\n", __func__);
4122 hp = sdp->host;
4123 if (hp) {
FUJITA Tomonorid1e4c9c2008-03-02 18:30:18 +09004124 sdbg_host = *(struct sdebug_host_info **)shost_priv(hp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004125 if (sdbg_host) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004126 list_for_each_entry(devip,
Douglas Gilbert9a051012017-12-23 12:48:10 -05004127 &sdbg_host->dev_info_list,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004128 dev_list) {
4129 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4130 ++k;
4131 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004132 }
4133 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004134 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004135 sdev_printk(KERN_INFO, sdp,
4136 "%s: %d device(s) found in host\n", __func__, k);
4137lie:
Linus Torvalds1da177e2005-04-16 15:20:36 -07004138 return SUCCESS;
4139}
4140
John Pittman91d4c752018-02-09 21:12:43 -05004141static int scsi_debug_host_reset(struct scsi_cmnd *SCpnt)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004142{
John Pittman91d4c752018-02-09 21:12:43 -05004143 struct sdebug_host_info *sdbg_host;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004144 struct sdebug_dev_info *devip;
4145 int k = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004146
Linus Torvalds1da177e2005-04-16 15:20:36 -07004147 ++num_host_resets;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004148 if ((SCpnt->device) && (SDEBUG_OPT_ALL_NOISE & sdebug_opts))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004149 sdev_printk(KERN_INFO, SCpnt->device, "%s\n", __func__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05004150 spin_lock(&sdebug_host_list_lock);
4151 list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004152 list_for_each_entry(devip, &sdbg_host->dev_info_list,
4153 dev_list) {
4154 set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
4155 ++k;
4156 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05004157 }
4158 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004159 stop_all_queued();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004160 if (SDEBUG_OPT_RESET_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004161 sdev_printk(KERN_INFO, SCpnt->device,
4162 "%s: %d device(s) found\n", __func__, k);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004163 return SUCCESS;
4164}
4165
FUJITA Tomonorif58b0ef2008-03-30 00:59:54 +09004166static void __init sdebug_build_parts(unsigned char *ramp,
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09004167 unsigned long store_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004168{
John Pittman91d4c752018-02-09 21:12:43 -05004169 struct partition *pp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004170 int starts[SDEBUG_MAX_PARTS + 2];
4171 int sectors_per_part, num_sectors, k;
4172 int heads_by_sects, start_sec, end_sec;
4173
4174 /* assume partition table already zeroed */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004175 if ((sdebug_num_parts < 1) || (store_size < 1048576))
Linus Torvalds1da177e2005-04-16 15:20:36 -07004176 return;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004177 if (sdebug_num_parts > SDEBUG_MAX_PARTS) {
4178 sdebug_num_parts = SDEBUG_MAX_PARTS;
Tomas Winklerc12879702015-07-28 16:54:20 +03004179 pr_warn("reducing partitions to %d\n", SDEBUG_MAX_PARTS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004180 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004181 num_sectors = (int)sdebug_store_sectors;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004182 sectors_per_part = (num_sectors - sdebug_sectors_per)
Douglas Gilbert773642d2016-04-25 12:16:28 -04004183 / sdebug_num_parts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004184 heads_by_sects = sdebug_heads * sdebug_sectors_per;
Douglas Gilbert9a051012017-12-23 12:48:10 -05004185 starts[0] = sdebug_sectors_per;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004186 for (k = 1; k < sdebug_num_parts; ++k)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004187 starts[k] = ((k * sectors_per_part) / heads_by_sects)
4188 * heads_by_sects;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004189 starts[sdebug_num_parts] = num_sectors;
4190 starts[sdebug_num_parts + 1] = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004191
4192 ramp[510] = 0x55; /* magic partition markings */
4193 ramp[511] = 0xAA;
4194 pp = (struct partition *)(ramp + 0x1be);
4195 for (k = 0; starts[k + 1]; ++k, ++pp) {
4196 start_sec = starts[k];
4197 end_sec = starts[k + 1] - 1;
4198 pp->boot_ind = 0;
4199
4200 pp->cyl = start_sec / heads_by_sects;
4201 pp->head = (start_sec - (pp->cyl * heads_by_sects))
4202 / sdebug_sectors_per;
4203 pp->sector = (start_sec % sdebug_sectors_per) + 1;
4204
4205 pp->end_cyl = end_sec / heads_by_sects;
4206 pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
4207 / sdebug_sectors_per;
4208 pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
4209
Akinobu Mita150c3542013-08-26 22:08:40 +09004210 pp->start_sect = cpu_to_le32(start_sec);
4211 pp->nr_sects = cpu_to_le32(end_sec - start_sec + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004212 pp->sys_ind = 0x83; /* plain Linux partition */
4213 }
4214}
4215
Douglas Gilbertc4837392016-05-06 00:40:26 -04004216static void block_unblock_all_queues(bool block)
4217{
4218 int j;
4219 struct sdebug_queue *sqp;
4220
4221 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp)
4222 atomic_set(&sqp->blocked, (int)block);
4223}
4224
4225/* Adjust (by rounding down) the sdebug_cmnd_count so abs(every_nth)-1
4226 * commands will be processed normally before triggers occur.
4227 */
4228static void tweak_cmnd_count(void)
4229{
4230 int count, modulo;
4231
4232 modulo = abs(sdebug_every_nth);
4233 if (modulo < 2)
4234 return;
4235 block_unblock_all_queues(true);
4236 count = atomic_read(&sdebug_cmnd_count);
4237 atomic_set(&sdebug_cmnd_count, (count / modulo) * modulo);
4238 block_unblock_all_queues(false);
4239}
4240
4241static void clear_queue_stats(void)
4242{
4243 atomic_set(&sdebug_cmnd_count, 0);
4244 atomic_set(&sdebug_completions, 0);
4245 atomic_set(&sdebug_miss_cpus, 0);
4246 atomic_set(&sdebug_a_tsf, 0);
4247}
4248
4249static void setup_inject(struct sdebug_queue *sqp,
4250 struct sdebug_queued_cmd *sqcp)
4251{
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004252 if ((atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) > 0) {
4253 if (sdebug_every_nth > 0)
4254 sqcp->inj_recovered = sqcp->inj_transport
4255 = sqcp->inj_dif
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004256 = sqcp->inj_dix = sqcp->inj_short
4257 = sqcp->inj_host_busy = sqcp->inj_cmd_abort = 0;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004258 return;
Martin Wilckf9ba7af2018-01-30 00:35:52 +01004259 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004260 sqcp->inj_recovered = !!(SDEBUG_OPT_RECOVERED_ERR & sdebug_opts);
4261 sqcp->inj_transport = !!(SDEBUG_OPT_TRANSPORT_ERR & sdebug_opts);
4262 sqcp->inj_dif = !!(SDEBUG_OPT_DIF_ERR & sdebug_opts);
4263 sqcp->inj_dix = !!(SDEBUG_OPT_DIX_ERR & sdebug_opts);
4264 sqcp->inj_short = !!(SDEBUG_OPT_SHORT_TRANSFER & sdebug_opts);
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08004265 sqcp->inj_host_busy = !!(SDEBUG_OPT_HOST_BUSY & sdebug_opts);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004266 sqcp->inj_cmd_abort = !!(SDEBUG_OPT_CMD_ABORT & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004267}
4268
4269/* Complete the processing of the thread that queued a SCSI command to this
4270 * driver. It either completes the command by calling cmnd_done() or
4271 * schedules a hr timer or work queue then returns 0. Returns
4272 * SCSI_MLQUEUE_HOST_BUSY if temporarily out of resources.
4273 */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004274static int schedule_resp(struct scsi_cmnd *cmnd, struct sdebug_dev_info *devip,
Martin Wilckf66b8512018-02-14 11:05:57 +01004275 int scsi_result,
4276 int (*pfp)(struct scsi_cmnd *,
4277 struct sdebug_dev_info *),
4278 int delta_jiff, int ndelay)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004279{
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004280 unsigned long iflags;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004281 int k, num_in_q, qdepth, inject;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004282 struct sdebug_queue *sqp;
4283 struct sdebug_queued_cmd *sqcp;
Tomas Winkler299b6c02015-07-28 16:54:24 +03004284 struct scsi_device *sdp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004285 struct sdebug_defer *sd_dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004286
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004287 if (unlikely(devip == NULL)) {
4288 if (scsi_result == 0)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004289 scsi_result = DID_NO_CONNECT << 16;
4290 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004291 }
Tomas Winkler299b6c02015-07-28 16:54:24 +03004292 sdp = cmnd->device;
4293
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004294 if (delta_jiff == 0)
4295 goto respond_in_thread;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004296
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004297 /* schedule the response at a later time if resources permit */
Douglas Gilbertc4837392016-05-06 00:40:26 -04004298 sqp = get_queue(cmnd);
4299 spin_lock_irqsave(&sqp->qc_lock, iflags);
4300 if (unlikely(atomic_read(&sqp->blocked))) {
4301 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4302 return SCSI_MLQUEUE_HOST_BUSY;
4303 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004304 num_in_q = atomic_read(&devip->num_in_q);
4305 qdepth = cmnd->device->queue_depth;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004306 inject = 0;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004307 if (unlikely((qdepth > 0) && (num_in_q >= qdepth))) {
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004308 if (scsi_result) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004309 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004310 goto respond_in_thread;
4311 } else
4312 scsi_result = device_qfull_result;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004313 } else if (unlikely(sdebug_every_nth &&
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004314 (SDEBUG_OPT_RARE_TSF & sdebug_opts) &&
4315 (scsi_result == 0))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004316 if ((num_in_q == (qdepth - 1)) &&
4317 (atomic_inc_return(&sdebug_a_tsf) >=
Douglas Gilbert773642d2016-04-25 12:16:28 -04004318 abs(sdebug_every_nth))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004319 atomic_set(&sdebug_a_tsf, 0);
4320 inject = 1;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004321 scsi_result = device_qfull_result;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004322 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004323 }
4324
Douglas Gilbertc4837392016-05-06 00:40:26 -04004325 k = find_first_zero_bit(sqp->in_use_bm, sdebug_max_queue);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004326 if (unlikely(k >= sdebug_max_queue)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004327 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004328 if (scsi_result)
4329 goto respond_in_thread;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004330 else if (SDEBUG_OPT_ALL_TSF & sdebug_opts)
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004331 scsi_result = device_qfull_result;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004332 if (SDEBUG_OPT_Q_NOISE & sdebug_opts)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004333 sdev_printk(KERN_INFO, sdp,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004334 "%s: max_queue=%d exceeded, %s\n",
Douglas Gilbert773642d2016-04-25 12:16:28 -04004335 __func__, sdebug_max_queue,
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004336 (scsi_result ? "status: TASK SET FULL" :
4337 "report: host busy"));
4338 if (scsi_result)
4339 goto respond_in_thread;
4340 else
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004341 return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004342 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004343 __set_bit(k, sqp->in_use_bm);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004344 atomic_inc(&devip->num_in_q);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004345 sqcp = &sqp->qc_arr[k];
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004346 sqcp->a_cmnd = cmnd;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004347 cmnd->host_scribble = (unsigned char *)sqcp;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004348 sd_dp = sqcp->sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004349 spin_unlock_irqrestore(&sqp->qc_lock, iflags);
4350 if (unlikely(sdebug_every_nth && sdebug_any_injecting_opt))
4351 setup_inject(sqp, sqcp);
Douglas Gilbert10bde982018-01-10 16:57:31 -05004352 if (sd_dp == NULL) {
4353 sd_dp = kzalloc(sizeof(*sd_dp), GFP_ATOMIC);
4354 if (sd_dp == NULL)
4355 return SCSI_MLQUEUE_HOST_BUSY;
4356 }
Martin Wilckf66b8512018-02-14 11:05:57 +01004357
4358 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4359 if (cmnd->result & SDEG_RES_IMMED_MASK) {
4360 /*
4361 * This is the F_DELAY_OVERR case. No delay.
4362 */
4363 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4364 delta_jiff = ndelay = 0;
4365 }
4366 if (cmnd->result == 0 && scsi_result != 0)
4367 cmnd->result = scsi_result;
4368
4369 if (unlikely(sdebug_verbose && cmnd->result))
4370 sdev_printk(KERN_INFO, sdp, "%s: non-zero result=0x%x\n",
4371 __func__, cmnd->result);
4372
Douglas Gilbert10bde982018-01-10 16:57:31 -05004373 if (delta_jiff > 0 || ndelay > 0) {
Douglas Gilbertb333a812016-04-25 12:16:30 -04004374 ktime_t kt;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004375
Douglas Gilbertb333a812016-04-25 12:16:30 -04004376 if (delta_jiff > 0) {
Arnd Bergmann13f6b612017-11-27 12:36:25 +01004377 kt = ns_to_ktime((u64)delta_jiff * (NSEC_PER_SEC / HZ));
Douglas Gilbertb333a812016-04-25 12:16:30 -04004378 } else
Douglas Gilbert10bde982018-01-10 16:57:31 -05004379 kt = ndelay;
4380 if (!sd_dp->init_hrt) {
4381 sd_dp->init_hrt = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004382 sqcp->sd_dp = sd_dp;
4383 hrtimer_init(&sd_dp->hrt, CLOCK_MONOTONIC,
Douglas Gilbertc4837392016-05-06 00:40:26 -04004384 HRTIMER_MODE_REL_PINNED);
Douglas Gilberta10bc122016-04-25 12:16:32 -04004385 sd_dp->hrt.function = sdebug_q_cmd_hrt_complete;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004386 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4387 sd_dp->qc_idx = k;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004388 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004389 if (sdebug_statistics)
4390 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004391 sd_dp->defer_t = SDEB_DEFER_HRT;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004392 hrtimer_start(&sd_dp->hrt, kt, HRTIMER_MODE_REL_PINNED);
4393 } else { /* jdelay < 0, use work queue */
Douglas Gilbert10bde982018-01-10 16:57:31 -05004394 if (!sd_dp->init_wq) {
4395 sd_dp->init_wq = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004396 sqcp->sd_dp = sd_dp;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004397 sd_dp->sqa_idx = sqp - sdebug_q_arr;
4398 sd_dp->qc_idx = k;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004399 INIT_WORK(&sd_dp->ew.work, sdebug_q_cmd_wq_complete);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004400 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004401 if (sdebug_statistics)
4402 sd_dp->issuing_cpu = raw_smp_processor_id();
Douglas Gilbert10bde982018-01-10 16:57:31 -05004403 sd_dp->defer_t = SDEB_DEFER_WQ;
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004404 if (unlikely(sqcp->inj_cmd_abort))
4405 sd_dp->aborted = true;
Douglas Gilberta10bc122016-04-25 12:16:32 -04004406 schedule_work(&sd_dp->ew.work);
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004407 if (unlikely(sqcp->inj_cmd_abort)) {
4408 sdev_printk(KERN_INFO, sdp, "abort request tag %d\n",
4409 cmnd->request->tag);
4410 blk_abort_request(cmnd->request);
4411 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004412 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04004413 if (unlikely((SDEBUG_OPT_Q_NOISE & sdebug_opts) &&
4414 (scsi_result == device_qfull_result)))
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004415 sdev_printk(KERN_INFO, sdp,
4416 "%s: num_in_q=%d +1, %s%s\n", __func__,
4417 num_in_q, (inject ? "<inject> " : ""),
4418 "status: TASK SET FULL");
4419 return 0;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004420
4421respond_in_thread: /* call back to mid-layer using invocation thread */
Martin Wilckf66b8512018-02-14 11:05:57 +01004422 cmnd->result = pfp != NULL ? pfp(cmnd, devip) : 0;
4423 cmnd->result &= ~SDEG_RES_IMMED_MASK;
4424 if (cmnd->result == 0 && scsi_result != 0)
4425 cmnd->result = scsi_result;
Douglas Gilbertcd62b7d2014-08-05 12:20:46 +02004426 cmnd->scsi_done(cmnd);
4427 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004428}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004429
Douglas Gilbert23183912006-09-16 20:30:47 -04004430/* Note: The following macros create attribute files in the
4431 /sys/module/scsi_debug/parameters directory. Unfortunately this
4432 driver is unaware of a change and cannot trigger auxiliary actions
4433 as it can when the corresponding attribute in the
4434 /sys/bus/pseudo/drivers/scsi_debug directory is changed.
4435 */
Douglas Gilbert773642d2016-04-25 12:16:28 -04004436module_param_named(add_host, sdebug_add_host, int, S_IRUGO | S_IWUSR);
4437module_param_named(ato, sdebug_ato, int, S_IRUGO);
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004438module_param_named(cdb_len, sdebug_cdb_len, int, 0644);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004439module_param_named(clustering, sdebug_clustering, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc2206092016-04-25 12:16:31 -04004440module_param_named(delay, sdebug_jdelay, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004441module_param_named(dev_size_mb, sdebug_dev_size_mb, int, S_IRUGO);
4442module_param_named(dif, sdebug_dif, int, S_IRUGO);
4443module_param_named(dix, sdebug_dix, int, S_IRUGO);
4444module_param_named(dsense, sdebug_dsense, int, S_IRUGO | S_IWUSR);
4445module_param_named(every_nth, sdebug_every_nth, int, S_IRUGO | S_IWUSR);
4446module_param_named(fake_rw, sdebug_fake_rw, int, S_IRUGO | S_IWUSR);
4447module_param_named(guard, sdebug_guard, uint, S_IRUGO);
4448module_param_named(host_lock, sdebug_host_lock, bool, S_IRUGO | S_IWUSR);
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004449module_param_string(inq_vendor, sdebug_inq_vendor_id,
4450 sizeof(sdebug_inq_vendor_id), S_IRUGO|S_IWUSR);
4451module_param_string(inq_product, sdebug_inq_product_id,
4452 sizeof(sdebug_inq_product_id), S_IRUGO|S_IWUSR);
4453module_param_string(inq_rev, sdebug_inq_product_rev,
4454 sizeof(sdebug_inq_product_rev), S_IRUGO|S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004455module_param_named(lbpu, sdebug_lbpu, int, S_IRUGO);
4456module_param_named(lbpws, sdebug_lbpws, int, S_IRUGO);
4457module_param_named(lbpws10, sdebug_lbpws10, int, S_IRUGO);
4458module_param_named(lbprz, sdebug_lbprz, int, S_IRUGO);
4459module_param_named(lowest_aligned, sdebug_lowest_aligned, int, S_IRUGO);
4460module_param_named(max_luns, sdebug_max_luns, int, S_IRUGO | S_IWUSR);
4461module_param_named(max_queue, sdebug_max_queue, int, S_IRUGO | S_IWUSR);
Laurence Obermand9da8912018-02-03 13:38:35 -05004462module_param_named(medium_error_start, sdebug_medium_error_start, int, S_IRUGO | S_IWUSR);
4463module_param_named(medium_error_count, sdebug_medium_error_count, int, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004464module_param_named(ndelay, sdebug_ndelay, int, S_IRUGO | S_IWUSR);
4465module_param_named(no_lun_0, sdebug_no_lun_0, int, S_IRUGO | S_IWUSR);
4466module_param_named(no_uld, sdebug_no_uld, int, S_IRUGO);
4467module_param_named(num_parts, sdebug_num_parts, int, S_IRUGO);
4468module_param_named(num_tgts, sdebug_num_tgts, int, S_IRUGO | S_IWUSR);
4469module_param_named(opt_blks, sdebug_opt_blks, int, S_IRUGO);
4470module_param_named(opts, sdebug_opts, int, S_IRUGO | S_IWUSR);
4471module_param_named(physblk_exp, sdebug_physblk_exp, int, S_IRUGO);
Lukas Herbolt86e68282017-01-26 10:00:37 +01004472module_param_named(opt_xferlen_exp, sdebug_opt_xferlen_exp, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004473module_param_named(ptype, sdebug_ptype, int, S_IRUGO | S_IWUSR);
4474module_param_named(removable, sdebug_removable, bool, S_IRUGO | S_IWUSR);
4475module_param_named(scsi_level, sdebug_scsi_level, int, S_IRUGO);
4476module_param_named(sector_size, sdebug_sector_size, int, S_IRUGO);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004477module_param_named(statistics, sdebug_statistics, bool, S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004478module_param_named(strict, sdebug_strict, bool, S_IRUGO | S_IWUSR);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004479module_param_named(submit_queues, submit_queues, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004480module_param_named(unmap_alignment, sdebug_unmap_alignment, int, S_IRUGO);
4481module_param_named(unmap_granularity, sdebug_unmap_granularity, int, S_IRUGO);
4482module_param_named(unmap_max_blocks, sdebug_unmap_max_blocks, int, S_IRUGO);
4483module_param_named(unmap_max_desc, sdebug_unmap_max_desc, int, S_IRUGO);
4484module_param_named(virtual_gb, sdebug_virtual_gb, int, S_IRUGO | S_IWUSR);
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004485module_param_named(uuid_ctl, sdebug_uuid_ctl, int, S_IRUGO);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004486module_param_named(vpd_use_hostno, sdebug_vpd_use_hostno, int,
Douglas Gilbert23183912006-09-16 20:30:47 -04004487 S_IRUGO | S_IWUSR);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004488module_param_named(write_same_length, sdebug_write_same_length, int,
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004489 S_IRUGO | S_IWUSR);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004490
4491MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
4492MODULE_DESCRIPTION("SCSI debug adapter driver");
4493MODULE_LICENSE("GPL");
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004494MODULE_VERSION(SDEBUG_VERSION);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004495
4496MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004497MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004498MODULE_PARM_DESC(cdb_len, "suggest CDB lengths to drivers (def=10)");
Akinobu Mita0759c662014-02-26 22:57:04 +09004499MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004500MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004501MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004502MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
4503MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004504MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
Randy Dunlapbeb87c32007-06-11 11:36:40 -07004505MODULE_PARM_DESC(every_nth, "timeout every nth command(def=0)");
Douglas Gilbert23183912006-09-16 20:30:47 -04004506MODULE_PARM_DESC(fake_rw, "fake reads/writes instead of copying (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004507MODULE_PARM_DESC(guard, "protection checksum: 0=crc, 1=ip (def=0)");
Douglas Gilbert185dd232016-04-25 12:16:29 -04004508MODULE_PARM_DESC(host_lock, "host_lock is ignored (def=0)");
Hannes Reineckee5203cf2017-10-02 16:26:33 +02004509MODULE_PARM_DESC(inq_vendor, "SCSI INQUIRY vendor string (def=\"Linux\")");
4510MODULE_PARM_DESC(inq_product, "SCSI INQUIRY product string (def=\"scsi_debug\")");
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05004511MODULE_PARM_DESC(inq_rev, "SCSI INQUIRY revision string (def=\""
4512 SDEBUG_VERSION "\")");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004513MODULE_PARM_DESC(lbpu, "enable LBP, support UNMAP command (def=0)");
4514MODULE_PARM_DESC(lbpws, "enable LBP, support WRITE SAME(16) with UNMAP bit (def=0)");
4515MODULE_PARM_DESC(lbpws10, "enable LBP, support WRITE SAME(10) with UNMAP bit (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004516MODULE_PARM_DESC(lbprz,
4517 "on read unmapped LBs return 0 when 1 (def), return 0xff when 2");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004518MODULE_PARM_DESC(lowest_aligned, "lowest aligned lba (def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004519MODULE_PARM_DESC(max_luns, "number of LUNs per target to simulate(def=1)");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004520MODULE_PARM_DESC(max_queue, "max number of queued commands (1 to max(def))");
Laurence Obermand9da8912018-02-03 13:38:35 -05004521MODULE_PARM_DESC(medium_error_start, "starting sector number to return MEDIUM error");
4522MODULE_PARM_DESC(medium_error_count, "count of sectors to return follow on MEDIUM error");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004523MODULE_PARM_DESC(ndelay, "response delay in nanoseconds (def=0 -> ignore)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004524MODULE_PARM_DESC(no_lun_0, "no LU number 0 (def=0 -> have lun 0)");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004525MODULE_PARM_DESC(no_uld, "stop ULD (e.g. sd driver) attaching (def=0))");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004526MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004527MODULE_PARM_DESC(num_tgts, "number of targets per host to simulate(def=1)");
Martin K. Petersen32c58442015-12-16 17:53:51 -05004528MODULE_PARM_DESC(opt_blks, "optimal transfer length in blocks (def=1024)");
Douglas Gilbert6f3cbf52007-01-05 00:05:25 -05004529MODULE_PARM_DESC(opts, "1->noise, 2->medium_err, 4->timeout, 8->recovered_err... (def=0)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004530MODULE_PARM_DESC(physblk_exp, "physical block exponent (def=0)");
Lukas Herbolt86e68282017-01-26 10:00:37 +01004531MODULE_PARM_DESC(opt_xferlen_exp, "optimal transfer length granularity exponent (def=physblk_exp)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004532MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
Martin Pittd9867882012-09-06 12:04:33 +02004533MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004534MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=7[SPC-5])");
Martin K. Petersenea61fca2009-05-15 00:40:33 -04004535MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004536MODULE_PARM_DESC(statistics, "collect statistics on commands, queues (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004537MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
Douglas Gilbertc4837392016-05-06 00:40:26 -04004538MODULE_PARM_DESC(submit_queues, "support for block multi-queue (def=1)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004539MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
4540MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
Martin K. Petersen60147592010-08-19 11:49:00 -04004541MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
4542MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04004543MODULE_PARM_DESC(uuid_ctl,
4544 "1->use uuid for lu name, 0->don't, 2->all use same (def=0)");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05004545MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
Martin K. Petersen5b94e232011-03-08 02:08:11 -05004546MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
4547MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
Linus Torvalds1da177e2005-04-16 15:20:36 -07004548
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004549#define SDEBUG_INFO_LEN 256
4550static char sdebug_info[SDEBUG_INFO_LEN];
Linus Torvalds1da177e2005-04-16 15:20:36 -07004551
John Pittman91d4c752018-02-09 21:12:43 -05004552static const char *scsi_debug_info(struct Scsi_Host *shp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004553{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004554 int k;
4555
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004556 k = scnprintf(sdebug_info, SDEBUG_INFO_LEN, "%s: version %s [%s]\n",
4557 my_name, SDEBUG_VERSION, sdebug_version_date);
4558 if (k >= (SDEBUG_INFO_LEN - 1))
Douglas Gilbertc4837392016-05-06 00:40:26 -04004559 return sdebug_info;
Douglas Gilbert760f3b02016-05-06 00:40:27 -04004560 scnprintf(sdebug_info + k, SDEBUG_INFO_LEN - k,
4561 " dev_size_mb=%d, opts=0x%x, submit_queues=%d, %s=%d",
4562 sdebug_dev_size_mb, sdebug_opts, submit_queues,
4563 "statistics", (int)sdebug_statistics);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004564 return sdebug_info;
4565}
4566
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004567/* 'echo <val> > /proc/scsi/scsi_debug/<host_id>' writes to opts */
Douglas Gilbertfd321192016-04-25 12:16:33 -04004568static int scsi_debug_write_info(struct Scsi_Host *host, char *buffer,
4569 int length)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004570{
Al Viroc8ed5552013-03-31 01:46:06 -04004571 char arr[16];
4572 int opts;
4573 int minLen = length > 15 ? 15 : length;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004574
Al Viroc8ed5552013-03-31 01:46:06 -04004575 if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
4576 return -EACCES;
4577 memcpy(arr, buffer, minLen);
4578 arr[minLen] = '\0';
4579 if (1 != sscanf(arr, "%d", &opts))
4580 return -EINVAL;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004581 sdebug_opts = opts;
4582 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4583 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
4584 if (sdebug_every_nth != 0)
Douglas Gilbertc4837392016-05-06 00:40:26 -04004585 tweak_cmnd_count();
Al Viroc8ed5552013-03-31 01:46:06 -04004586 return length;
4587}
Linus Torvalds1da177e2005-04-16 15:20:36 -07004588
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004589/* Output seen with 'cat /proc/scsi/scsi_debug/<host_id>'. It will be the
4590 * same for each scsi_debug host (if more than one). Some of the counters
4591 * output are not atomics so might be inaccurate in a busy system. */
Al Viroc8ed5552013-03-31 01:46:06 -04004592static int scsi_debug_show_info(struct seq_file *m, struct Scsi_Host *host)
4593{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004594 int f, j, l;
4595 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004596
Douglas Gilbertc4837392016-05-06 00:40:26 -04004597 seq_printf(m, "scsi_debug adapter driver, version %s [%s]\n",
4598 SDEBUG_VERSION, sdebug_version_date);
4599 seq_printf(m, "num_tgts=%d, %ssize=%d MB, opts=0x%x, every_nth=%d\n",
4600 sdebug_num_tgts, "shared (ram) ", sdebug_dev_size_mb,
4601 sdebug_opts, sdebug_every_nth);
4602 seq_printf(m, "delay=%d, ndelay=%d, max_luns=%d, sector_size=%d %s\n",
4603 sdebug_jdelay, sdebug_ndelay, sdebug_max_luns,
4604 sdebug_sector_size, "bytes");
4605 seq_printf(m, "cylinders=%d, heads=%d, sectors=%d, command aborts=%d\n",
4606 sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
4607 num_aborts);
4608 seq_printf(m, "RESETs: device=%d, target=%d, bus=%d, host=%d\n",
4609 num_dev_resets, num_target_resets, num_bus_resets,
4610 num_host_resets);
4611 seq_printf(m, "dix_reads=%d, dix_writes=%d, dif_errors=%d\n",
4612 dix_reads, dix_writes, dif_errors);
Bart Van Assche458df782018-01-26 08:52:19 -08004613 seq_printf(m, "usec_in_jiffy=%lu, statistics=%d\n", TICK_NSEC / 1000,
4614 sdebug_statistics);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004615 seq_printf(m, "cmnd_count=%d, completions=%d, %s=%d, a_tsf=%d\n",
4616 atomic_read(&sdebug_cmnd_count),
4617 atomic_read(&sdebug_completions),
4618 "miss_cpus", atomic_read(&sdebug_miss_cpus),
4619 atomic_read(&sdebug_a_tsf));
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004620
Douglas Gilbertc4837392016-05-06 00:40:26 -04004621 seq_printf(m, "submit_queues=%d\n", submit_queues);
4622 for (j = 0, sqp = sdebug_q_arr; j < submit_queues; ++j, ++sqp) {
4623 seq_printf(m, " queue %d:\n", j);
4624 f = find_first_bit(sqp->in_use_bm, sdebug_max_queue);
4625 if (f != sdebug_max_queue) {
4626 l = find_last_bit(sqp->in_use_bm, sdebug_max_queue);
4627 seq_printf(m, " in_use_bm BUSY: %s: %d,%d\n",
4628 "first,last bits", f, l);
4629 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004630 }
Al Viroc8ed5552013-03-31 01:46:06 -04004631 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004632}
4633
Akinobu Mita82069372013-10-14 22:48:04 +09004634static ssize_t delay_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004635{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004636 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_jdelay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004637}
Douglas Gilbertc4837392016-05-06 00:40:26 -04004638/* Returns -EBUSY if jdelay is being changed and commands are queued. The unit
4639 * of delay is jiffies.
4640 */
Akinobu Mita82069372013-10-14 22:48:04 +09004641static ssize_t delay_store(struct device_driver *ddp, const char *buf,
4642 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004643{
Douglas Gilbertc2206092016-04-25 12:16:31 -04004644 int jdelay, res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004645
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04004646 if (count > 0 && sscanf(buf, "%d", &jdelay) == 1) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004647 res = count;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004648 if (sdebug_jdelay != jdelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004649 int j, k;
4650 struct sdebug_queue *sqp;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004651
Douglas Gilbertc4837392016-05-06 00:40:26 -04004652 block_unblock_all_queues(true);
4653 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4654 ++j, ++sqp) {
4655 k = find_first_bit(sqp->in_use_bm,
4656 sdebug_max_queue);
4657 if (k != sdebug_max_queue) {
4658 res = -EBUSY; /* queued commands */
4659 break;
4660 }
4661 }
4662 if (res > 0) {
Douglas Gilbertc2206092016-04-25 12:16:31 -04004663 sdebug_jdelay = jdelay;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004664 sdebug_ndelay = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004665 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004666 block_unblock_all_queues(false);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004667 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004668 return res;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004669 }
4670 return -EINVAL;
4671}
Akinobu Mita82069372013-10-14 22:48:04 +09004672static DRIVER_ATTR_RW(delay);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004673
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004674static ssize_t ndelay_show(struct device_driver *ddp, char *buf)
4675{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004676 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ndelay);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004677}
4678/* Returns -EBUSY if ndelay is being changed and commands are queued */
Douglas Gilbertc2206092016-04-25 12:16:31 -04004679/* If > 0 and accepted then sdebug_jdelay is set to JDELAY_OVERRIDDEN */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004680static ssize_t ndelay_store(struct device_driver *ddp, const char *buf,
Douglas Gilbertfd321192016-04-25 12:16:33 -04004681 size_t count)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004682{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004683 int ndelay, res;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004684
4685 if ((count > 0) && (1 == sscanf(buf, "%d", &ndelay)) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004686 (ndelay >= 0) && (ndelay < (1000 * 1000 * 1000))) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004687 res = count;
Douglas Gilbert773642d2016-04-25 12:16:28 -04004688 if (sdebug_ndelay != ndelay) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04004689 int j, k;
4690 struct sdebug_queue *sqp;
4691
4692 block_unblock_all_queues(true);
4693 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4694 ++j, ++sqp) {
4695 k = find_first_bit(sqp->in_use_bm,
4696 sdebug_max_queue);
4697 if (k != sdebug_max_queue) {
4698 res = -EBUSY; /* queued commands */
4699 break;
4700 }
4701 }
4702 if (res > 0) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004703 sdebug_ndelay = ndelay;
Douglas Gilbertc2206092016-04-25 12:16:31 -04004704 sdebug_jdelay = ndelay ? JDELAY_OVERRIDDEN
4705 : DEF_JDELAY;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004706 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04004707 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004708 }
4709 return res;
4710 }
4711 return -EINVAL;
4712}
4713static DRIVER_ATTR_RW(ndelay);
4714
Akinobu Mita82069372013-10-14 22:48:04 +09004715static ssize_t opts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004716{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004717 return scnprintf(buf, PAGE_SIZE, "0x%x\n", sdebug_opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004718}
4719
Akinobu Mita82069372013-10-14 22:48:04 +09004720static ssize_t opts_store(struct device_driver *ddp, const char *buf,
4721 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004722{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004723 int opts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004724 char work[20];
4725
Douglas Gilbert9a051012017-12-23 12:48:10 -05004726 if (sscanf(buf, "%10s", work) == 1) {
4727 if (strncasecmp(work, "0x", 2) == 0) {
4728 if (kstrtoint(work + 2, 16, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004729 goto opts_done;
4730 } else {
Douglas Gilbert9a051012017-12-23 12:48:10 -05004731 if (kstrtoint(work, 10, &opts) == 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004732 goto opts_done;
4733 }
4734 }
4735 return -EINVAL;
4736opts_done:
Douglas Gilbert773642d2016-04-25 12:16:28 -04004737 sdebug_opts = opts;
4738 sdebug_verbose = !!(SDEBUG_OPT_NOISE & opts);
4739 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004740 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004741 return count;
4742}
Akinobu Mita82069372013-10-14 22:48:04 +09004743static DRIVER_ATTR_RW(opts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004744
Akinobu Mita82069372013-10-14 22:48:04 +09004745static ssize_t ptype_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004746{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004747 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004748}
Akinobu Mita82069372013-10-14 22:48:04 +09004749static ssize_t ptype_store(struct device_driver *ddp, const char *buf,
4750 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004751{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004752 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004753
4754 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004755 sdebug_ptype = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004756 return count;
4757 }
4758 return -EINVAL;
4759}
Akinobu Mita82069372013-10-14 22:48:04 +09004760static DRIVER_ATTR_RW(ptype);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004761
Akinobu Mita82069372013-10-14 22:48:04 +09004762static ssize_t dsense_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004763{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004764 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004765}
Akinobu Mita82069372013-10-14 22:48:04 +09004766static ssize_t dsense_store(struct device_driver *ddp, const char *buf,
4767 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004768{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004769 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004770
4771 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004772 sdebug_dsense = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004773 return count;
4774 }
4775 return -EINVAL;
4776}
Akinobu Mita82069372013-10-14 22:48:04 +09004777static DRIVER_ATTR_RW(dsense);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004778
Akinobu Mita82069372013-10-14 22:48:04 +09004779static ssize_t fake_rw_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04004780{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004781 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004782}
Akinobu Mita82069372013-10-14 22:48:04 +09004783static ssize_t fake_rw_store(struct device_driver *ddp, const char *buf,
4784 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04004785{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004786 int n;
Douglas Gilbert23183912006-09-16 20:30:47 -04004787
4788 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004789 n = (n > 0);
Douglas Gilbert773642d2016-04-25 12:16:28 -04004790 sdebug_fake_rw = (sdebug_fake_rw > 0);
4791 if (sdebug_fake_rw != n) {
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004792 if ((0 == n) && (NULL == fake_storep)) {
4793 unsigned long sz =
Douglas Gilbert773642d2016-04-25 12:16:28 -04004794 (unsigned long)sdebug_dev_size_mb *
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004795 1048576;
4796
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04004797 fake_storep = vzalloc(sz);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004798 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03004799 pr_err("out of memory, 9\n");
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004800 return -ENOMEM;
4801 }
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004802 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004803 sdebug_fake_rw = n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004804 }
Douglas Gilbert23183912006-09-16 20:30:47 -04004805 return count;
4806 }
4807 return -EINVAL;
4808}
Akinobu Mita82069372013-10-14 22:48:04 +09004809static DRIVER_ATTR_RW(fake_rw);
Douglas Gilbert23183912006-09-16 20:30:47 -04004810
Akinobu Mita82069372013-10-14 22:48:04 +09004811static ssize_t no_lun_0_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004812{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004813 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004814}
Akinobu Mita82069372013-10-14 22:48:04 +09004815static ssize_t no_lun_0_store(struct device_driver *ddp, const char *buf,
4816 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004817{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004818 int n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004819
4820 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004821 sdebug_no_lun_0 = n;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004822 return count;
4823 }
4824 return -EINVAL;
4825}
Akinobu Mita82069372013-10-14 22:48:04 +09004826static DRIVER_ATTR_RW(no_lun_0);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004827
Akinobu Mita82069372013-10-14 22:48:04 +09004828static ssize_t num_tgts_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_num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004831}
Akinobu Mita82069372013-10-14 22:48:04 +09004832static ssize_t num_tgts_store(struct device_driver *ddp, const char *buf,
4833 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004834{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004835 int n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004836
4837 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004838 sdebug_num_tgts = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004839 sdebug_max_tgts_luns();
4840 return count;
4841 }
4842 return -EINVAL;
4843}
Akinobu Mita82069372013-10-14 22:48:04 +09004844static DRIVER_ATTR_RW(num_tgts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004845
Akinobu Mita82069372013-10-14 22:48:04 +09004846static ssize_t dev_size_mb_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004847{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004848 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004849}
Akinobu Mita82069372013-10-14 22:48:04 +09004850static DRIVER_ATTR_RO(dev_size_mb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004851
Akinobu Mita82069372013-10-14 22:48:04 +09004852static ssize_t num_parts_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004853{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004854 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004855}
Akinobu Mita82069372013-10-14 22:48:04 +09004856static DRIVER_ATTR_RO(num_parts);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004857
Akinobu Mita82069372013-10-14 22:48:04 +09004858static ssize_t every_nth_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004859{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004860 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004861}
Akinobu Mita82069372013-10-14 22:48:04 +09004862static ssize_t every_nth_store(struct device_driver *ddp, const char *buf,
4863 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004864{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004865 int nth;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004866
4867 if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004868 sdebug_every_nth = nth;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004869 if (nth && !sdebug_statistics) {
4870 pr_info("every_nth needs statistics=1, set it\n");
4871 sdebug_statistics = true;
4872 }
4873 tweak_cmnd_count();
Linus Torvalds1da177e2005-04-16 15:20:36 -07004874 return count;
4875 }
4876 return -EINVAL;
4877}
Akinobu Mita82069372013-10-14 22:48:04 +09004878static DRIVER_ATTR_RW(every_nth);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004879
Akinobu Mita82069372013-10-14 22:48:04 +09004880static ssize_t max_luns_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004881{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004882 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004883}
Akinobu Mita82069372013-10-14 22:48:04 +09004884static ssize_t max_luns_store(struct device_driver *ddp, const char *buf,
4885 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004886{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004887 int n;
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004888 bool changed;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004889
4890 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert8d039e22016-04-30 22:44:43 -04004891 if (n > 256) {
4892 pr_warn("max_luns can be no more than 256\n");
4893 return -EINVAL;
4894 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004895 changed = (sdebug_max_luns != n);
4896 sdebug_max_luns = n;
Linus Torvalds1da177e2005-04-16 15:20:36 -07004897 sdebug_max_tgts_luns();
Douglas Gilbert773642d2016-04-25 12:16:28 -04004898 if (changed && (sdebug_scsi_level >= 5)) { /* >= SPC-3 */
Ewan D. Milne19c8ead2014-12-04 11:49:27 -05004899 struct sdebug_host_info *sdhp;
4900 struct sdebug_dev_info *dp;
4901
4902 spin_lock(&sdebug_host_list_lock);
4903 list_for_each_entry(sdhp, &sdebug_host_list,
4904 host_list) {
4905 list_for_each_entry(dp, &sdhp->dev_info_list,
4906 dev_list) {
4907 set_bit(SDEBUG_UA_LUNS_CHANGED,
4908 dp->uas_bm);
4909 }
4910 }
4911 spin_unlock(&sdebug_host_list_lock);
4912 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07004913 return count;
4914 }
4915 return -EINVAL;
4916}
Akinobu Mita82069372013-10-14 22:48:04 +09004917static DRIVER_ATTR_RW(max_luns);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004918
Akinobu Mita82069372013-10-14 22:48:04 +09004919static ssize_t max_queue_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004920{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004921 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004922}
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004923/* N.B. max_queue can be changed while there are queued commands. In flight
4924 * commands beyond the new max_queue will be completed. */
Akinobu Mita82069372013-10-14 22:48:04 +09004925static ssize_t max_queue_store(struct device_driver *ddp, const char *buf,
4926 size_t count)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004927{
Douglas Gilbertc4837392016-05-06 00:40:26 -04004928 int j, n, k, a;
4929 struct sdebug_queue *sqp;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004930
4931 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n > 0) &&
Douglas Gilbertc4837392016-05-06 00:40:26 -04004932 (n <= SDEBUG_CANQUEUE)) {
4933 block_unblock_all_queues(true);
4934 k = 0;
4935 for (j = 0, sqp = sdebug_q_arr; j < submit_queues;
4936 ++j, ++sqp) {
4937 a = find_last_bit(sqp->in_use_bm, SDEBUG_CANQUEUE);
4938 if (a > k)
4939 k = a;
4940 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04004941 sdebug_max_queue = n;
Douglas Gilbertc4837392016-05-06 00:40:26 -04004942 if (k == SDEBUG_CANQUEUE)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04004943 atomic_set(&retired_max_queue, 0);
4944 else if (k >= n)
4945 atomic_set(&retired_max_queue, k + 1);
4946 else
4947 atomic_set(&retired_max_queue, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04004948 block_unblock_all_queues(false);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004949 return count;
4950 }
4951 return -EINVAL;
4952}
Akinobu Mita82069372013-10-14 22:48:04 +09004953static DRIVER_ATTR_RW(max_queue);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004954
Akinobu Mita82069372013-10-14 22:48:04 +09004955static ssize_t no_uld_show(struct device_driver *ddp, char *buf)
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004956{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004957 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004958}
Akinobu Mita82069372013-10-14 22:48:04 +09004959static DRIVER_ATTR_RO(no_uld);
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04004960
Akinobu Mita82069372013-10-14 22:48:04 +09004961static ssize_t scsi_level_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07004962{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004963 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004964}
Akinobu Mita82069372013-10-14 22:48:04 +09004965static DRIVER_ATTR_RO(scsi_level);
Linus Torvalds1da177e2005-04-16 15:20:36 -07004966
Akinobu Mita82069372013-10-14 22:48:04 +09004967static ssize_t virtual_gb_show(struct device_driver *ddp, char *buf)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004968{
Douglas Gilbert773642d2016-04-25 12:16:28 -04004969 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004970}
Akinobu Mita82069372013-10-14 22:48:04 +09004971static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
4972 size_t count)
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004973{
Douglas Gilbert9a051012017-12-23 12:48:10 -05004974 int n;
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004975 bool changed;
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004976
4977 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04004978 changed = (sdebug_virtual_gb != n);
4979 sdebug_virtual_gb = n;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004980 sdebug_capacity = get_sdebug_capacity();
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004981 if (changed) {
4982 struct sdebug_host_info *sdhp;
4983 struct sdebug_dev_info *dp;
FUJITA Tomonori28898872008-03-30 00:59:55 +09004984
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004985 spin_lock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004986 list_for_each_entry(sdhp, &sdebug_host_list,
4987 host_list) {
4988 list_for_each_entry(dp, &sdhp->dev_info_list,
4989 dev_list) {
4990 set_bit(SDEBUG_UA_CAPACITY_CHANGED,
4991 dp->uas_bm);
4992 }
4993 }
Ewan D. Milne4bc6b632014-12-04 11:49:26 -05004994 spin_unlock(&sdebug_host_list_lock);
Douglas Gilbert0d01c5d2014-11-24 20:27:51 -05004995 }
Douglas Gilbertc65b1442006-06-06 00:11:24 -04004996 return count;
4997 }
4998 return -EINVAL;
4999}
Akinobu Mita82069372013-10-14 22:48:04 +09005000static DRIVER_ATTR_RW(virtual_gb);
Douglas Gilbertc65b1442006-06-06 00:11:24 -04005001
Akinobu Mita82069372013-10-14 22:48:04 +09005002static ssize_t add_host_show(struct device_driver *ddp, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005003{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005004 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005005}
5006
Douglas Gilbertfd321192016-04-25 12:16:33 -04005007static int sdebug_add_adapter(void);
5008static void sdebug_remove_adapter(void);
5009
Akinobu Mita82069372013-10-14 22:48:04 +09005010static ssize_t add_host_store(struct device_driver *ddp, const char *buf,
5011 size_t count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005012{
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005013 int delta_hosts;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005014
FUJITA Tomonorif3df41c2008-03-20 11:09:15 +09005015 if (sscanf(buf, "%d", &delta_hosts) != 1)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005016 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005017 if (delta_hosts > 0) {
5018 do {
5019 sdebug_add_adapter();
5020 } while (--delta_hosts);
5021 } else if (delta_hosts < 0) {
5022 do {
5023 sdebug_remove_adapter();
5024 } while (++delta_hosts);
5025 }
5026 return count;
5027}
Akinobu Mita82069372013-10-14 22:48:04 +09005028static DRIVER_ATTR_RW(add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005029
Akinobu Mita82069372013-10-14 22:48:04 +09005030static ssize_t vpd_use_hostno_show(struct device_driver *ddp, char *buf)
Douglas Gilbert23183912006-09-16 20:30:47 -04005031{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005032 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005033}
Akinobu Mita82069372013-10-14 22:48:04 +09005034static ssize_t vpd_use_hostno_store(struct device_driver *ddp, const char *buf,
5035 size_t count)
Douglas Gilbert23183912006-09-16 20:30:47 -04005036{
5037 int n;
5038
5039 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005040 sdebug_vpd_use_hostno = n;
Douglas Gilbert23183912006-09-16 20:30:47 -04005041 return count;
5042 }
5043 return -EINVAL;
5044}
Akinobu Mita82069372013-10-14 22:48:04 +09005045static DRIVER_ATTR_RW(vpd_use_hostno);
Douglas Gilbert23183912006-09-16 20:30:47 -04005046
Douglas Gilbertc4837392016-05-06 00:40:26 -04005047static ssize_t statistics_show(struct device_driver *ddp, char *buf)
5048{
5049 return scnprintf(buf, PAGE_SIZE, "%d\n", (int)sdebug_statistics);
5050}
5051static ssize_t statistics_store(struct device_driver *ddp, const char *buf,
5052 size_t count)
5053{
5054 int n;
5055
5056 if ((count > 0) && (sscanf(buf, "%d", &n) == 1) && (n >= 0)) {
5057 if (n > 0)
5058 sdebug_statistics = true;
5059 else {
5060 clear_queue_stats();
5061 sdebug_statistics = false;
5062 }
5063 return count;
5064 }
5065 return -EINVAL;
5066}
5067static DRIVER_ATTR_RW(statistics);
5068
Akinobu Mita82069372013-10-14 22:48:04 +09005069static ssize_t sector_size_show(struct device_driver *ddp, char *buf)
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005070{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005071 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005072}
Akinobu Mita82069372013-10-14 22:48:04 +09005073static DRIVER_ATTR_RO(sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005074
Douglas Gilbertc4837392016-05-06 00:40:26 -04005075static ssize_t submit_queues_show(struct device_driver *ddp, char *buf)
5076{
5077 return scnprintf(buf, PAGE_SIZE, "%d\n", submit_queues);
5078}
5079static DRIVER_ATTR_RO(submit_queues);
5080
Akinobu Mita82069372013-10-14 22:48:04 +09005081static ssize_t dix_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_dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005084}
Akinobu Mita82069372013-10-14 22:48:04 +09005085static DRIVER_ATTR_RO(dix);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005086
Akinobu Mita82069372013-10-14 22:48:04 +09005087static ssize_t dif_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005088{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005089 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005090}
Akinobu Mita82069372013-10-14 22:48:04 +09005091static DRIVER_ATTR_RO(dif);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005092
Akinobu Mita82069372013-10-14 22:48:04 +09005093static ssize_t guard_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005094{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005095 return scnprintf(buf, PAGE_SIZE, "%u\n", sdebug_guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005096}
Akinobu Mita82069372013-10-14 22:48:04 +09005097static DRIVER_ATTR_RO(guard);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005098
Akinobu Mita82069372013-10-14 22:48:04 +09005099static ssize_t ato_show(struct device_driver *ddp, char *buf)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005100{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005101 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005102}
Akinobu Mita82069372013-10-14 22:48:04 +09005103static DRIVER_ATTR_RO(ato);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005104
Akinobu Mita82069372013-10-14 22:48:04 +09005105static ssize_t map_show(struct device_driver *ddp, char *buf)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005106{
5107 ssize_t count;
5108
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005109 if (!scsi_debug_lbp())
Martin K. Petersen44d92692009-10-15 14:45:27 -04005110 return scnprintf(buf, PAGE_SIZE, "0-%u\n",
5111 sdebug_store_sectors);
5112
Tejun Heoc7badc92015-02-13 14:37:51 -08005113 count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
5114 (int)map_size, map_storep);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005115 buf[count++] = '\n';
Tejun Heoc7badc92015-02-13 14:37:51 -08005116 buf[count] = '\0';
Martin K. Petersen44d92692009-10-15 14:45:27 -04005117
5118 return count;
5119}
Akinobu Mita82069372013-10-14 22:48:04 +09005120static DRIVER_ATTR_RO(map);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005121
Akinobu Mita82069372013-10-14 22:48:04 +09005122static ssize_t removable_show(struct device_driver *ddp, char *buf)
Martin Pittd9867882012-09-06 12:04:33 +02005123{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005124 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_removable ? 1 : 0);
Martin Pittd9867882012-09-06 12:04:33 +02005125}
Akinobu Mita82069372013-10-14 22:48:04 +09005126static ssize_t removable_store(struct device_driver *ddp, const char *buf,
5127 size_t count)
Martin Pittd9867882012-09-06 12:04:33 +02005128{
5129 int n;
5130
5131 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005132 sdebug_removable = (n > 0);
Martin Pittd9867882012-09-06 12:04:33 +02005133 return count;
5134 }
5135 return -EINVAL;
5136}
Akinobu Mita82069372013-10-14 22:48:04 +09005137static DRIVER_ATTR_RW(removable);
Martin Pittd9867882012-09-06 12:04:33 +02005138
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005139static ssize_t host_lock_show(struct device_driver *ddp, char *buf)
5140{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005141 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_host_lock);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005142}
Douglas Gilbert185dd232016-04-25 12:16:29 -04005143/* N.B. sdebug_host_lock does nothing, kept for backward compatibility */
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005144static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
5145 size_t count)
5146{
Douglas Gilbert185dd232016-04-25 12:16:29 -04005147 int n;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005148
5149 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert185dd232016-04-25 12:16:29 -04005150 sdebug_host_lock = (n > 0);
5151 return count;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005152 }
5153 return -EINVAL;
5154}
5155static DRIVER_ATTR_RW(host_lock);
5156
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005157static ssize_t strict_show(struct device_driver *ddp, char *buf)
5158{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005159 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_strict);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005160}
5161static ssize_t strict_store(struct device_driver *ddp, const char *buf,
5162 size_t count)
5163{
5164 int n;
5165
5166 if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005167 sdebug_strict = (n > 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005168 return count;
5169 }
5170 return -EINVAL;
5171}
5172static DRIVER_ATTR_RW(strict);
5173
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005174static ssize_t uuid_ctl_show(struct device_driver *ddp, char *buf)
5175{
5176 return scnprintf(buf, PAGE_SIZE, "%d\n", !!sdebug_uuid_ctl);
5177}
5178static DRIVER_ATTR_RO(uuid_ctl);
5179
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005180static ssize_t cdb_len_show(struct device_driver *ddp, char *buf)
5181{
5182 return scnprintf(buf, PAGE_SIZE, "%d\n", sdebug_cdb_len);
5183}
5184static ssize_t cdb_len_store(struct device_driver *ddp, const char *buf,
5185 size_t count)
5186{
5187 int ret, n;
5188
5189 ret = kstrtoint(buf, 0, &n);
5190 if (ret)
5191 return ret;
5192 sdebug_cdb_len = n;
5193 all_config_cdb_len();
5194 return count;
5195}
5196static DRIVER_ATTR_RW(cdb_len);
5197
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005198
Akinobu Mita82069372013-10-14 22:48:04 +09005199/* Note: The following array creates attribute files in the
Douglas Gilbert23183912006-09-16 20:30:47 -04005200 /sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
5201 files (over those found in the /sys/module/scsi_debug/parameters
5202 directory) is that auxiliary actions can be triggered when an attribute
5203 is changed. For example see: sdebug_add_host_store() above.
5204 */
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005205
Akinobu Mita82069372013-10-14 22:48:04 +09005206static struct attribute *sdebug_drv_attrs[] = {
5207 &driver_attr_delay.attr,
5208 &driver_attr_opts.attr,
5209 &driver_attr_ptype.attr,
5210 &driver_attr_dsense.attr,
5211 &driver_attr_fake_rw.attr,
5212 &driver_attr_no_lun_0.attr,
5213 &driver_attr_num_tgts.attr,
5214 &driver_attr_dev_size_mb.attr,
5215 &driver_attr_num_parts.attr,
5216 &driver_attr_every_nth.attr,
5217 &driver_attr_max_luns.attr,
5218 &driver_attr_max_queue.attr,
5219 &driver_attr_no_uld.attr,
5220 &driver_attr_scsi_level.attr,
5221 &driver_attr_virtual_gb.attr,
5222 &driver_attr_add_host.attr,
5223 &driver_attr_vpd_use_hostno.attr,
5224 &driver_attr_sector_size.attr,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005225 &driver_attr_statistics.attr,
5226 &driver_attr_submit_queues.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005227 &driver_attr_dix.attr,
5228 &driver_attr_dif.attr,
5229 &driver_attr_guard.attr,
5230 &driver_attr_ato.attr,
5231 &driver_attr_map.attr,
5232 &driver_attr_removable.attr,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005233 &driver_attr_host_lock.attr,
5234 &driver_attr_ndelay.attr,
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005235 &driver_attr_strict.attr,
Douglas Gilbert09ba24c2016-05-06 00:40:28 -04005236 &driver_attr_uuid_ctl.attr,
Douglas Gilbert9b760fd2017-12-05 00:05:49 -05005237 &driver_attr_cdb_len.attr,
Akinobu Mita82069372013-10-14 22:48:04 +09005238 NULL,
5239};
5240ATTRIBUTE_GROUPS(sdebug_drv);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005241
Akinobu Mita11ddcec2014-02-26 22:56:59 +09005242static struct device *pseudo_primary;
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005243
Linus Torvalds1da177e2005-04-16 15:20:36 -07005244static int __init scsi_debug_init(void)
5245{
FUJITA Tomonori5f2578e2008-03-30 00:59:57 +09005246 unsigned long sz;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005247 int host_to_add;
5248 int k;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005249 int ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005250
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005251 atomic_set(&retired_max_queue, 0);
5252
Douglas Gilbert773642d2016-04-25 12:16:28 -04005253 if (sdebug_ndelay >= 1000 * 1000 * 1000) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005254 pr_warn("ndelay must be less than 1 second, ignored\n");
Douglas Gilbert773642d2016-04-25 12:16:28 -04005255 sdebug_ndelay = 0;
5256 } else if (sdebug_ndelay > 0)
Douglas Gilbertc2206092016-04-25 12:16:31 -04005257 sdebug_jdelay = JDELAY_OVERRIDDEN;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005258
Douglas Gilbert773642d2016-04-25 12:16:28 -04005259 switch (sdebug_sector_size) {
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005260 case 512:
5261 case 1024:
5262 case 2048:
5263 case 4096:
5264 break;
5265 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005266 pr_err("invalid sector_size %d\n", sdebug_sector_size);
Martin K. Petersen597136ab2008-06-05 00:12:59 -04005267 return -EINVAL;
5268 }
5269
Douglas Gilbert773642d2016-04-25 12:16:28 -04005270 switch (sdebug_dif) {
Christoph Hellwig8475c812016-09-11 19:35:41 +02005271 case T10_PI_TYPE0_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005272 break;
Christoph Hellwig8475c812016-09-11 19:35:41 +02005273 case T10_PI_TYPE1_PROTECTION:
5274 case T10_PI_TYPE2_PROTECTION:
5275 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005276 have_dif_prot = true;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005277 break;
5278
5279 default:
Tomas Winklerc12879702015-07-28 16:54:20 +03005280 pr_err("dif must be 0, 1, 2 or 3\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005281 return -EINVAL;
5282 }
5283
Douglas Gilbert773642d2016-04-25 12:16:28 -04005284 if (sdebug_guard > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005285 pr_err("guard must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005286 return -EINVAL;
5287 }
5288
Douglas Gilbert773642d2016-04-25 12:16:28 -04005289 if (sdebug_ato > 1) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005290 pr_err("ato must be 0 or 1\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005291 return -EINVAL;
5292 }
5293
Douglas Gilbert773642d2016-04-25 12:16:28 -04005294 if (sdebug_physblk_exp > 15) {
5295 pr_err("invalid physblk_exp %u\n", sdebug_physblk_exp);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005296 return -EINVAL;
5297 }
Douglas Gilbert8d039e22016-04-30 22:44:43 -04005298 if (sdebug_max_luns > 256) {
5299 pr_warn("max_luns can be no more than 256, use default\n");
5300 sdebug_max_luns = DEF_MAX_LUNS;
5301 }
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005302
Douglas Gilbert773642d2016-04-25 12:16:28 -04005303 if (sdebug_lowest_aligned > 0x3fff) {
5304 pr_err("lowest_aligned too big: %u\n", sdebug_lowest_aligned);
Martin K. Petersenea61fca2009-05-15 00:40:33 -04005305 return -EINVAL;
5306 }
5307
Douglas Gilbertc4837392016-05-06 00:40:26 -04005308 if (submit_queues < 1) {
5309 pr_err("submit_queues must be 1 or more\n");
5310 return -EINVAL;
5311 }
5312 sdebug_q_arr = kcalloc(submit_queues, sizeof(struct sdebug_queue),
5313 GFP_KERNEL);
5314 if (sdebug_q_arr == NULL)
5315 return -ENOMEM;
5316 for (k = 0; k < submit_queues; ++k)
5317 spin_lock_init(&sdebug_q_arr[k].qc_lock);
5318
Douglas Gilbert773642d2016-04-25 12:16:28 -04005319 if (sdebug_dev_size_mb < 1)
5320 sdebug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */
5321 sz = (unsigned long)sdebug_dev_size_mb * 1048576;
5322 sdebug_store_sectors = sz / sdebug_sector_size;
FUJITA Tomonori28898872008-03-30 00:59:55 +09005323 sdebug_capacity = get_sdebug_capacity();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005324
5325 /* play around with geometry, don't waste too much on track 0 */
5326 sdebug_heads = 8;
5327 sdebug_sectors_per = 32;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005328 if (sdebug_dev_size_mb >= 256)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005329 sdebug_heads = 64;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005330 else if (sdebug_dev_size_mb >= 16)
Andy Shevchenkofa785f02015-11-26 20:22:50 +02005331 sdebug_heads = 32;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005332 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5333 (sdebug_sectors_per * sdebug_heads);
5334 if (sdebug_cylinders_per >= 1024) {
5335 /* other LLDs do this; implies >= 1GB ram disk ... */
5336 sdebug_heads = 255;
5337 sdebug_sectors_per = 63;
5338 sdebug_cylinders_per = (unsigned long)sdebug_capacity /
5339 (sdebug_sectors_per * sdebug_heads);
5340 }
5341
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005342 if (sdebug_fake_rw == 0) {
Douglas Gilbert7382f9d2018-07-21 01:10:04 -04005343 fake_storep = vzalloc(sz);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005344 if (NULL == fake_storep) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005345 pr_err("out of memory, 1\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005346 ret = -ENOMEM;
5347 goto free_q_arr;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005348 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005349 if (sdebug_num_parts > 0)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005350 sdebug_build_parts(fake_storep, sz);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005351 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005352
Douglas Gilbert773642d2016-04-25 12:16:28 -04005353 if (sdebug_dix) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005354 int dif_size;
5355
Christoph Hellwig6ebf1052016-09-11 19:35:39 +02005356 dif_size = sdebug_store_sectors * sizeof(struct t10_pi_tuple);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005357 dif_storep = vmalloc(dif_size);
5358
Tomas Winklerc12879702015-07-28 16:54:20 +03005359 pr_err("dif_storep %u bytes @ %p\n", dif_size, dif_storep);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005360
5361 if (dif_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005362 pr_err("out of mem. (DIX)\n");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005363 ret = -ENOMEM;
5364 goto free_vm;
5365 }
5366
5367 memset(dif_storep, 0xff, dif_size);
5368 }
5369
Martin K. Petersen5b94e232011-03-08 02:08:11 -05005370 /* Logical Block Provisioning */
5371 if (scsi_debug_lbp()) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005372 sdebug_unmap_max_blocks =
5373 clamp(sdebug_unmap_max_blocks, 0U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005374
Douglas Gilbert773642d2016-04-25 12:16:28 -04005375 sdebug_unmap_max_desc =
5376 clamp(sdebug_unmap_max_desc, 0U, 256U);
Martin K. Petersen60147592010-08-19 11:49:00 -04005377
Douglas Gilbert773642d2016-04-25 12:16:28 -04005378 sdebug_unmap_granularity =
5379 clamp(sdebug_unmap_granularity, 1U, 0xffffffffU);
Martin K. Petersen60147592010-08-19 11:49:00 -04005380
Douglas Gilbert773642d2016-04-25 12:16:28 -04005381 if (sdebug_unmap_alignment &&
5382 sdebug_unmap_granularity <=
5383 sdebug_unmap_alignment) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005384 pr_err("ERR: unmap_granularity <= unmap_alignment\n");
Douglas Gilbertc4837392016-05-06 00:40:26 -04005385 ret = -EINVAL;
5386 goto free_vm;
Martin K. Petersen44d92692009-10-15 14:45:27 -04005387 }
5388
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005389 map_size = lba_to_map_index(sdebug_store_sectors - 1) + 1;
Kees Cook42bc47b2018-06-12 14:27:11 -07005390 map_storep = vmalloc(array_size(sizeof(long),
5391 BITS_TO_LONGS(map_size)));
Martin K. Petersen44d92692009-10-15 14:45:27 -04005392
Tomas Winklerc12879702015-07-28 16:54:20 +03005393 pr_info("%lu provisioning blocks\n", map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005394
5395 if (map_storep == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005396 pr_err("out of mem. (MAP)\n");
Martin K. Petersen44d92692009-10-15 14:45:27 -04005397 ret = -ENOMEM;
5398 goto free_vm;
5399 }
5400
Akinobu Mitab90ebc32013-04-16 22:11:58 +09005401 bitmap_zero(map_storep, map_size);
Martin K. Petersen44d92692009-10-15 14:45:27 -04005402
5403 /* Map first 1KB for partition table */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005404 if (sdebug_num_parts)
Martin K. Petersen44d92692009-10-15 14:45:27 -04005405 map_region(0, 2);
5406 }
5407
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005408 pseudo_primary = root_device_register("pseudo_0");
5409 if (IS_ERR(pseudo_primary)) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005410 pr_warn("root_device_register() error\n");
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005411 ret = PTR_ERR(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005412 goto free_vm;
5413 }
5414 ret = bus_register(&pseudo_lld_bus);
5415 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005416 pr_warn("bus_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005417 goto dev_unreg;
5418 }
5419 ret = driver_register(&sdebug_driverfs_driver);
5420 if (ret < 0) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005421 pr_warn("driver_register error: %d\n", ret);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005422 goto bus_unreg;
5423 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005424
Douglas Gilbert773642d2016-04-25 12:16:28 -04005425 host_to_add = sdebug_add_host;
5426 sdebug_add_host = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005427
Douglas Gilbert9a051012017-12-23 12:48:10 -05005428 for (k = 0; k < host_to_add; k++) {
5429 if (sdebug_add_adapter()) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005430 pr_err("sdebug_add_adapter failed k=%d\n", k);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005431 break;
5432 }
5433 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005434
Douglas Gilbert773642d2016-04-25 12:16:28 -04005435 if (sdebug_verbose)
5436 pr_info("built %d host(s)\n", sdebug_add_host);
Tomas Winklerc12879702015-07-28 16:54:20 +03005437
Linus Torvalds1da177e2005-04-16 15:20:36 -07005438 return 0;
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005439
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005440bus_unreg:
5441 bus_unregister(&pseudo_lld_bus);
5442dev_unreg:
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005443 root_device_unregister(pseudo_primary);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005444free_vm:
Tomas Winklerde232af2015-07-28 16:54:22 +03005445 vfree(map_storep);
5446 vfree(dif_storep);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005447 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005448free_q_arr:
5449 kfree(sdebug_q_arr);
Randy Dunlap6ecaff72006-07-11 20:53:22 -07005450 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005451}
5452
5453static void __exit scsi_debug_exit(void)
5454{
Douglas Gilbert773642d2016-04-25 12:16:28 -04005455 int k = sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005456
5457 stop_all_queued();
5458 for (; k; k--)
5459 sdebug_remove_adapter();
Luis Henriques52ab9762018-06-18 17:08:03 +01005460 free_all_queued();
Linus Torvalds1da177e2005-04-16 15:20:36 -07005461 driver_unregister(&sdebug_driverfs_driver);
5462 bus_unregister(&pseudo_lld_bus);
Nicholas Bellinger9b906772010-09-06 17:24:28 -07005463 root_device_unregister(pseudo_primary);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005464
Ewan D. Milne4d2b4962016-10-26 11:22:53 -04005465 vfree(map_storep);
Tomas Winklerde232af2015-07-28 16:54:22 +03005466 vfree(dif_storep);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005467 vfree(fake_storep);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005468 kfree(sdebug_q_arr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005469}
5470
5471device_initcall(scsi_debug_init);
5472module_exit(scsi_debug_exit);
5473
John Pittman91d4c752018-02-09 21:12:43 -05005474static void sdebug_release_adapter(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005475{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005476 struct sdebug_host_info *sdbg_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005477
5478 sdbg_host = to_sdebug_host(dev);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005479 kfree(sdbg_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005480}
5481
5482static int sdebug_add_adapter(void)
5483{
5484 int k, devs_per_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005485 int error = 0;
5486 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005487 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005488
Douglas Gilbert9a051012017-12-23 12:48:10 -05005489 sdbg_host = kzalloc(sizeof(*sdbg_host), GFP_KERNEL);
5490 if (sdbg_host == NULL) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005491 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005492 return -ENOMEM;
5493 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005494
Douglas Gilbert9a051012017-12-23 12:48:10 -05005495 INIT_LIST_HEAD(&sdbg_host->dev_info_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005496
Douglas Gilbert773642d2016-04-25 12:16:28 -04005497 devs_per_host = sdebug_num_tgts * sdebug_max_luns;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005498 for (k = 0; k < devs_per_host; k++) {
FUJITA Tomonori5cb2fc02008-03-20 11:09:16 +09005499 sdbg_devinfo = sdebug_device_create(sdbg_host, GFP_KERNEL);
5500 if (!sdbg_devinfo) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005501 pr_err("out of memory at line %d\n", __LINE__);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005502 error = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005503 goto clean;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005504 }
5505 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005506
Douglas Gilbert9a051012017-12-23 12:48:10 -05005507 spin_lock(&sdebug_host_list_lock);
5508 list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
5509 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005510
Douglas Gilbert9a051012017-12-23 12:48:10 -05005511 sdbg_host->dev.bus = &pseudo_lld_bus;
5512 sdbg_host->dev.parent = pseudo_primary;
5513 sdbg_host->dev.release = &sdebug_release_adapter;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005514 dev_set_name(&sdbg_host->dev, "adapter%d", sdebug_add_host);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005515
Douglas Gilbert9a051012017-12-23 12:48:10 -05005516 error = device_register(&sdbg_host->dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005517
Douglas Gilbert9a051012017-12-23 12:48:10 -05005518 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005519 goto clean;
5520
Douglas Gilbert773642d2016-04-25 12:16:28 -04005521 ++sdebug_add_host;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005522 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005523
5524clean:
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005525 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5526 dev_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07005527 list_del(&sdbg_devinfo->dev_list);
5528 kfree(sdbg_devinfo);
5529 }
5530
5531 kfree(sdbg_host);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005532 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005533}
5534
5535static void sdebug_remove_adapter(void)
5536{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005537 struct sdebug_host_info *sdbg_host = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005538
Douglas Gilbert9a051012017-12-23 12:48:10 -05005539 spin_lock(&sdebug_host_list_lock);
5540 if (!list_empty(&sdebug_host_list)) {
5541 sdbg_host = list_entry(sdebug_host_list.prev,
5542 struct sdebug_host_info, host_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005543 list_del(&sdbg_host->host_list);
5544 }
Douglas Gilbert9a051012017-12-23 12:48:10 -05005545 spin_unlock(&sdebug_host_list_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005546
5547 if (!sdbg_host)
5548 return;
5549
Douglas Gilbert773642d2016-04-25 12:16:28 -04005550 device_unregister(&sdbg_host->dev);
5551 --sdebug_add_host;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005552}
5553
Douglas Gilbertfd321192016-04-25 12:16:33 -04005554static int sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005555{
5556 int num_in_q = 0;
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005557 struct sdebug_dev_info *devip;
5558
Douglas Gilbertc4837392016-05-06 00:40:26 -04005559 block_unblock_all_queues(true);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005560 devip = (struct sdebug_dev_info *)sdev->hostdata;
5561 if (NULL == devip) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005562 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005563 return -ENODEV;
5564 }
5565 num_in_q = atomic_read(&devip->num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005566
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005567 if (qdepth < 1)
5568 qdepth = 1;
Douglas Gilbertc4837392016-05-06 00:40:26 -04005569 /* allow to exceed max host qc_arr elements for testing */
5570 if (qdepth > SDEBUG_CANQUEUE + 10)
5571 qdepth = SDEBUG_CANQUEUE + 10;
Christoph Hellwigdb5ed4d2014-11-13 15:08:42 +01005572 scsi_change_queue_depth(sdev, qdepth);
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005573
Douglas Gilbert773642d2016-04-25 12:16:28 -04005574 if (SDEBUG_OPT_Q_NOISE & sdebug_opts) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005575 sdev_printk(KERN_INFO, sdev, "%s: qdepth=%d, num_in_q=%d\n",
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005576 __func__, qdepth, num_in_q);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005577 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005578 block_unblock_all_queues(false);
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005579 return sdev->queue_depth;
5580}
5581
Douglas Gilbertc4837392016-05-06 00:40:26 -04005582static bool fake_timeout(struct scsi_cmnd *scp)
Douglas Gilbert817fd662014-11-24 20:18:02 -05005583{
Douglas Gilbertc4837392016-05-06 00:40:26 -04005584 if (0 == (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005585 if (sdebug_every_nth < -1)
5586 sdebug_every_nth = -1;
5587 if (SDEBUG_OPT_TIMEOUT & sdebug_opts)
Douglas Gilbertc4837392016-05-06 00:40:26 -04005588 return true; /* ignore command causing timeout */
Douglas Gilbert773642d2016-04-25 12:16:28 -04005589 else if (SDEBUG_OPT_MAC_TIMEOUT & sdebug_opts &&
Douglas Gilbert817fd662014-11-24 20:18:02 -05005590 scsi_medium_access_command(scp))
Douglas Gilbertc4837392016-05-06 00:40:26 -04005591 return true; /* time out reads and writes */
Douglas Gilbert817fd662014-11-24 20:18:02 -05005592 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005593 return false;
Douglas Gilbert817fd662014-11-24 20:18:02 -05005594}
5595
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005596static bool fake_host_busy(struct scsi_cmnd *scp)
5597{
5598 return (sdebug_opts & SDEBUG_OPT_HOST_BUSY) &&
5599 (atomic_read(&sdebug_cmnd_count) % abs(sdebug_every_nth)) == 0;
5600}
5601
Douglas Gilbertfd321192016-04-25 12:16:33 -04005602static int scsi_debug_queuecommand(struct Scsi_Host *shost,
5603 struct scsi_cmnd *scp)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005604{
5605 u8 sdeb_i;
5606 struct scsi_device *sdp = scp->device;
5607 const struct opcode_info_t *oip;
5608 const struct opcode_info_t *r_oip;
5609 struct sdebug_dev_info *devip;
5610 u8 *cmd = scp->cmnd;
5611 int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
Martin Wilckf66b8512018-02-14 11:05:57 +01005612 int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *) = NULL;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005613 int k, na;
5614 int errsts = 0;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005615 u32 flags;
5616 u16 sa;
5617 u8 opcode = cmd[0];
5618 bool has_wlun_rl;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005619
5620 scsi_set_resid(scp, 0);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005621 if (sdebug_statistics)
5622 atomic_inc(&sdebug_cmnd_count);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005623 if (unlikely(sdebug_verbose &&
5624 !(SDEBUG_OPT_NO_CDB_NOISE & sdebug_opts))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005625 char b[120];
5626 int n, len, sb;
5627
5628 len = scp->cmd_len;
5629 sb = (int)sizeof(b);
5630 if (len > 32)
5631 strcpy(b, "too long, over 32 bytes");
5632 else {
5633 for (k = 0, n = 0; k < len && n < sb; ++k)
5634 n += scnprintf(b + n, sb - n, "%02x ",
5635 (u32)cmd[k]);
5636 }
Bart Van Assche458df782018-01-26 08:52:19 -08005637 sdev_printk(KERN_INFO, sdp, "%s: tag=%#x, cmd %s\n", my_name,
5638 blk_mq_unique_tag(scp->request), b);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005639 }
Bart Van Assche7ee6d1b2017-12-07 14:56:18 -08005640 if (fake_host_busy(scp))
5641 return SCSI_MLQUEUE_HOST_BUSY;
Tomas Winkler34d55432015-07-28 16:54:21 +03005642 has_wlun_rl = (sdp->lun == SCSI_W_LUN_REPORT_LUNS);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005643 if (unlikely((sdp->lun >= sdebug_max_luns) && !has_wlun_rl))
5644 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005645
5646 sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
5647 oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
5648 devip = (struct sdebug_dev_info *)sdp->hostdata;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005649 if (unlikely(!devip)) {
5650 devip = find_build_dev_info(sdp);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005651 if (NULL == devip)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005652 goto err_out;
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005653 }
5654 na = oip->num_attached;
5655 r_pfp = oip->pfp;
5656 if (na) { /* multiple commands with this opcode */
5657 r_oip = oip;
5658 if (FF_SA & r_oip->flags) {
5659 if (F_SA_LOW & oip->flags)
5660 sa = 0x1f & cmd[1];
5661 else
5662 sa = get_unaligned_be16(cmd + 8);
5663 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5664 if (opcode == oip->opcode && sa == oip->sa)
5665 break;
5666 }
5667 } else { /* since no service action only check opcode */
5668 for (k = 0; k <= na; oip = r_oip->arrp + k++) {
5669 if (opcode == oip->opcode)
5670 break;
5671 }
5672 }
5673 if (k > na) {
5674 if (F_SA_LOW & r_oip->flags)
5675 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
5676 else if (F_SA_HIGH & r_oip->flags)
5677 mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
5678 else
5679 mk_sense_invalid_opcode(scp);
5680 goto check_cond;
5681 }
5682 } /* else (when na==0) we assume the oip is a match */
5683 flags = oip->flags;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005684 if (unlikely(F_INV_OP & flags)) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005685 mk_sense_invalid_opcode(scp);
5686 goto check_cond;
5687 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005688 if (unlikely(has_wlun_rl && !(F_RL_WLUN_OK & flags))) {
Douglas Gilbert773642d2016-04-25 12:16:28 -04005689 if (sdebug_verbose)
5690 sdev_printk(KERN_INFO, sdp, "%s: Opcode 0x%x not%s\n",
5691 my_name, opcode, " supported for wlun");
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005692 mk_sense_invalid_opcode(scp);
5693 goto check_cond;
5694 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005695 if (unlikely(sdebug_strict)) { /* check cdb against mask */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005696 u8 rem;
5697 int j;
5698
5699 for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
5700 rem = ~oip->len_mask[k] & cmd[k];
5701 if (rem) {
5702 for (j = 7; j >= 0; --j, rem <<= 1) {
5703 if (0x80 & rem)
5704 break;
5705 }
5706 mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
5707 goto check_cond;
5708 }
5709 }
5710 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005711 if (unlikely(!(F_SKIP_UA & flags) &&
Douglas Gilbertb01f6f82016-04-30 22:44:42 -04005712 find_first_bit(devip->uas_bm,
5713 SDEBUG_NUM_UAS) != SDEBUG_NUM_UAS)) {
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005714 errsts = make_ua(scp, devip);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005715 if (errsts)
5716 goto check_cond;
5717 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005718 if (unlikely((F_M_ACCESS & flags) && atomic_read(&devip->stopped))) {
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005719 mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
Douglas Gilbert773642d2016-04-25 12:16:28 -04005720 if (sdebug_verbose)
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005721 sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
5722 "%s\n", my_name, "initializing command "
5723 "required");
5724 errsts = check_condition_result;
5725 goto fini;
5726 }
Douglas Gilbert773642d2016-04-25 12:16:28 -04005727 if (sdebug_fake_rw && (F_FAKE_RW & flags))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005728 goto fini;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005729 if (unlikely(sdebug_every_nth)) {
Douglas Gilbertc4837392016-05-06 00:40:26 -04005730 if (fake_timeout(scp))
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005731 return 0; /* ignore command: make trouble */
5732 }
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005733 if (likely(oip->pfp))
Martin Wilckf66b8512018-02-14 11:05:57 +01005734 pfp = oip->pfp; /* calls a resp_* function */
5735 else
5736 pfp = r_pfp; /* if leaf function ptr NULL, try the root's */
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005737
5738fini:
Douglas Gilbert10bde982018-01-10 16:57:31 -05005739 if (F_DELAY_OVERR & flags)
Martin Wilckf66b8512018-02-14 11:05:57 +01005740 return schedule_resp(scp, devip, errsts, pfp, 0, 0);
Douglas Gilbert75aa3202018-07-12 13:35:42 -04005741 else if ((flags & F_LONG_DELAY) && (sdebug_jdelay > 0 ||
5742 sdebug_ndelay > 10000)) {
Douglas Gilbert80c49562018-02-09 21:36:39 -05005743 /*
Douglas Gilbert75aa3202018-07-12 13:35:42 -04005744 * Skip long delays if ndelay <= 10 microseconds. Otherwise
5745 * for Start Stop Unit (SSU) want at least 1 second delay and
5746 * if sdebug_jdelay>1 want a long delay of that many seconds.
5747 * For Synchronize Cache want 1/20 of SSU's delay.
Douglas Gilbert80c49562018-02-09 21:36:39 -05005748 */
5749 int jdelay = (sdebug_jdelay < 2) ? 1 : sdebug_jdelay;
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005750 int denom = (flags & F_SYNC_DELAY) ? 20 : 1;
Douglas Gilbert80c49562018-02-09 21:36:39 -05005751
Douglas Gilbert4f2c8bf2018-04-10 13:00:36 -04005752 jdelay = mult_frac(USER_HZ * jdelay, HZ, denom * USER_HZ);
Martin Wilckf66b8512018-02-14 11:05:57 +01005753 return schedule_resp(scp, devip, errsts, pfp, jdelay, 0);
Douglas Gilbert80c49562018-02-09 21:36:39 -05005754 } else
Martin Wilckf66b8512018-02-14 11:05:57 +01005755 return schedule_resp(scp, devip, errsts, pfp, sdebug_jdelay,
Douglas Gilbert10bde982018-01-10 16:57:31 -05005756 sdebug_ndelay);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005757check_cond:
Martin Wilckf66b8512018-02-14 11:05:57 +01005758 return schedule_resp(scp, devip, check_condition_result, NULL, 0, 0);
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005759err_out:
Martin Wilckf66b8512018-02-14 11:05:57 +01005760 return schedule_resp(scp, NULL, DID_NO_CONNECT << 16, NULL, 0, 0);
Douglas Gilbertc2248fc2014-11-24 20:46:29 -05005761}
5762
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005763static struct scsi_host_template sdebug_driver_template = {
Al Viroc8ed5552013-03-31 01:46:06 -04005764 .show_info = scsi_debug_show_info,
5765 .write_info = scsi_debug_write_info,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005766 .proc_name = sdebug_proc_name,
5767 .name = "SCSI DEBUG",
5768 .info = scsi_debug_info,
5769 .slave_alloc = scsi_debug_slave_alloc,
5770 .slave_configure = scsi_debug_slave_configure,
5771 .slave_destroy = scsi_debug_slave_destroy,
5772 .ioctl = scsi_debug_ioctl,
Douglas Gilbert185dd232016-04-25 12:16:29 -04005773 .queuecommand = scsi_debug_queuecommand,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005774 .change_queue_depth = sdebug_change_qdepth,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005775 .eh_abort_handler = scsi_debug_abort,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005776 .eh_device_reset_handler = scsi_debug_device_reset,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005777 .eh_target_reset_handler = scsi_debug_target_reset,
5778 .eh_bus_reset_handler = scsi_debug_bus_reset,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005779 .eh_host_reset_handler = scsi_debug_host_reset,
Douglas Gilbertc4837392016-05-06 00:40:26 -04005780 .can_queue = SDEBUG_CANQUEUE,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005781 .this_id = 7,
Ming Lin65e86172016-04-04 14:48:10 -07005782 .sg_tablesize = SG_MAX_SEGMENTS,
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005783 .cmd_per_lun = DEF_CMD_PER_LUN,
Akinobu Mita6bb5e6e2014-06-02 22:56:49 +09005784 .max_sectors = -1U,
Christoph Hellwig50c2e912018-12-13 16:17:03 +01005785 .max_segment_size = -1U,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005786 .module = THIS_MODULE,
Christoph Hellwigc40ecc12014-11-13 14:25:11 +01005787 .track_queue_depth = 1,
FUJITA Tomonori9e603ca2008-03-02 18:30:16 +09005788};
5789
John Pittman91d4c752018-02-09 21:12:43 -05005790static int sdebug_driver_probe(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005791{
Douglas Gilbert22017ed2014-11-24 23:04:47 -05005792 int error = 0;
5793 struct sdebug_host_info *sdbg_host;
5794 struct Scsi_Host *hpnt;
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005795 int hprot;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005796
5797 sdbg_host = to_sdebug_host(dev);
5798
Douglas Gilbert773642d2016-04-25 12:16:28 -04005799 sdebug_driver_template.can_queue = sdebug_max_queue;
Christoph Hellwig2a3d4eb2018-12-13 16:17:02 +01005800 if (!sdebug_clustering)
Christoph Hellwig4af14d12018-12-13 16:17:09 +01005801 sdebug_driver_template.dma_boundary = PAGE_SIZE - 1;
5802
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005803 hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
5804 if (NULL == hpnt) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005805 pr_err("scsi_host_alloc failed\n");
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005806 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005807 return error;
Douglas Gilbert78d4e5a2010-03-25 17:29:05 -04005808 }
Douglas Gilbertc4837392016-05-06 00:40:26 -04005809 if (submit_queues > nr_cpu_ids) {
Alexey Dobriyan9b130ad2017-09-08 16:14:18 -07005810 pr_warn("%s: trim submit_queues (was %d) to nr_cpu_ids=%u\n",
Douglas Gilbertc4837392016-05-06 00:40:26 -04005811 my_name, submit_queues, nr_cpu_ids);
5812 submit_queues = nr_cpu_ids;
5813 }
5814 /* Decide whether to tell scsi subsystem that we want mq */
5815 /* Following should give the same answer for each host */
Jens Axboef664a3c2018-11-01 16:36:27 -06005816 hpnt->nr_hw_queues = submit_queues;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005817
Douglas Gilbert9a051012017-12-23 12:48:10 -05005818 sdbg_host->shost = hpnt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005819 *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005820 if ((hpnt->this_id >= 0) && (sdebug_num_tgts > hpnt->this_id))
5821 hpnt->max_id = sdebug_num_tgts + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005822 else
Douglas Gilbert773642d2016-04-25 12:16:28 -04005823 hpnt->max_id = sdebug_num_tgts;
5824 /* = sdebug_max_luns; */
Tomas Winklerf2d3fd22015-07-28 16:54:25 +03005825 hpnt->max_lun = SCSI_W_LUN_REPORT_LUNS + 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005826
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005827 hprot = 0;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005828
Douglas Gilbert773642d2016-04-25 12:16:28 -04005829 switch (sdebug_dif) {
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005830
Christoph Hellwig8475c812016-09-11 19:35:41 +02005831 case T10_PI_TYPE1_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005832 hprot = SHOST_DIF_TYPE1_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005833 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005834 hprot |= SHOST_DIX_TYPE1_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005835 break;
5836
Christoph Hellwig8475c812016-09-11 19:35:41 +02005837 case T10_PI_TYPE2_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005838 hprot = SHOST_DIF_TYPE2_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005839 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005840 hprot |= SHOST_DIX_TYPE2_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005841 break;
5842
Christoph Hellwig8475c812016-09-11 19:35:41 +02005843 case T10_PI_TYPE3_PROTECTION:
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005844 hprot = SHOST_DIF_TYPE3_PROTECTION;
Douglas Gilbert773642d2016-04-25 12:16:28 -04005845 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005846 hprot |= SHOST_DIX_TYPE3_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005847 break;
5848
5849 default:
Douglas Gilbert773642d2016-04-25 12:16:28 -04005850 if (sdebug_dix)
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005851 hprot |= SHOST_DIX_TYPE0_PROTECTION;
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005852 break;
5853 }
5854
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005855 scsi_host_set_prot(hpnt, hprot);
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005856
Douglas Gilbertf46eb0e2016-04-25 12:16:34 -04005857 if (have_dif_prot || sdebug_dix)
5858 pr_info("host protection%s%s%s%s%s%s%s\n",
5859 (hprot & SHOST_DIF_TYPE1_PROTECTION) ? " DIF1" : "",
5860 (hprot & SHOST_DIF_TYPE2_PROTECTION) ? " DIF2" : "",
5861 (hprot & SHOST_DIF_TYPE3_PROTECTION) ? " DIF3" : "",
5862 (hprot & SHOST_DIX_TYPE0_PROTECTION) ? " DIX0" : "",
5863 (hprot & SHOST_DIX_TYPE1_PROTECTION) ? " DIX1" : "",
5864 (hprot & SHOST_DIX_TYPE2_PROTECTION) ? " DIX2" : "",
5865 (hprot & SHOST_DIX_TYPE3_PROTECTION) ? " DIX3" : "");
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005866
Douglas Gilbert773642d2016-04-25 12:16:28 -04005867 if (sdebug_guard == 1)
Martin K. Petersenc6a44282009-01-04 03:08:19 -05005868 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_IP);
5869 else
5870 scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
5871
Douglas Gilbert773642d2016-04-25 12:16:28 -04005872 sdebug_verbose = !!(SDEBUG_OPT_NOISE & sdebug_opts);
5873 sdebug_any_injecting_opt = !!(SDEBUG_OPT_ALL_INJECTING & sdebug_opts);
Douglas Gilbertc4837392016-05-06 00:40:26 -04005874 if (sdebug_every_nth) /* need stats counters for every_nth */
5875 sdebug_statistics = true;
Douglas Gilbert9a051012017-12-23 12:48:10 -05005876 error = scsi_add_host(hpnt, &sdbg_host->dev);
5877 if (error) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005878 pr_err("scsi_add_host failed\n");
Douglas Gilbert9a051012017-12-23 12:48:10 -05005879 error = -ENODEV;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005880 scsi_host_put(hpnt);
Douglas Gilbert9a051012017-12-23 12:48:10 -05005881 } else
Linus Torvalds1da177e2005-04-16 15:20:36 -07005882 scsi_scan_host(hpnt);
5883
Douglas Gilbertcbf67842014-07-26 11:55:35 -04005884 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005885}
5886
John Pittman91d4c752018-02-09 21:12:43 -05005887static int sdebug_driver_remove(struct device *dev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005888{
Douglas Gilbert9a051012017-12-23 12:48:10 -05005889 struct sdebug_host_info *sdbg_host;
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005890 struct sdebug_dev_info *sdbg_devinfo, *tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005891
5892 sdbg_host = to_sdebug_host(dev);
5893
5894 if (!sdbg_host) {
Tomas Winklerc12879702015-07-28 16:54:20 +03005895 pr_err("Unable to locate host info\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07005896 return -ENODEV;
5897 }
5898
Douglas Gilbert9a051012017-12-23 12:48:10 -05005899 scsi_remove_host(sdbg_host->shost);
Linus Torvalds1da177e2005-04-16 15:20:36 -07005900
FUJITA Tomonori8b402282008-03-20 11:09:18 +09005901 list_for_each_entry_safe(sdbg_devinfo, tmp, &sdbg_host->dev_info_list,
5902 dev_list) {
Douglas Gilbert9a051012017-12-23 12:48:10 -05005903 list_del(&sdbg_devinfo->dev_list);
5904 kfree(sdbg_devinfo);
5905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07005906
Douglas Gilbert9a051012017-12-23 12:48:10 -05005907 scsi_host_put(sdbg_host->shost);
5908 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005909}
5910
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005911static int pseudo_lld_bus_match(struct device *dev,
5912 struct device_driver *dev_driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -07005913{
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005914 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07005915}
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005916
5917static struct bus_type pseudo_lld_bus = {
5918 .name = "pseudo",
5919 .match = pseudo_lld_bus_match,
5920 .probe = sdebug_driver_probe,
5921 .remove = sdebug_driver_remove,
Akinobu Mita82069372013-10-14 22:48:04 +09005922 .drv_groups = sdebug_drv_groups,
FUJITA Tomonori8dea0d02008-03-30 00:59:58 +09005923};